summaryrefslogtreecommitdiffstats
path: root/lib/plugins/stonith/bladehpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plugins/stonith/bladehpi.c')
-rw-r--r--lib/plugins/stonith/bladehpi.c1101
1 files changed, 1101 insertions, 0 deletions
diff --git a/lib/plugins/stonith/bladehpi.c b/lib/plugins/stonith/bladehpi.c
new file mode 100644
index 0000000..ae9a4cf
--- /dev/null
+++ b/lib/plugins/stonith/bladehpi.c
@@ -0,0 +1,1101 @@
+/*
+ * Stonith module for BladeCenter via OpenHPI, an implementation of Service
+ * Availability Forum's Hardware Platfrom Interface
+ *
+ * Author: Dave Blaschke <debltc@us.ibm.com>
+ *
+ * Copyright (c) 2005 International Business Machines
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <lha_internal.h>
+
+#define DEVICE "IBM BladeCenter (OpenHPI)"
+
+#include "stonith_plugin_common.h"
+
+#define PIL_PLUGIN bladehpi
+#define PIL_PLUGIN_S "bladehpi"
+#define PIL_PLUGINLICENSE LICENSE_LGPL
+#define PIL_PLUGINLICENSEURL URL_LGPL
+#include <pils/plugin.h>
+
+#include <openhpi/SaHpi.h>
+
+/* Maximum number of seconds to wait for host to power off */
+#define MAX_POWEROFF_WAIT 60
+
+/* entity_root, the one required plugin parameter */
+#define ST_ENTITYROOT "entity_root"
+
+/* String format of entity_root */
+#define SYSTEM_CHASSIS_FMT "{SYSTEM_CHASSIS,%d}"
+
+/* soft_reset, the one optional plugin parameter */
+#define ST_SOFTRESET "soft_reset"
+
+#define OPENHPIURL "http://www.openhpi.org/"
+
+/* OpenHPI resource types of interest to this plugin */
+#define OHRES_NONE 0
+#define OHRES_BLADECENT 1
+#define OHRES_MGMTMOD 2
+#define OHRES_BLADE 3
+
+/* IBMBC_WAIT_FOR_OFF - This constant has to do with the problem that
+ saHpiResourcePowerStateSet can return before the desired state has been
+ achieved by the blade. In the SAHPI_POWER_OFF case this is not good,
+ as whoever calls this plugin assumes that the power is actually off
+ when the plugin returns with a successful return code. Define this
+ constant to build code that loops in one second intervals after calling
+ saHpiResourcePowerStateSet(SAHPI_POWER_OFF) to make sure the power is
+ really off.
+#define IBMBC_WAIT_FOR_OFF */
+
+static StonithPlugin * bladehpi_new(const char *);
+static void bladehpi_destroy(StonithPlugin *);
+static const char * bladehpi_getinfo(StonithPlugin *, int);
+static const char * const * bladehpi_get_confignames(StonithPlugin *);
+static int bladehpi_status(StonithPlugin *);
+static int bladehpi_reset_req(StonithPlugin *, int, const char *);
+static char ** bladehpi_hostlist(StonithPlugin *);
+static int bladehpi_set_config(StonithPlugin *, StonithNVpair *);
+
+static struct stonith_ops bladehpiOps = {
+ bladehpi_new, /* Create new STONITH object */
+ bladehpi_destroy, /* Destroy STONITH object */
+ bladehpi_getinfo, /* Return STONITH info string */
+ bladehpi_get_confignames, /* Return configuration parameters */
+ bladehpi_set_config, /* Set configuration */
+ bladehpi_status, /* Return STONITH device status */
+ bladehpi_reset_req, /* Request a reset */
+ bladehpi_hostlist, /* Return list of supported hosts */
+};
+
+PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
+
+static const PILPluginImports * PluginImports;
+static PILPlugin * OurPlugin;
+static PILInterface * OurInterface;
+static StonithImports * OurImports;
+static void * interfprivate;
+
+
+PIL_rc
+PIL_PLUGIN_INIT(PILPlugin *us, const PILPluginImports *imports);
+
+PIL_rc
+PIL_PLUGIN_INIT(PILPlugin *us, const PILPluginImports *imports)
+{
+ /* Force the compiler to do a little type checking */
+ (void)(PILPluginInitFun)PIL_PLUGIN_INIT;
+
+ PluginImports = imports;
+ OurPlugin = us;
+
+ /* Register ourself as a plugin */
+ imports->register_plugin(us, &OurPIExports);
+
+ /* Register our interface implementation */
+ return imports->register_interface(us
+ , PIL_PLUGINTYPE_S
+ , PIL_PLUGIN_S
+ , &bladehpiOps
+ , NULL /* close */
+ , &OurInterface
+ , (void *)&OurImports
+ , &interfprivate);
+}
+
+struct pluginDevice {
+ StonithPlugin sp;
+ const char * pluginid;
+ char * idinfo;
+ char * device;
+ int softreset;
+ GList * hostlist;
+ SaHpiVersionT ohver; /* OpenHPI interface version */
+ SaHpiSessionIdT ohsession; /* session ID */
+ SaHpiUint32T ohrptcnt; /* RPT count for hostlist */
+ SaHpiResourceIdT ohdevid; /* device resource ID */
+ SaHpiResourceIdT ohsensid; /* sensor resource ID */
+ SaHpiSensorNumT ohsensnum; /* sensor number */
+};
+
+static int open_hpi_session(struct pluginDevice *dev);
+static void close_hpi_session(struct pluginDevice *dev);
+
+static const char *pluginid = "BladeCenterDevice-Stonith";
+static const char *NOTpluginID = "IBM BladeCenter device has been destroyed";
+
+#include "stonith_config_xml.h"
+
+#define XML_ENTITYROOT_SHORTDESC \
+ XML_PARM_SHORTDESC_BEGIN("en") \
+ ST_ENTITYROOT \
+ XML_PARM_SHORTDESC_END
+
+#define XML_ENTITYROOT_LONGDESC \
+ XML_PARM_LONGDESC_BEGIN("en") \
+ "The entity_root of the STONITH device from the OpenHPI config file" \
+ XML_PARM_LONGDESC_END
+
+#define XML_ENTITYROOT_PARM \
+ XML_PARAMETER_BEGIN(ST_ENTITYROOT, "string", "1", "0") \
+ XML_ENTITYROOT_SHORTDESC \
+ XML_ENTITYROOT_LONGDESC \
+ XML_PARAMETER_END
+
+#define XML_SOFTRESET_SHORTDESC \
+ XML_PARM_SHORTDESC_BEGIN("en") \
+ ST_SOFTRESET \
+ XML_PARM_SHORTDESC_END
+
+#define XML_SOFTRESET_LONGDESC \
+ XML_PARM_LONGDESC_BEGIN("en") \
+ "Soft reset indicator, true|1 if STONITH device should use soft reset (power cycle) to reset nodes, false|0 if device should use hard reset (power off, wait, power on); default is false" \
+ XML_PARM_LONGDESC_END
+
+#define XML_SOFTRESET_PARM \
+ XML_PARAMETER_BEGIN(ST_SOFTRESET, "string", "0", "0") \
+ XML_SOFTRESET_SHORTDESC \
+ XML_SOFTRESET_LONGDESC \
+ XML_PARAMETER_END
+
+static const char *bladehpiXML =
+ XML_PARAMETERS_BEGIN
+ XML_ENTITYROOT_PARM
+ XML_SOFTRESET_PARM
+ XML_PARAMETERS_END;
+
+static int get_resource_type(char *, SaHpiRptEntryT *);
+static int get_sensor_num(SaHpiSessionIdT, SaHpiResourceIdT);
+static int get_bladehpi_hostlist(struct pluginDevice *);
+static void free_bladehpi_hostlist(struct pluginDevice *);
+static int get_num_tokens(char *str);
+
+struct blade_info {
+ char * name; /* blade name */
+ SaHpiResourceIdT resourceId; /* blade resource ID */
+ SaHpiCapabilitiesT resourceCaps; /* blade capabilities */
+};
+
+
+static int
+bladehpi_status(StonithPlugin *s)
+{
+ struct pluginDevice * dev;
+ SaErrorT ohrc;
+ SaHpiDomainInfoT ohdi;
+ int rc = S_OK;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called", __FUNCTION__);
+ }
+
+ ERRIFWRONGDEV(s, S_OOPS);
+
+ dev = (struct pluginDevice *)s;
+ rc = open_hpi_session(dev);
+ if( rc != S_OK )
+ return rc;
+
+ /* Refresh the hostlist only if RPTs updated */
+ ohrc = saHpiDomainInfoGet(dev->ohsession, &ohdi);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get domain info in %s (%d)"
+ , __FUNCTION__, ohrc);
+ rc = S_BADCONFIG;
+ goto done;
+ }
+ if (dev->ohrptcnt != ohdi.RptUpdateCount) {
+ free_bladehpi_hostlist(dev);
+ if (get_bladehpi_hostlist(dev) != S_OK) {
+ LOG(PIL_CRIT, "Unable to obtain list of hosts in %s"
+ , __FUNCTION__);
+ rc = S_BADCONFIG;
+ goto done;
+ }
+ }
+
+ /* At this point, hostlist is up to date */
+ if (dev->ohsensid && dev->ohsensnum) {
+ /*
+ * For accurate status, need to make a call that goes out to
+ * BladeCenter MM because the calls made so far by this
+ * function (and perhaps get_bladehpi_hostlist) only retrieve
+ * information from memory cached by OpenHPI
+ */
+ ohrc = saHpiSensorReadingGet(dev->ohsession
+ , dev->ohsensid, dev->ohsensnum, NULL, NULL);
+ if (ohrc == SA_ERR_HPI_BUSY || ohrc == SA_ERR_HPI_NO_RESPONSE) {
+ LOG(PIL_CRIT, "Unable to connect to BladeCenter in %s"
+ , __FUNCTION__);
+ rc = S_OOPS;
+ goto done;
+ }
+ }
+
+done:
+ close_hpi_session(dev);
+ return (rc == S_OK) ? (dev->ohdevid ? S_OK : S_OOPS) : rc;
+}
+
+
+/*
+ * Return the list of hosts configured for this HMC device
+ */
+
+static char **
+bladehpi_hostlist(StonithPlugin *s)
+{
+ struct pluginDevice * dev;
+ int numnames = 0, j;
+ char ** ret = NULL;
+ GList * node = NULL;
+ SaErrorT ohrc;
+ SaHpiDomainInfoT ohdi;
+ int rc = S_OK;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called", __FUNCTION__);
+ }
+
+ ERRIFWRONGDEV(s, NULL);
+
+ dev = (struct pluginDevice *)s;
+ rc = open_hpi_session(dev);
+ if( rc != S_OK )
+ return NULL;
+
+ /* Refresh the hostlist only if RPTs updated */
+ ohrc = saHpiDomainInfoGet(dev->ohsession, &ohdi);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get domain info in %s (%d)"
+ , __FUNCTION__, ohrc);
+ goto done;
+ }
+ if (dev->ohrptcnt != ohdi.RptUpdateCount) {
+ free_bladehpi_hostlist(dev);
+ if (get_bladehpi_hostlist(dev) != S_OK) {
+ LOG(PIL_CRIT, "Unable to obtain list of hosts in %s"
+ , __FUNCTION__);
+ goto done;
+ }
+ }
+
+ /* At this point, hostlist is up to date */
+ numnames = g_list_length(dev->hostlist);
+ if (numnames < 0) {
+ LOG(PIL_CRIT, "Unconfigured stonith object in %s"
+ , __FUNCTION__);
+ goto done;
+ }
+
+ ret = (char **)MALLOC((numnames+1) * sizeof(char *));
+ if (ret == NULL) {
+ LOG(PIL_CRIT, "Out of memory for malloc in %s", __FUNCTION__);
+ goto done;
+ }
+
+ memset(ret, 0, (numnames+1) * sizeof(char *));
+ for (node = g_list_first(dev->hostlist), j = 0
+ ; NULL != node
+ ; j++, node = g_list_next(node)) {
+ ret[j] = STRDUP(((struct blade_info *)node->data)->name);
+ if (ret[j] == NULL) {
+ LOG(PIL_CRIT, "Out of memory for strdup in %s"
+ , __FUNCTION__);
+ stonith_free_hostlist(ret);
+ ret = NULL;
+ goto done;
+ }
+ strdown(ret[j]);
+ }
+
+done:
+ close_hpi_session(dev);
+ return ret;
+}
+
+
+static const char * const *
+bladehpi_get_confignames(StonithPlugin *s)
+{
+ static const char * names[] = {ST_ENTITYROOT, NULL};
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called", __FUNCTION__);
+ }
+
+ return names;
+}
+
+
+/*
+ * Reset the given host, and obey the request type.
+ */
+
+static int
+bladehpi_reset_req(StonithPlugin *s, int request, const char *host)
+{
+ GList * node = NULL;
+ struct pluginDevice * dev = NULL;
+ struct blade_info * bi = NULL;
+ SaHpiPowerStateT ohcurstate, ohnewstate;
+ SaHpiDomainInfoT ohdi;
+ SaErrorT ohrc;
+ int rc = S_OK;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called, request=%d, host=%s"
+ , __FUNCTION__, request, host);
+ }
+
+ ERRIFWRONGDEV(s, S_OOPS);
+
+ if (host == NULL) {
+ LOG(PIL_CRIT, "Invalid host argument to %s", __FUNCTION__);
+ rc = S_OOPS;
+ goto done;
+ }
+
+ dev = (struct pluginDevice *)s;
+ rc = open_hpi_session(dev);
+ if( rc != S_OK )
+ return rc;
+
+ ohrc = saHpiDomainInfoGet(dev->ohsession, &ohdi);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get domain info in %s (%d)"
+ , __FUNCTION__, ohrc);
+ rc = S_BADCONFIG;
+ goto done;
+ }
+ if (dev->ohrptcnt != ohdi.RptUpdateCount) {
+ free_bladehpi_hostlist(dev);
+ if (get_bladehpi_hostlist(dev) != S_OK) {
+ LOG(PIL_CRIT, "Unable to obtain list of hosts in %s"
+ , __FUNCTION__);
+ rc = S_OOPS;
+ goto done;
+ }
+ }
+
+ for (node = g_list_first(dev->hostlist)
+ ; node != NULL
+ ; node = g_list_next(node)) {
+ bi = ((struct blade_info *)node->data);
+ if (Debug) {
+ LOG(PIL_DEBUG, "Found host %s in hostlist", bi->name);
+ }
+
+ if (!strcasecmp(bi->name, host)) {
+ break;
+ }
+ }
+
+ if (!node || !bi) {
+ LOG(PIL_CRIT
+ , "Host %s is not configured in this STONITH module, "
+ "please check your configuration information", host);
+ rc = S_OOPS;
+ goto done;
+ }
+
+ /* Make sure host has proper capabilities for get */
+ if (!(bi->resourceCaps & SAHPI_CAPABILITY_POWER)) {
+ LOG(PIL_CRIT
+ , "Host %s does not have power capability", host);
+ rc = S_OOPS;
+ goto done;
+ }
+
+ ohrc = saHpiResourcePowerStateGet(dev->ohsession, bi->resourceId
+ , &ohcurstate);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get host %s power state (%d)"
+ , host, ohrc);
+ rc = S_OOPS;
+ goto done;
+ }
+
+ switch (request) {
+ case ST_POWERON:
+ if (ohcurstate == SAHPI_POWER_ON) {
+ LOG(PIL_INFO, "Host %s already on", host);
+ goto done;
+ }
+ ohnewstate = SAHPI_POWER_ON;
+
+ break;
+
+ case ST_POWEROFF:
+ if (ohcurstate == SAHPI_POWER_OFF) {
+ LOG(PIL_INFO, "Host %s already off", host);
+ goto done;
+ }
+ ohnewstate = SAHPI_POWER_OFF;
+
+ break;
+
+ case ST_GENERIC_RESET:
+ if (ohcurstate == SAHPI_POWER_OFF) {
+ ohnewstate = SAHPI_POWER_ON;
+ } else {
+ ohnewstate = SAHPI_POWER_CYCLE;
+ }
+
+ break;
+
+ default:
+ LOG(PIL_CRIT, "Invalid request argument to %s"
+ , __FUNCTION__);
+ rc = S_INVAL;
+ goto done;
+ }
+
+ if (!dev->softreset && (ohnewstate == SAHPI_POWER_CYCLE)) {
+ int maxwait;
+
+ ohrc = saHpiResourcePowerStateSet(dev->ohsession
+ , bi->resourceId, SAHPI_POWER_OFF);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to set host %s power state to"
+ " OFF (%d)", host, ohrc);
+ rc = S_OOPS;
+ goto done;
+ }
+
+ /*
+ * Must wait for power off here or subsequent power on request
+ * may take place while power is still on and thus ignored
+ */
+ maxwait = MAX_POWEROFF_WAIT;
+ do {
+ maxwait--;
+ sleep(1);
+ ohrc = saHpiResourcePowerStateGet(dev->ohsession
+ , bi->resourceId, &ohcurstate);
+ } while ((ohrc == SA_OK)
+ && (ohcurstate != SAHPI_POWER_OFF)
+ && (maxwait > 0));
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "Waited %d seconds for power off"
+ , MAX_POWEROFF_WAIT - maxwait);
+ }
+
+ ohrc = saHpiResourcePowerStateSet(dev->ohsession
+ , bi->resourceId, SAHPI_POWER_ON);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to set host %s power state to"
+ " ON (%d)", host, ohrc);
+ rc = S_OOPS;
+ goto done;
+ }
+ } else {
+ /* Make sure host has proper capabilities to reset */
+ if ((ohnewstate == SAHPI_POWER_CYCLE) &&
+ (!(bi->resourceCaps & SAHPI_CAPABILITY_RESET))) {
+ LOG(PIL_CRIT
+ , "Host %s does not have reset capability"
+ , host);
+ rc = S_OOPS;
+ goto done;
+ }
+
+ if ((ohrc = saHpiResourcePowerStateSet(dev->ohsession
+ , bi->resourceId, ohnewstate)) != SA_OK) {
+ LOG(PIL_CRIT, "Unable to set host %s power state (%d)"
+ , host, ohrc);
+ rc = S_OOPS;
+ goto done;
+ }
+ }
+
+#ifdef IBMBC_WAIT_FOR_OFF
+ if (ohnewstate == SAHPI_POWER_OFF) {
+ int maxwait = MAX_POWEROFF_WAIT;
+
+ do {
+ maxwait--;
+ sleep(1);
+ ohrc = saHpiResourcePowerStateGet(dev->ohsession
+ , bi->resourceId, &ohcurstate);
+ } while ((ohrc == SA_OK)
+ && (ohcurstate != SAHPI_POWER_OFF)
+ && (maxwait > 0));
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "Waited %d seconds for power off"
+ , MAX_POWEROFF_WAIT - maxwait);
+ }
+ }
+#endif
+
+ LOG(PIL_INFO, "Host %s %s %d.", host, __FUNCTION__, request);
+
+done:
+ close_hpi_session(dev);
+ return rc;
+}
+
+
+/*
+ * Parse the information in the given configuration file,
+ * and stash it away...
+ */
+
+static int
+bladehpi_set_config(StonithPlugin *s, StonithNVpair *list)
+{
+ struct pluginDevice * dev = NULL;
+ StonithNamesToGet namestocopy [] =
+ { {ST_ENTITYROOT, NULL}
+ , {NULL, NULL}
+ };
+ int rc, i;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called", __FUNCTION__);
+ }
+
+ ERRIFWRONGDEV(s, S_OOPS);
+
+ dev = (struct pluginDevice *)s;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s conditionally compiled with:"
+#ifdef IBMBC_WAIT_FOR_OFF
+ " IBMBC_WAIT_FOR_OFF"
+#endif
+ , dev->pluginid);
+ }
+
+ if ((rc = OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
+ return rc;
+ }
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s = %s", ST_ENTITYROOT
+ , namestocopy[0].s_value);
+ }
+
+ if (get_num_tokens(namestocopy[0].s_value) == 1) {
+ /* name=value pairs on command line, look for soft_reset */
+ const char *softreset =
+ OurImports->GetValue(list, ST_SOFTRESET);
+ if (softreset != NULL) {
+ if (!strcasecmp(softreset, "true") ||
+ !strcmp(softreset, "1")) {
+ dev->softreset = 1;
+ } else if (!strcasecmp(softreset, "false") ||
+ !strcmp(softreset, "0")) {
+ dev->softreset = 0;
+ } else {
+ LOG(PIL_CRIT, "Invalid %s %s, must be "
+ "true, 1, false or 0"
+ , ST_SOFTRESET, softreset);
+ FREE(namestocopy[0].s_value);
+ return S_OOPS;
+ }
+ }
+ } else {
+ /* -p or -F option with args "entity_root [soft_reset]..." */
+ char *pch = namestocopy[0].s_value;
+
+ /* skip over entity_root and null-terminate */
+ pch += strcspn(pch, WHITESPACE);
+ *pch = EOS;
+
+ /* skip over white-space up to next token */
+ pch++;
+ pch += strspn(pch, WHITESPACE);
+ if (!strcasecmp(pch, "true") || !strcmp(pch, "1")) {
+ dev->softreset = 1;
+ } else if (!strcasecmp(pch, "false") || !strcmp(pch, "0")) {
+ dev->softreset = 0;
+ } else {
+ LOG(PIL_CRIT, "Invalid %s %s, must be "
+ "true, 1, false or 0"
+ , ST_SOFTRESET, pch);
+ FREE(namestocopy[0].s_value);
+ return S_OOPS;
+ }
+ }
+
+ dev->device = STRDUP(namestocopy[0].s_value);
+ FREE(namestocopy[0].s_value);
+ if (dev->device == NULL) {
+ LOG(PIL_CRIT, "Out of memory for strdup in %s", __FUNCTION__);
+ return S_OOPS;
+ }
+
+ if (strcspn(dev->device, WHITESPACE) != strlen(dev->device) ||
+ sscanf(dev->device, SYSTEM_CHASSIS_FMT, &i) != 1 || i < 0) {
+ LOG(PIL_CRIT, "Invalid %s %s, must be of format %s"
+ , ST_ENTITYROOT, dev->device, SYSTEM_CHASSIS_FMT);
+ return S_BADCONFIG;
+ }
+
+ dev->ohver = saHpiVersionGet();
+ if (dev->ohver > SAHPI_INTERFACE_VERSION) {
+ LOG(PIL_CRIT, "Installed OpenHPI interface (%x) greater than "
+ "one used by plugin (%x), incompatibilites may exist"
+ , dev->ohver, SAHPI_INTERFACE_VERSION);
+ return S_BADCONFIG;
+ }
+ return S_OK;
+}
+
+static int
+open_hpi_session(struct pluginDevice *dev)
+{
+ SaErrorT ohrc;
+
+ ohrc = saHpiSessionOpen(SAHPI_UNSPECIFIED_DOMAIN_ID
+ , &dev->ohsession, NULL);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to open HPI session (%d)", ohrc);
+ return S_BADCONFIG;
+ }
+
+ ohrc = saHpiDiscover(dev->ohsession);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to discover resources (%d)", ohrc);
+ return S_BADCONFIG;
+ }
+
+ return S_OK;
+}
+static void
+close_hpi_session(struct pluginDevice *dev)
+{
+ if (dev && dev->ohsession) {
+ saHpiSessionClose(dev->ohsession);
+ dev->ohsession = 0;
+ }
+}
+
+static const char *
+bladehpi_getinfo(StonithPlugin *s, int reqtype)
+{
+ struct pluginDevice * dev;
+ const char * ret;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called, reqtype=%d"
+ , __FUNCTION__, reqtype);
+ }
+
+ ERRIFWRONGDEV(s, NULL);
+
+ dev = (struct pluginDevice *)s;
+
+ switch (reqtype) {
+ case ST_DEVICEID:
+ ret = dev->idinfo;
+ break;
+
+ case ST_DEVICENAME:
+ ret = dev->device;
+ break;
+
+ case ST_DEVICEDESCR:
+ ret = "IBM BladeCenter via OpenHPI\n"
+ "Use for IBM xSeries systems managed by BladeCenter\n"
+ " Required parameter name " ST_ENTITYROOT " is "
+ "a string (no white-space) of\n"
+ "the format \""SYSTEM_CHASSIS_FMT"\" "
+ "which is entity_root of BladeCenter\n"
+ "from OpenHPI config file, where %d is a positive "
+ "integer\n"
+ " Optional parameter name " ST_SOFTRESET " is "
+ "true|1 if STONITH device should\n"
+ "use soft reset (power cycle) to reset nodes or "
+ "false|0 if device should\n"
+ "use hard reset (power off, wait, power on); "
+ "default is false";
+ break;
+
+ case ST_DEVICEURL:
+ ret = OPENHPIURL;
+ break;
+
+ case ST_CONF_XML: /* XML metadata */
+ ret = bladehpiXML;
+ break;
+
+ default:
+ ret = NULL;
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ * HMC Stonith destructor...
+ */
+
+static void
+bladehpi_destroy(StonithPlugin *s)
+{
+ struct pluginDevice * dev;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called", __FUNCTION__);
+ }
+
+ VOIDERRIFWRONGDEV(s);
+
+ dev = (struct pluginDevice *)s;
+
+ dev->pluginid = NOTpluginID;
+ if (dev->device) {
+ FREE(dev->device);
+ dev->device = NULL;
+ }
+ if (dev->idinfo) {
+ FREE(dev->idinfo);
+ dev->idinfo = NULL;
+ }
+ free_bladehpi_hostlist(dev);
+
+ if (dev->ohsession) {
+ saHpiSessionClose(dev->ohsession);
+ dev->ohsession = 0;
+ }
+
+ FREE(dev);
+}
+
+
+static StonithPlugin *
+bladehpi_new(const char *subplugin)
+{
+ struct pluginDevice * dev = ST_MALLOCT(struct pluginDevice);
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called", __FUNCTION__);
+ }
+
+ if (dev == NULL) {
+ LOG(PIL_CRIT, "Out of memory in %s", __FUNCTION__);
+ return NULL;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+
+ dev->pluginid = pluginid;
+ dev->device = NULL;
+ dev->hostlist = NULL;
+ REPLSTR(dev->idinfo, DEVICE);
+ if (dev->idinfo == NULL) {
+ FREE(dev);
+ return NULL;
+ }
+ dev->sp.s_ops = &bladehpiOps;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: returning successfully", __FUNCTION__);
+ }
+
+ return ((void *)dev);
+}
+
+
+static int
+get_resource_type(char *entityRoot, SaHpiRptEntryT *ohRPT)
+{
+ int i, rc = OHRES_NONE;
+ int foundBlade = 0, foundExp = 0, foundMgmt = 0;
+ int foundRoot = 0, foundOther = 0;
+ char rootName[64];
+ SaHpiEntityPathT * ohep = &ohRPT->ResourceEntity;
+
+ if (ohep == NULL || entityRoot == NULL) {
+ return 0;
+ }
+
+ /* First find root of entity path, which is last entity in entry */
+ for (i = 0; i < SAHPI_MAX_ENTITY_PATH; i++) {
+ if (ohep->Entry[i].EntityType == SAHPI_ENT_ROOT) {
+ break;
+ }
+ }
+
+ /* Then back up through entries looking for specific entity */
+ for (i--; i >= 0; i--) {
+ switch (ohep->Entry[i].EntityType) {
+ case SAHPI_ENT_SBC_BLADE:
+ foundBlade = 1;
+ break;
+
+ case SAHPI_ENT_SYS_EXPANSION_BOARD:
+ foundExp = 1;
+ break;
+
+ case SAHPI_ENT_SYS_MGMNT_MODULE:
+ if (ohep->Entry[i].EntityLocation == 0) {
+ foundMgmt = 1;
+ }
+ break;
+
+ case SAHPI_ENT_SYSTEM_CHASSIS:
+ snprintf(rootName, sizeof(rootName)
+ , SYSTEM_CHASSIS_FMT
+ , ohep->Entry[i].EntityLocation);
+ if (!strcmp(entityRoot, rootName)) {
+ foundRoot = 1;
+ }
+ break;
+
+ default:
+ foundOther = 1;
+ break;
+ }
+ }
+
+ /* We are only interested in specific entities on specific device */
+ if (foundRoot) {
+ if (foundMgmt && !(foundBlade||foundExp||foundOther)) {
+ rc = OHRES_MGMTMOD;
+ } else if (!(foundMgmt||foundBlade||foundExp||foundOther)) {
+ rc = OHRES_BLADECENT;
+ } else if (foundBlade && !foundExp) {
+ rc = OHRES_BLADE;
+ }
+ }
+
+ return rc;
+}
+
+
+static int
+get_sensor_num(SaHpiSessionIdT ohsession, SaHpiResourceIdT ohresid)
+{
+ SaErrorT ohrc = SA_OK;
+ SaHpiEntryIdT ohnextid;
+ SaHpiRdrT ohRDR;
+
+ ohnextid = SAHPI_FIRST_ENTRY;
+ do {
+ ohrc = saHpiRdrGet(ohsession, ohresid, ohnextid
+ , &ohnextid, &ohRDR);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get RDR entry in %s (%d)"
+ , __FUNCTION__, ohrc);
+ } else if (ohRDR.RdrType == SAHPI_SENSOR_RDR) {
+ return ohRDR.RdrTypeUnion.SensorRec.Num;
+ }
+ } while (ohrc == SA_OK && ohnextid != SAHPI_LAST_ENTRY);
+
+ return 0;
+}
+
+
+/*
+ * Get RPT update count
+ * Loop through all RPT entries
+ * If entry is BladeCenter, save resource ID in dev->ohdevid
+ * If entry is MgmtMod and has sensor, save resource ID in dev->ohsensid
+ * and sensor number in dev->ohsensnum
+ * If entry is blade, save blade_info and add to dev->hostlist
+ * Get RPT update count
+ * If RPT update count changed since start of loop, repeat loop
+ * Save RPT update count in dev->ohrptcnt
+ *
+ * Note that not only does this function update hostlist, it also
+ * updates ohrptcnt, ohdevid, ohsensid and ohsensnum. However, with
+ * this logic it does not need to be called again until the RPT update
+ * count changes.
+ */
+
+static int
+get_bladehpi_hostlist(struct pluginDevice *dev)
+{
+ struct blade_info * bi;
+ SaErrorT ohrc;
+ SaHpiEntryIdT ohnextid;
+ SaHpiRptEntryT ohRPT;
+ SaHpiDomainInfoT ohdi;
+ SaHpiUint32T ohupdate;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called, dev->device=%s"
+ , __FUNCTION__, dev->device);
+ }
+
+ if (dev->device == NULL || *dev->device == 0) {
+ LOG(PIL_CRIT, "Unconfigured stonith object in %s"
+ , __FUNCTION__);
+ return S_BADCONFIG;
+ }
+
+ ohrc = saHpiDomainInfoGet(dev->ohsession, &ohdi);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get domain info in %s (%d)"
+ , __FUNCTION__, ohrc);
+ return S_BADCONFIG;
+ }
+
+try_again:
+ ohupdate = ohdi.RptUpdateCount;
+ dev->ohdevid = dev->ohsensid = dev->ohsensnum = 0;
+ ohnextid = SAHPI_FIRST_ENTRY;
+ do {
+ char blname[SAHPI_MAX_TEXT_BUFFER_LENGTH];
+ int blnum;
+
+ ohrc = saHpiRptEntryGet(dev->ohsession, ohnextid
+ , &ohnextid, &ohRPT);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get RPT entry in %s (%d)"
+ , __FUNCTION__, ohrc);
+ free_bladehpi_hostlist(dev);
+ return S_BADCONFIG;
+ }
+
+ switch (get_resource_type(dev->device, &ohRPT)) {
+ case OHRES_BLADECENT:
+ dev->ohdevid = ohRPT.ResourceId;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "BladeCenter '%s' has id %d"
+ , (char*)ohRPT.ResourceTag.Data
+ , dev->ohdevid);
+ }
+ break;
+
+ case OHRES_MGMTMOD:
+ if (ohRPT.ResourceCapabilities&SAHPI_CAPABILITY_SENSOR){
+ dev->ohsensnum = get_sensor_num(dev->ohsession
+ , ohRPT.ResourceId);
+
+ if (dev->ohsensnum) {
+ dev->ohsensid = ohRPT.ResourceId;
+
+ if (Debug) {
+ LOG(PIL_DEBUG
+ , "MgmtModule '%s' has id %d "
+ "with sensor #%d"
+ , (char*)ohRPT.ResourceTag.Data
+ , dev->ohsensid
+ , dev->ohsensnum);
+ }
+ }
+ }
+ break;
+
+ case OHRES_BLADE:
+ if ((bi = (struct blade_info *)
+ MALLOC(sizeof(struct blade_info))) == NULL) {
+ LOG(PIL_CRIT, "Out of memory in %s"
+ , __FUNCTION__);
+ free_bladehpi_hostlist(dev);
+ return S_OOPS;
+ }
+
+ /*
+ * New format consists of "Blade N - name" while older
+ * format consists only of "name"; we only need to
+ * stash name because ResourceID is the important info
+ */
+ if (sscanf((char*)ohRPT.ResourceTag.Data, "Blade %d - %s"
+ , &blnum, blname) == 2) {
+ bi->name = STRDUP(blname);
+ } else {
+ bi->name = STRDUP((char*)ohRPT.ResourceTag.Data);
+ }
+ if (bi->name == NULL) {
+ LOG(PIL_CRIT, "Out of memory for strdup in %s"
+ , __FUNCTION__);
+ free_bladehpi_hostlist(dev);
+ return S_OOPS;
+ }
+
+ bi->resourceId = ohRPT.ResourceId;
+ bi->resourceCaps = ohRPT.ResourceCapabilities;
+ dev->hostlist = g_list_append(dev->hostlist, bi);
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "Blade '%s' has id %d, caps %x"
+ , bi->name, bi->resourceId, bi->resourceCaps);
+ }
+ break;
+ }
+ } while (ohrc == SA_OK && ohnextid != SAHPI_LAST_ENTRY);
+
+ ohrc = saHpiDomainInfoGet(dev->ohsession, &ohdi);
+ if (ohrc != SA_OK) {
+ LOG(PIL_CRIT, "Unable to get domain info in %s (%d)"
+ , __FUNCTION__, ohrc);
+ free_bladehpi_hostlist(dev);
+ return S_BADCONFIG;
+ }
+
+ if (ohupdate != ohdi.RptUpdateCount) {
+ free_bladehpi_hostlist(dev);
+ if(Debug){
+ LOG(PIL_DEBUG, "Looping through entries again,"
+ " count changed from %d to %d"
+ , ohupdate, ohdi.RptUpdateCount);
+ }
+ goto try_again;
+ }
+
+ dev->ohrptcnt = ohupdate;
+
+ return S_OK;
+}
+
+
+static void
+free_bladehpi_hostlist(struct pluginDevice *dev)
+{
+ if (dev->hostlist) {
+ GList *node;
+ while (NULL != (node = g_list_first(dev->hostlist))) {
+ dev->hostlist =
+ g_list_remove_link(dev->hostlist, node);
+ FREE(((struct blade_info *)node->data)->name);
+ FREE(node->data);
+ g_list_free(node);
+ }
+ dev->hostlist = NULL;
+ }
+ dev->ohdevid = dev->ohsensid = dev->ohsensnum = 0;
+}
+
+
+static int
+get_num_tokens(char *str)
+{
+ int namecount = 0;
+
+ while (*str != EOS) {
+ str += strspn(str, WHITESPACE);
+ if (*str == EOS)
+ break;
+ str += strcspn(str, WHITESPACE);
+ namecount++;
+ }
+ return namecount;
+}