summaryrefslogtreecommitdiff
path: root/util/oem_sun.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/oem_sun.c')
-rw-r--r--util/oem_sun.c1058
1 files changed, 1058 insertions, 0 deletions
diff --git a/util/oem_sun.c b/util/oem_sun.c
new file mode 100644
index 0000000..da413a8
--- /dev/null
+++ b/util/oem_sun.c
@@ -0,0 +1,1058 @@
+/*
+ * oem_sun.c
+ * Handle Sun OEM command functions
+ *
+ * Change history:
+ * 09/02/2010 ARCress - included in source tree
+ *
+ *---------------------------------------------------------------------
+ */
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#include <windows.h>
+#define uint8_t unsigned char
+#define uint16_t unsigned short
+#define uint32_t unsigned int
+#include "getopt.h"
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include <limits.h>
+#if defined(HPUX)
+/* getopt is defined in stdio.h */
+#elif defined(MACOS)
+/* getopt is defined in unistd.h */
+#include <unistd.h>
+#include <stdint.h>
+#else
+#include <getopt.h>
+#endif
+#endif
+
+#ifndef ULONG_MAX
+/*needed for WIN32*/
+#define ULONG_MAX 4294967295UL
+#define UCHAR_MAX 255
+#endif
+
+#include "ipmicmd.h"
+#include "isensor.h"
+#include "oem_sun.h"
+
+extern int verbose; /*ipmilanplus.c*/
+extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/
+extern void set_loglevel(int level);
+
+static const struct valstr sunoem_led_type_vals[] = {
+ { 0, "OK2RM" },
+ { 1, "SERVICE" },
+ { 2, "ACT" },
+ { 3, "LOCATE" },
+ { 0xFF, NULL }
+};
+
+static const struct valstr sunoem_led_mode_vals[] = {
+ { 0, "OFF" },
+ { 1, "ON" },
+ { 2, "STANDBY" },
+ { 3, "SLOW" },
+ { 4, "FAST" },
+ { 0xFF, NULL }
+};
+static const struct valstr sunoem_led_mode_optvals[] = {
+ { 0, "STEADY_OFF" },
+ { 1, "STEADY_ON" },
+ { 2, "STANDBY_BLINK" },
+ { 3, "SLOW_BLINK" },
+ { 4, "FAST_BLINK" },
+ { 0xFF, NULL }
+};
+
+/* global variables */
+static char * progname = "isunoem";
+static char * progver = "2.93";
+static char fdebug = 0;
+static uchar g_bus = PUBLIC_BUS;
+static uchar g_sa = BMC_SA;
+static uchar g_lun = BMC_LUN;
+static uchar g_addrtype = ADDR_SMI;
+static int is_sbcmd = 0;
+static int csv_output = 0;
+static uchar *sdrcache = NULL;
+static int vend_id = 0;
+static int prod_id = 0;
+
+static void
+ipmi_sunoem_usage(void)
+{
+ lprintf(LOG_NOTICE, "usage: sunoem <command> [option...]");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " fan speed <0-100>");
+ lprintf(LOG_NOTICE, " Set system fan speed (PWM duty cycle)");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " sshkey set <userid> <id_rsa.pub>");
+ lprintf(LOG_NOTICE, " Set ssh key for a userid into authorized_keys,");
+ lprintf(LOG_NOTICE, " view users with 'user list' command.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " sshkey del <userid>");
+ lprintf(LOG_NOTICE, " Delete ssh key for userid from authorized_keys,");
+ lprintf(LOG_NOTICE, " view users with 'user list' command.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " led get <sensorid> [ledtype]");
+ lprintf(LOG_NOTICE, " Read status of LED found in Generic Device Locator.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " led set <sensorid> <ledmode> [ledtype]");
+ lprintf(LOG_NOTICE, " Set mode of LED found in Generic Device Locator.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " sbled get <sensorid> [ledtype]");
+ lprintf(LOG_NOTICE, " Read status of LED found in Generic Device Locator");
+ lprintf(LOG_NOTICE, " for Sun Blade Modular Systems.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " sbled set <sensorid> <ledmode> [ledtype]");
+ lprintf(LOG_NOTICE, " Set mode of LED found in Generic Device Locator");
+ lprintf(LOG_NOTICE, " for Sun Blade Modular Systems.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " Use 'sdr list generic' command to get list of Generic");
+ lprintf(LOG_NOTICE, " Devices that are controllable LEDs.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " Required SIS LED Mode:");
+ lprintf(LOG_NOTICE, " OFF Off");
+ lprintf(LOG_NOTICE, " ON Steady On");
+ lprintf(LOG_NOTICE, " STANDBY 100ms on 2900ms off blink rate");
+ lprintf(LOG_NOTICE, " SLOW 1HZ blink rate");
+ lprintf(LOG_NOTICE, " FAST 4HZ blink rate");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " Optional SIS LED Type:");
+ lprintf(LOG_NOTICE, " OK2RM OK to Remove");
+ lprintf(LOG_NOTICE, " SERVICE Service Required");
+ lprintf(LOG_NOTICE, " ACT Activity");
+ lprintf(LOG_NOTICE, " LOCATE Locate");
+ lprintf(LOG_NOTICE, "");
+}
+
+/*
+ * IPMI Request Data: 1 byte
+ *
+ * [byte 0] FanSpeed Fan speed as percentage
+ */
+static int
+ipmi_sunoem_fan_speed(void * intf, uint8_t speed)
+{
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ struct ipmi_rq req;
+
+ /*
+ * sunoem fan speed <percent>
+ */
+
+ if (speed > 100) {
+ lprintf(LOG_NOTICE, "Invalid fan speed: %d", speed);
+ return -1;
+ }
+
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_SET_FAN_SPEED;
+ req.msg.data = &speed;
+ req.msg.data_len = 1;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv < 0) {
+ lprintf(LOG_ERR, "Sun OEM Set Fan Speed command failed");
+ return (rv);
+ } else if (rv > 0) {
+ lprintf(LOG_ERR, "Sun OEM Set Fan Speed command failed: %s",
+ decode_cc(0,rv));
+ return (rv);
+ }
+
+ printf("Set Fan speed to %d%%\n", speed);
+
+ return rv;
+}
+
+
+static void
+led_print(const char * name, uint8_t state)
+{
+ if (csv_output)
+ printf("%s,%s\n", name, val2str(state, sunoem_led_mode_vals));
+ else
+ printf("%-16s | %s\n", name, val2str(state, sunoem_led_mode_vals));
+}
+
+int
+sunoem_led_get(void * intf, uchar *sdr, uchar ledtype, uchar *prsp)
+{
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ struct ipmi_rq req;
+ uint8_t rqdata[7];
+ int rqdata_len = 5;
+ struct sdr_record_generic_locator * dev;
+
+ if (sdr == NULL) return -1;
+ dev = (struct sdr_record_generic_locator *)&sdr[5];
+
+ rqdata[0] = dev->dev_slave_addr;
+ if (ledtype == 0xFF)
+ rqdata[1] = dev->oem;
+ else
+ rqdata[1] = ledtype;
+ rqdata[2] = dev->dev_access_addr;
+ rqdata[3] = dev->oem;
+ if (is_sbcmd) {
+ rqdata[4] = dev->entity.id;
+ rqdata[5] = dev->entity.instance;
+ rqdata[6] = 0;
+ rqdata_len = 7;
+ }
+ else {
+ rqdata[4] = 0;
+ }
+
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_LED_GET;
+ req.msg.lun = dev->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = (uchar)rqdata_len;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv < 0) {
+ lprintf(LOG_ERR, "Sun OEM Get LED command failed");
+ return rv;
+ }
+ else if (rv > 0) {
+ lprintf(LOG_ERR, "Sun OEM Get LED command failed: %s",
+ decode_cc(0,rv));
+ return rv;
+ }
+ if (prsp != NULL) memcpy(prsp,rsp,rsp_len);
+ if (rsp_len != 1) {
+ lprintf(LOG_ERR, "Sun OEM Get LED command error len=%d",
+ rsp_len);
+ return -1;
+ }
+ return rv;
+}
+
+int
+sunoem_led_set(void * intf, uchar *sdr, uchar ledtype, uchar ledmode)
+{
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ struct ipmi_rq req;
+ uint8_t rqdata[9];
+ int rqdata_len = 7;
+ struct sdr_record_generic_locator * dev;
+
+ if (sdr == NULL) return -1;
+ dev = (struct sdr_record_generic_locator *)&sdr[5];
+
+ rqdata[0] = dev->dev_slave_addr;
+ if (ledtype == 0xFF)
+ rqdata[1] = dev->oem;
+ else
+ rqdata[1] = ledtype;
+ rqdata[2] = dev->dev_access_addr;
+ rqdata[3] = dev->oem;
+ rqdata[4] = ledmode;
+ if (is_sbcmd) {
+ rqdata[5] = dev->entity.id;
+ rqdata[6] = dev->entity.instance;
+ rqdata[7] = 0;
+ rqdata[8] = 0;
+ rqdata_len = 9;
+ }
+ else {
+ rqdata[5] = 0;
+ rqdata[6] = 0;
+ }
+
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_LED_SET;
+ req.msg.lun = dev->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = (uchar)rqdata_len;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv < 0) {
+ lprintf(LOG_ERR, "Sun OEM Set LED command failed");
+ } else if (rv > 0) {
+ lprintf(LOG_ERR, "Sun OEM Set LED command failed: %s",
+ decode_cc(0,rv));
+ }
+ return rv;
+}
+
+static void
+sunoem_led_get_byentity(void * intf, uchar entity_id,
+ uchar entity_inst, uchar ledtype)
+{
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rv;
+ uchar *elist;
+ struct entity_id entity;
+ struct sdr_record_generic_locator *dev;
+ uchar sdr[IPMI_RSPBUF_SIZE];
+ ushort id;
+
+ if (entity_id == 0)
+ return;
+
+ /* lookup sdrs with this entity */
+ memset(&entity, 0, sizeof(struct entity_id));
+ entity.id = entity_id;
+ entity.instance = entity_inst;
+
+ if (sdrcache == NULL) rv = get_sdr_cache(&elist);
+ else elist = sdrcache;
+ id = 0;
+ /* for each generic sensor set its led state */
+ while(find_sdr_next(sdr,elist,id) == 0) {
+ id = sdr[0] + (sdr[1] << 8);
+ if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+ dev = (struct sdr_record_generic_locator *)&sdr[5];
+ if ((dev->entity.id == entity_id) &&
+ (dev->entity.instance == entity_inst)) {
+ rv = sunoem_led_get(intf, sdr, ledtype, rsp);
+ if (rv == 0) {
+ led_print((const char *)dev->id_string, rsp[0]);
+ }
+ }
+ }
+
+ if (sdrcache == NULL) free_sdr_cache(elist);
+}
+
+static void
+sunoem_led_set_byentity(void * intf, uchar entity_id,
+ uchar entity_inst, uchar ledtype, uchar ledmode)
+{
+ int rv;
+ uchar *elist;
+ struct entity_id entity;
+ struct sdr_record_generic_locator * dev;
+ uchar sdr[IPMI_RSPBUF_SIZE];
+ ushort id;
+
+ if (entity_id == 0)
+ return;
+
+ /* lookup sdrs with this entity */
+ memset(&entity, 0, sizeof(struct entity_id));
+ entity.id = entity_id;
+ entity.instance = entity_inst;
+
+ if (sdrcache == NULL) rv = get_sdr_cache(&elist);
+ else elist = sdrcache;
+ id = 0;
+ /* for each generic sensor set its led state */
+ while(find_sdr_next(sdr,elist,id) == 0) {
+ id = sdr[0] + (sdr[1] << 8);
+ if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+ /* match entity_id and entity_inst */
+ dev = (struct sdr_record_generic_locator *)&sdr[5];
+ if ((dev->entity.id == entity_id) &&
+ (dev->entity.instance == entity_inst)) {
+ rv = sunoem_led_set(intf, sdr, ledtype, ledmode);
+ if (rv == 0) {
+ led_print((const char *)dev->id_string, ledmode);
+ }
+ }
+ }
+
+ if (sdrcache == NULL) free_sdr_cache(elist);
+}
+
+/*
+ * IPMI Request Data: 5 bytes
+ *
+ * [byte 0] devAddr Value from the "Device Slave Address" field in
+ * LED's Generic Device Locator record in the SDR
+ * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE
+ * [byte 2] ctrlrAddr Controller address; value from the "Device
+ * Access Address" field, 0x20 if the LED is local
+ * [byte 3] hwInfo The OEM field from the SDR record
+ * [byte 4] force 1 = directly access the device
+ * 0 = go thru its controller
+ * Ignored if LED is local
+ *
+ * The format below is for Sun Blade Modular systems only
+ * [byte 4] entityID The entityID field from the SDR record
+ * [byte 5] entityIns The entityIns field from the SDR record
+ * [byte 6] force 1 = directly access the device
+ * 0 = go thru its controller
+ * Ignored if LED is local
+ */
+static int
+ipmi_sunoem_led_get(void * intf, int argc, char ** argv)
+{
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rv;
+ uchar *alist;
+ struct sdr_record_entity_assoc *assoc;
+ struct sdr_record_generic_locator * dev;
+ uchar sdr[IPMI_RSPBUF_SIZE];
+ uchar sdr1[IPMI_RSPBUF_SIZE];
+ ushort id;
+ uchar ledtype = 0xFF;
+ int i;
+
+ /*
+ * sunoem led/sbled get <id> [type]
+ */
+
+ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
+ ipmi_sunoem_usage();
+ return 0;
+ }
+
+ if (argc > 1) {
+ ledtype = (uchar)str2val(argv[1], sunoem_led_type_vals);
+ if (ledtype == 0xFF)
+ lprintf(LOG_ERR, "Unknown ledtype, will use data from the SDR oem field");
+ }
+
+ if (strncasecmp(argv[0], "all", 3) == 0) {
+ /* do all generic sensors */
+ lprintf(LOG_NOTICE, "Fetching SDRs ...");
+ rv = get_sdr_cache(&alist);
+ if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv);
+ id = 0;
+ rv = ERR_NOT_FOUND;
+ while(find_sdr_next(sdr,alist,id) == 0) {
+ id = sdr[0] + (sdr[1] << 8);
+ if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+ dev = (struct sdr_record_generic_locator *)&sdr[5];
+ if (dev->entity.logical) // (sdr[13] & 0x80 != 0)
+ continue;
+ rv = sunoem_led_get(intf, sdr, ledtype, rsp);
+ if (rv == 0) {
+ led_print((const char *)dev->id_string, rsp[0]);
+ }
+ }
+ free_sdr_cache(alist);
+ return rv;
+ }
+
+ /* look up generic device locator record in SDR */
+ id = (ushort)atoi(argv[0]);
+ lprintf(LOG_NOTICE, "Fetching SDRs ...");
+ rv = get_sdr_cache(&alist);
+ if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv);
+ if (rv == 0) {
+ sdrcache = alist;
+ rv = find_sdr_next(sdr1,alist,id);
+ }
+ if (rv != 0) {
+ lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]);
+ free_sdr_cache(alist);
+ return (rv);
+ }
+
+ if (sdr1[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) {
+ lprintf(LOG_ERR, "Invalid SDR type %d", sdr1[3]);
+ free_sdr_cache(alist);
+ return (-1);
+ }
+
+ dev = (struct sdr_record_generic_locator *)&sdr1[5];
+ if (!dev->entity.logical) {
+ /*
+ * handle physical entity
+ */
+ rv = sunoem_led_get(intf, sdr1, ledtype, rsp);
+ if (rv == 0) {
+ led_print((const char *)dev->id_string, rsp[0]);
+ }
+ free_sdr_cache(alist);
+ return rv;
+ }
+
+ /*
+ * handle logical entity for LED grouping
+ */
+
+ lprintf(LOG_INFO, "LED %s is logical device", argv[0]);
+
+ /* get entity assoc records */
+ // rv = get_sdr_cache(&alist);
+ id = 0;
+ while(find_sdr_next(sdr,alist,id) == 0) {
+ id = sdr[0] + (sdr[1] << 8);
+ if (sdr[3] != SDR_RECORD_TYPE_ENTITY_ASSOC)
+ continue;
+ assoc = (struct sdr_record_entity_assoc *)&sdr[5];
+ if (assoc == NULL) continue;
+ /* check that the entity id/instance matches our generic record */
+ if (assoc->entity.id != dev->entity.id ||
+ assoc->entity.instance != dev->entity.instance)
+ continue;
+
+ if (assoc->flags.isrange) {
+ /*
+ * handle ranged entity associations
+ *
+ * the test for non-zero entity id is handled in
+ * sunoem_led_get_byentity()
+ */
+
+ /* first range set - id 1 and 2 must be equal */
+ if (assoc->entity_id_1 == assoc->entity_id_2)
+ for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++)
+ sunoem_led_get_byentity(intf, assoc->entity_id_1, (uchar)i, ledtype);
+
+ /* second range set - id 3 and 4 must be equal */
+ if (assoc->entity_id_3 == assoc->entity_id_4)
+ for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++)
+ sunoem_led_get_byentity(intf, assoc->entity_id_3, (uchar)i, ledtype);
+ }
+ else {
+ /*
+ * handle entity list
+ */
+ sunoem_led_get_byentity(intf, assoc->entity_id_1,
+ assoc->entity_inst_1, ledtype);
+ sunoem_led_get_byentity(intf, assoc->entity_id_2,
+ assoc->entity_inst_2, ledtype);
+ sunoem_led_get_byentity(intf, assoc->entity_id_3,
+ assoc->entity_inst_3, ledtype);
+ sunoem_led_get_byentity(intf, assoc->entity_id_4,
+ assoc->entity_inst_4, ledtype);
+ }
+ }
+
+ free_sdr_cache(alist);
+ sdrcache = NULL;
+
+ return rv;
+}
+
+/*
+ * IPMI Request Data: 7 bytes
+ *
+ * [byte 0] devAddr Value from the "Device Slave Address" field in
+ * LED's Generic Device Locator record in the SDR
+ * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE
+ * [byte 2] ctrlrAddr Controller address; value from the "Device
+ * Access Address" field, 0x20 if the LED is local
+ * [byte 3] hwInfo The OEM field from the SDR record
+ * [byte 4] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST
+ * [byte 5] force TRUE - directly access the device
+ * FALSE - go thru its controller
+ * Ignored if LED is local
+ * [byte 6] role Used by BMC for authorization purposes
+ *
+ * The format below is for Sun Blade Modular systems only
+ * [byte 5] entityID The entityID field from the SDR record
+ * [byte 6] entityIns The entityIns field from the SDR record
+ * [byte 7] force TRUE - directly access the device
+ * FALSE - go thru its controller
+ * Ignored if LED is local
+ * [byte 8] role Used by BMC for authorization purposes
+ *
+ *
+ * IPMI Response Data: 1 byte
+ *
+ * [byte 0] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST
+ */
+
+static int
+ipmi_sunoem_led_set(void * intf, int argc, char ** argv)
+{
+ int rv;
+ uchar *alist;
+ struct sdr_record_entity_assoc *assoc;
+ struct sdr_record_generic_locator * dev;
+ uchar sdr[IPMI_RSPBUF_SIZE];
+ uchar sdr1[IPMI_RSPBUF_SIZE];
+ ushort id;
+ uchar ledmode;
+ uchar ledtype = 0xFF;
+ int i;
+
+ /*
+ * sunoem led/sbled set <id> <mode> [type]
+ */
+
+ if (argc < 2 || strncmp(argv[0], "help", 4) == 0) {
+ ipmi_sunoem_usage();
+ return 0;
+ }
+
+ i = str2val(argv[1], sunoem_led_mode_vals);
+ if (i == 0xFF) {
+ i = str2val(argv[1], sunoem_led_mode_optvals);
+ if (i == 0xFF) {
+ lprintf(LOG_NOTICE, "Invalid LED Mode: %s", argv[1]);
+ return -1;
+ }
+ }
+ ledmode = (uchar)i;
+
+ if (argc > 3) {
+ ledtype = (uchar)str2val(argv[2], sunoem_led_type_vals);
+ if (ledtype == 0xFF)
+ lprintf(LOG_ERR, "Unknown ledtype, will use data from the SDR oem field");
+ }
+
+ if (strncasecmp(argv[0], "all", 3) == 0) {
+ /* do all generic sensors */
+ lprintf(LOG_NOTICE, "Fetching SDRs ...");
+ rv = get_sdr_cache(&alist);
+ if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv);
+ id = 0;
+ rv = ERR_NOT_FOUND;
+ while(find_sdr_next(sdr,alist,id) == 0) {
+ id = sdr[0] + (sdr[1] << 8);
+ if (sdr[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+ dev = (struct sdr_record_generic_locator *)&sdr[5];
+ if ((sdr[13] & 0x80) != 0) /*logical entity*/
+ continue;
+ rv = sunoem_led_set(intf, sdr, ledtype, ledmode);
+ if (rv == 0) {
+ led_print((const char *)dev->id_string, ledmode);
+ }
+ }
+ free_sdr_cache(alist);
+ return rv;
+ }
+
+ /* look up generic device locator records in SDR */
+ id = (ushort)atoi(argv[0]);
+ lprintf(LOG_NOTICE, "Fetching SDRs ...");
+ rv = get_sdr_cache(&alist);
+ if (fdebug) lprintf(LOG_NOTICE, "get_sdr_cache rv = %d",rv);
+ if (rv == 0) {
+ sdrcache = alist;
+ rv = find_sdr_next(sdr1,alist,id);
+ }
+ if (rv != 0) {
+ lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]);
+ free_sdr_cache(alist);
+ return (rv);
+ }
+
+ if (sdr1[3] != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) {
+ lprintf(LOG_ERR, "Invalid SDR type %d", sdr1[3]);
+ free_sdr_cache(alist);
+ return -1;
+ }
+ dev = (struct sdr_record_generic_locator *)&sdr1[5];
+
+ if (!dev->entity.logical) {
+ /*
+ * handle physical entity
+ */
+ rv = sunoem_led_set(intf, sdr, ledtype, ledmode);
+ if (rv == 0) {
+ led_print(argv[0], ledmode);
+ }
+ free_sdr_cache(alist);
+ return rv;
+ }
+
+ /*
+ * handle logical entity for LED grouping
+ */
+
+ lprintf(LOG_INFO, "LED %s is logical device", argv[0]);
+
+ /* get entity assoc records */
+ id = 0;
+ while(find_sdr_next(sdr,alist,id) == 0) {
+ id = sdr[0] + (sdr[1] << 8);
+ if (sdr[3] != SDR_RECORD_TYPE_ENTITY_ASSOC)
+ continue;
+ assoc = (struct sdr_record_entity_assoc *)&sdr[5];
+ if (assoc == NULL) continue;
+
+ /* check that the entity id/instance matches our generic record */
+ if (assoc->entity.id != dev->entity.id ||
+ assoc->entity.instance != dev->entity.instance)
+ continue;
+
+ if (assoc->flags.isrange) {
+ /*
+ * handle ranged entity associations
+ *
+ * the test for non-zero entity id is handled in
+ * sunoem_led_get_byentity()
+ */
+
+ /* first range set - id 1 and 2 must be equal */
+ if (assoc->entity_id_1 == assoc->entity_id_2)
+ for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++)
+ sunoem_led_set_byentity(intf, assoc->entity_id_1, (uchar)i, ledtype, ledmode);
+
+ /* second range set - id 3 and 4 must be equal */
+ if (assoc->entity_id_3 == assoc->entity_id_4)
+ for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++)
+ sunoem_led_set_byentity(intf, assoc->entity_id_3, (uchar)i, ledtype, ledmode);
+ }
+ else {
+ /*
+ * handle entity list
+ */
+ sunoem_led_set_byentity(intf, assoc->entity_id_1,
+ assoc->entity_inst_1, ledtype, ledmode);
+ sunoem_led_set_byentity(intf, assoc->entity_id_2,
+ assoc->entity_inst_2, ledtype, ledmode);
+ sunoem_led_set_byentity(intf, assoc->entity_id_3,
+ assoc->entity_inst_3, ledtype, ledmode);
+ sunoem_led_set_byentity(intf, assoc->entity_id_4,
+ assoc->entity_inst_4, ledtype, ledmode);
+ }
+ }
+
+ free_sdr_cache(alist);
+ sdrcache = NULL;
+
+ return rv;
+}
+
+static int
+ipmi_sunoem_sshkey_del(void * intf, uint8_t uid)
+{
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(struct ipmi_rq));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_DEL_SSH_KEY;
+ req.msg.data = &uid;
+ req.msg.data_len = 1;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv < 0) {
+ lprintf(LOG_ERR, "Unable to delete ssh key for UID %d", uid);
+ return rv;
+ }
+ else if (rv > 0) {
+ lprintf(LOG_ERR, "Unable to delete ssh key for UID %d: %s", uid,
+ decode_cc(0,rv));
+ return rv;
+ }
+
+ printf("Deleted SSH key for user id %d\n", uid);
+ return rv;
+}
+
+#define SSHKEY_BLOCK_SIZE 64
+static int
+ipmi_sunoem_sshkey_set(void * intf, uint8_t uid, char * ifile)
+{
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv = -1;
+ struct ipmi_rq req;
+ FILE * fp;
+ size_t count;
+ uint16_t i_size, r, f_size;
+ uint8_t wbuf[SSHKEY_BLOCK_SIZE + 3];
+
+ if (ifile == NULL) {
+ lprintf(LOG_ERR, "Invalid or missing input filename");
+ return -1;
+ }
+
+ fp = fopen(ifile, "r");
+ if (fp == NULL) {
+ lprintf(LOG_ERR, "Unable to open file %s for reading", ifile);
+ return -1;
+ }
+
+ printf("Setting SSH key for user id %d...", uid);
+
+ memset(&req, 0, sizeof(struct ipmi_rq));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_SET_SSH_KEY;
+ req.msg.data = wbuf;
+
+ fseek(fp, 0, SEEK_END);
+ f_size = (uint16_t)ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ for (r = 0; r < f_size; r += i_size) {
+ i_size = f_size - r;
+ if (i_size > SSHKEY_BLOCK_SIZE)
+ i_size = SSHKEY_BLOCK_SIZE;
+
+ memset(wbuf, 0, SSHKEY_BLOCK_SIZE);
+ fseek(fp, r, SEEK_SET);
+ count = fread(wbuf+3, 1, i_size, fp);
+ if (count != i_size) {
+ lprintf(LOG_ERR, "Unable to read %d bytes from file %s", i_size, ifile);
+ fclose(fp);
+ return -1;
+ }
+
+ printf(".");
+ fflush(stdout);
+
+ wbuf[0] = uid;
+ if ((r + SSHKEY_BLOCK_SIZE) >= f_size)
+ wbuf[1] = 0xff;
+ else
+ wbuf[1] = (uint8_t)(r / SSHKEY_BLOCK_SIZE);
+ wbuf[2] = (uint8_t)i_size;
+ req.msg.data_len = i_size + 3;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv < 0) {
+ lprintf(LOG_ERR, "Unable to set ssh key for UID %d", uid);
+ break;
+ }
+ }
+
+ printf("done\n");
+
+ fclose(fp);
+ return rv;
+}
+
+
+int
+ipmi_sunoem_main(void * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
+ ipmi_sunoem_usage();
+ return 0;
+ }
+
+ if (strncmp(argv[0], "fan", 3) == 0) {
+ uint8_t pct;
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ else if (strncmp(argv[1], "speed", 5) == 0) {
+ if (argc < 3) {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ pct = atob(argv[2]);
+ rc = ipmi_sunoem_fan_speed(intf, pct);
+ }
+ else {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ }
+
+ if ((strncmp(argv[0], "led", 3) == 0) || (strncmp(argv[0], "sbled", 5) == 0)) {
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ if (strncmp(argv[0], "sbled", 5) == 0) {
+ is_sbcmd = 1;
+ }
+ if (strncmp(argv[1], "get", 3) == 0) {
+ if (argc < 3) {
+ char * arg[] = { "all" };
+ rc = ipmi_sunoem_led_get(intf, 1, arg);
+ } else {
+ rc = ipmi_sunoem_led_get(intf, argc-2, &(argv[2]));
+ }
+ }
+ else if (strncmp(argv[1], "set", 3) == 0) {
+ if (argc < 4) {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ rc = ipmi_sunoem_led_set(intf, argc-2, &(argv[2]));
+ }
+ else {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ }
+
+ if (strncmp(argv[0], "sshkey", 6) == 0) {
+ uint8_t uid = 0;
+ unsigned long l;
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ else if (strncmp(argv[1], "del", 3) == 0) {
+ if (argc < 3) {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ l = strtoul(argv[2], NULL, 0);
+ if ((l == ULONG_MAX) || (l > UCHAR_MAX)) {
+ printf("param %s is out of bounds\n",argv[2]);
+ return -17; /*ERR_BAD_PARAM*/
+ }
+ uid = (uint8_t)l;
+ rc = ipmi_sunoem_sshkey_del(intf, uid);
+ }
+ else if (strncmp(argv[1], "set", 3) == 0) {
+ if (argc < 4) {
+ ipmi_sunoem_usage();
+ return -1;
+ }
+ l = strtoul(argv[2], NULL, 0);
+ if ((l == ULONG_MAX) || (l > UCHAR_MAX)) {
+ printf("param %s is out of bounds\n",argv[2]);
+ return -17; /*ERR_BAD_PARAM*/
+ }
+ uid = (uint8_t)l;
+ rc = ipmi_sunoem_sshkey_set(intf, uid, argv[3]);
+ }
+ }
+
+ return rc;
+}
+
+int decode_sensor_sun(uchar *sdr,uchar *reading,char *pstring, int slen)
+{
+ int rv = -1;
+ uchar stype;
+ char *pstr = NULL;
+
+ if (sdr == NULL || reading == NULL) return(rv);
+ if (pstring == NULL || slen == 0) return(rv);
+ /* sdr[3] is the SDR type: 02=Compact, 01=Full) */
+ /* Usually compact sensors here, but type 0xC0 is a full sensor */
+ stype = sdr[12];
+ switch(stype) {
+ case 0x15: /* Module/Board State sensor (e.g. BL0/STATE) */
+ if ((reading[1] + reading[2]) == 0) pstr = "NotAvailable";
+ else if (reading[2] & 0x01) pstr = "OK"; /*deasserted/OK*/
+ else pstr = "Asserted"; /*Asserted, error*/
+ rv = 0;
+ break;
+ case 0xC0: /* Blade Error sensor (e.g. BL0/ERR, a Full SDR) */
+ if ((reading[1] + reading[2]) == 0) pstr = "NotAvailable";
+ else if (reading[2] & 0x01) pstr = "OK"; /*deasserted/OK*/
+ else pstr = "Asserted"; /*Asserted, error*/
+ rv = 0;
+ break;
+ default:
+ break;
+ }
+ if (rv == 0) strncpy(pstring, pstr, slen);
+ return(rv);
+}
+
+#ifdef METACOMMAND
+int i_sunoem(int argc, char **argv)
+#else
+#ifdef WIN32
+int __cdecl
+#else
+int
+#endif
+main(int argc, char **argv)
+#endif
+{
+ void *intf = NULL;
+ int rc = 0;
+ int c, i;
+ char *s1;
+ uchar devrec[16];
+
+ printf("%s ver %s\n", progname,progver);
+ set_loglevel(LOG_NOTICE);
+
+ while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF )
+ switch (c) {
+ case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */
+ g_bus = htoi(&optarg[0]); /*bus/channel*/
+ g_sa = htoi(&optarg[2]); /*device slave address*/
+ g_lun = htoi(&optarg[4]); /*LUN*/
+ g_addrtype = ADDR_IPMB;
+ if (optarg[6] == 's') {
+ g_addrtype = ADDR_SMI; s1 = "SMI";
+ } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; }
+ ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype);
+ printf("Use MC at %s bus=%x sa=%x lun=%x\n",
+ s1,g_bus,g_sa,g_lun);
+ break;
+ case 'x': fdebug = 1; verbose = 1;
+ set_debug();
+ break; /* debug messages */
+ case 'N': /* nodename */
+ case 'U': /* remote username */
+ case 'P': /* remote password */
+ case 'R': /* remote password */
+ case 'E': /* get password from IPMI_PASSWORD environment var */
+ case 'F': /* force driver type */
+ case 'T': /* auth type */
+ case 'J': /* cipher suite */
+ case 'V': /* priv level */
+ case 'Y': /* prompt for remote password */
+ case 'Z': /* set local MC address */
+ parse_lan_options(c,optarg,fdebug);
+ break;
+ case '?':
+ ipmi_sunoem_usage();
+ return 0;
+ break;
+ }
+ for (i = 0; i < optind; i++) { argv++; argc--; }
+
+ rc = ipmi_getdeviceid( devrec, sizeof(devrec),fdebug);
+ if (rc == 0) {
+ char ipmi_maj, ipmi_min;
+ ipmi_maj = devrec[4] & 0x0f;
+ ipmi_min = devrec[4] >> 4;
+ vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16);
+ prod_id = devrec[9] + (devrec[10] << 8);
+ show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min);
+
+ rc = ipmi_sunoem_main(intf, argc, argv);
+ }
+ ipmi_close_();
+ // show_outcome(progname,rc);
+ return rc;
+}