# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../Makefile.lib HDRS= libipmi.h HDRDIR= common # Hammerhead: amd64-only SUBDIRS = $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) install_h: $(ROOTHDRS) check: $(CHECKHDRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include ../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= libipmi.a VERS= .1 OBJECTS= ipmi_bmc.o \ ipmi_entity.o \ ipmi_event.o \ ipmi_fru.o \ ipmi_hash.o \ ipmi_lan.o \ ipmi_lancfg.o \ ipmi_list.o \ ipmi_misc.o \ ipmi_sdr.o \ ipmi_sel.o \ ipmi_sensor.o \ ipmi_sunoem.o \ ipmi_tables.o \ ipmi_user.o \ ipmi_util.o \ libipmi.o include ../../Makefile.lib LIBS= $(DYNLIB) SRCDIR= ../common CLEANFILES += $(SRCDIR)/ipmi_tables.c INCS += -I$(SRCDIR) LDLIBS += -lc -lm -lnvpair -lsocket -lnsl CPPFLAGS += $(INCS) CSTD = $(CSTD_GNU99) CERRWARN += $(CNOWARN_UNINIT) .KEEP_STATE: all: $(LIBS) $(SRCDIR)/ipmi_tables.c: $(SRCDIR)/mktables.sh $(SRCDIR)/libipmi.h $(KSH93) $(SRCDIR)/mktables.sh $(SRCDIR)/libipmi.h > $@ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" include ../Makefile.com include ../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Joyent, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include "ipmi_impl.h" /* * IPMI transport for the local BMC at /dev/ipmi0. */ typedef struct ipmi_bmc { ipmi_handle_t *ib_ihp; /* ipmi handle */ int ib_fd; /* /dev/ipmi0 filedescriptor */ uint32_t ib_msgseq; /* message sequence number */ uint8_t *ib_msg; /* message buffer */ size_t ib_msglen; /* size of message buffer */ } ipmi_bmc_t; #define BMC_DEV "/dev/ipmi0" static void ipmi_bmc_close(void *data) { ipmi_bmc_t *ibp = data; ipmi_free(ibp->ib_ihp, ibp->ib_msg); (void) close(ibp->ib_fd); ipmi_free(ibp->ib_ihp, ibp); } /*ARGSUSED*/ static void * ipmi_bmc_open(ipmi_handle_t *ihp, nvlist_t *params) { ipmi_bmc_t *ibp; if ((ibp = ipmi_zalloc(ihp, sizeof (ipmi_bmc_t))) == NULL) return (NULL); ibp->ib_ihp = ihp; /* open /dev/ipmi0 */ if ((ibp->ib_fd = open(BMC_DEV, O_RDWR)) < 0) { ipmi_free(ihp, ibp); (void) ipmi_set_error(ihp, EIPMI_BMC_OPEN_FAILED, "%s", strerror(errno)); return (NULL); } if ((ibp->ib_msg = (uint8_t *)ipmi_zalloc(ihp, BUFSIZ)) == NULL) { ipmi_bmc_close(ibp); return (NULL); } ibp->ib_msglen = BUFSIZ; return (ibp); } static int ipmi_bmc_send(void *data, ipmi_cmd_t *cmd, ipmi_cmd_t *response, int *completion) { ipmi_bmc_t *ibp = data; struct ipmi_req req; struct ipmi_recv recv; struct ipmi_addr addr; fd_set rset; struct ipmi_system_interface_addr bmc_addr; bmc_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; bmc_addr.channel = IPMI_BMC_CHANNEL; bmc_addr.lun = cmd->ic_lun; (void) memset(&req, 0, sizeof (struct ipmi_req)); req.addr = (unsigned char *) &bmc_addr; req.addr_len = sizeof (bmc_addr); req.msgid = ibp->ib_msgseq++; req.msg.netfn = cmd->ic_netfn; req.msg.cmd = cmd->ic_cmd; req.msg.data = cmd->ic_data; req.msg.data_len = cmd->ic_dlen; if (ioctl(ibp->ib_fd, IPMICTL_SEND_COMMAND, &req) < 0) { (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_PUTMSG, "%s", strerror(errno)); return (-1); } /* get the response from the BMC */ FD_ZERO(&rset); FD_SET(ibp->ib_fd, &rset); if (select(ibp->ib_fd + 1, &rset, NULL, NULL, NULL) < 0) { (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", strerror(errno)); return (-1); } if (FD_ISSET(ibp->ib_fd, &rset) == 0) { (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", "No data available"); return (-1); } recv.addr = (unsigned char *) &addr; recv.addr_len = sizeof (addr); recv.msg.data = (unsigned char *)ibp->ib_msg; recv.msg.data_len = ibp->ib_msglen; /* get data */ if (ioctl(ibp->ib_fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv) < 0) { (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s", strerror(errno)); return (-1); } if (recv.recv_type != IPMI_RESPONSE_RECV_TYPE) { (void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE, "unknown BMC message type %d", recv.recv_type); return (-1); } response->ic_netfn = recv.msg.netfn; /* The lun is not returned in addr, return the lun passed in */ response->ic_lun = cmd->ic_lun; response->ic_cmd = recv.msg.cmd; if (recv.msg.data[0] != 0) { *completion = recv.msg.data[0]; response->ic_dlen = 0; response->ic_data = NULL; } else { *completion = 0; response->ic_dlen = (recv.msg.data_len > 0) ? recv.msg.data_len - 1 : 0; response->ic_data = &(recv.msg.data[1]); } return (0); } ipmi_transport_t ipmi_transport_bmc = { ipmi_bmc_open, ipmi_bmc_close, ipmi_bmc_send }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * IPMI entities are a strange beast. A reasonable assumption for those * unfamiliar with the spec would be that there was a command to iterate over * all entities, and a command to iterate over sensors associated with each * entity. Instead, the entire IPMI world is derived from the SDR repository. * Entities only exist in the sense that they are referenced by a SDR record. * * In addition, entities can be associated into groups, and determining entity * presence is quite complicated. The IPMI spec dedicates an entire chapter * (40) to the process of handling sensor associations. * * The above logic is implemented via the ipmi_entity_present() function. We * make a first pass over the SDR repository to discover entities, creating * entity groups and associating SDR records with the each. * * We don't currently support device-relative entities. */ #include #include #include typedef struct ipmi_entity_sdr { ipmi_list_t ies_list; const char *ies_name; ipmi_sdr_t *ies_sdr; } ipmi_entity_sdr_t; typedef struct ipmi_entity_impl { ipmi_list_t ie_list; ipmi_entity_t ie_entity; struct ipmi_entity_impl *ie_parent; ipmi_hash_link_t ie_link; ipmi_list_t ie_child_list; ipmi_list_t ie_sdr_list; } ipmi_entity_impl_t; #define ENTITY_TO_IMPL(ep) \ ((ipmi_entity_impl_t *)((char *)(ep) - \ offsetof(ipmi_entity_impl_t, ie_entity))) static int ipmi_entity_add_assoc(ipmi_handle_t *ihp, ipmi_entity_impl_t *eip, uint8_t id, uint8_t instance) { ipmi_entity_impl_t *cp; ipmi_entity_t search; search.ie_type = id; search.ie_instance = instance; if ((cp = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) { if ((cp = ipmi_zalloc(ihp, sizeof (ipmi_entity_impl_t))) == NULL) return (-1); cp->ie_entity.ie_type = id; cp->ie_entity.ie_instance = instance; ipmi_hash_insert(ihp->ih_entities, cp); } if (cp->ie_parent != NULL) { /* * This should never happen. However, we want to be tolerant of * pathologically broken IPMI implementations, so we ignore this * error, and the first parent wins. */ return (0); } cp->ie_parent = eip; ipmi_list_append(&eip->ie_child_list, cp); eip->ie_entity.ie_children++; return (0); } static int ipmi_entity_sdr_parse(ipmi_sdr_t *sdrp, uint8_t *id, uint8_t *instance, boolean_t *logical) { switch (sdrp->is_type) { case IPMI_SDR_TYPE_FULL_SENSOR: { ipmi_sdr_full_sensor_t *fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record; *id = fsp->is_fs_entity_id; *instance = fsp->is_fs_entity_instance; *logical = fsp->is_fs_entity_logical; break; } case IPMI_SDR_TYPE_COMPACT_SENSOR: { ipmi_sdr_compact_sensor_t *csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record; *id = csp->is_cs_entity_id; *instance = csp->is_cs_entity_instance; *logical = csp->is_cs_entity_logical; break; } case IPMI_SDR_TYPE_EVENT_ONLY: { ipmi_sdr_event_only_t *eop = (ipmi_sdr_event_only_t *)sdrp->is_record; *id = eop->is_eo_entity_id; *instance = eop->is_eo_entity_instance; *logical = eop->is_eo_entity_logical; break; } case IPMI_SDR_TYPE_ENTITY_ASSOCIATION: { ipmi_sdr_entity_association_t *eap = (ipmi_sdr_entity_association_t *)sdrp->is_record; *id = eap->is_ea_entity_id; *instance = eap->is_ea_entity_instance; *logical = B_TRUE; break; } case IPMI_SDR_TYPE_GENERIC_LOCATOR: { ipmi_sdr_generic_locator_t *glp = (ipmi_sdr_generic_locator_t *)sdrp->is_record; *id = glp->is_gl_entity; *instance = glp->is_gl_instance; *logical = B_FALSE; break; } case IPMI_SDR_TYPE_FRU_LOCATOR: { ipmi_sdr_fru_locator_t *flp = (ipmi_sdr_fru_locator_t *)sdrp->is_record; *id = flp->is_fl_entity; *instance = flp->is_fl_instance; *logical = B_FALSE; break; } case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR: { ipmi_sdr_management_locator_t *mlp = (ipmi_sdr_management_locator_t *)sdrp->is_record; *id = mlp->is_ml_entity_id; *instance = mlp->is_ml_entity_instance; *logical = B_FALSE; break; } default: return (-1); } return (0); } /* * This function is responsible for gathering all entities, inserting them into * the global hash, and establishing any associations. */ /*ARGSUSED*/ static int ipmi_entity_visit(ipmi_handle_t *ihp, const char *name, ipmi_sdr_t *sdrp, void *unused) { uint8_t id, instance; boolean_t logical; ipmi_entity_t search; ipmi_entity_impl_t *eip; ipmi_entity_sdr_t *esp; if (ipmi_entity_sdr_parse(sdrp, &id, &instance, &logical) != 0) return (0); search.ie_type = id; search.ie_instance = instance; if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) { if ((eip = ipmi_zalloc(ihp, sizeof (ipmi_entity_impl_t))) == NULL) return (-1); eip->ie_entity.ie_type = id; eip->ie_entity.ie_instance = instance; ipmi_hash_insert(ihp->ih_entities, eip); } eip->ie_entity.ie_logical |= logical; if (sdrp->is_type == IPMI_SDR_TYPE_ENTITY_ASSOCIATION) { uint8_t start, end; uint8_t i, type; ipmi_sdr_entity_association_t *eap = (ipmi_sdr_entity_association_t *)sdrp->is_record; if (eap->is_ea_range) { type = eap->is_ea_sub[0].is_ea_sub_id; start = eap->is_ea_sub[0].is_ea_sub_instance; end = eap->is_ea_sub[1].is_ea_sub_instance; if (type != 0) { for (i = start; i <= end; i++) { if (ipmi_entity_add_assoc(ihp, eip, type, i) != 0) return (-1); } } type = eap->is_ea_sub[2].is_ea_sub_id; start = eap->is_ea_sub[2].is_ea_sub_instance; end = eap->is_ea_sub[3].is_ea_sub_instance; if (type != 0) { for (i = start; i <= end; i++) { if (ipmi_entity_add_assoc(ihp, eip, type, i) != 0) return (-1); } } } else { for (i = 0; i < 4; i++) { type = eap->is_ea_sub[i].is_ea_sub_id; instance = eap->is_ea_sub[i].is_ea_sub_instance; if (type == 0) continue; if (ipmi_entity_add_assoc(ihp, eip, type, instance) != 0) return (-1); } } } else { if ((esp = ipmi_zalloc(ihp, sizeof (ipmi_entity_sdr_t))) == NULL) return (-1); esp->ies_sdr = sdrp; esp->ies_name = name; ipmi_list_append(&eip->ie_sdr_list, esp); } return (0); } /* * Given a SDR record, return boolean values indicating whether the sensor * indicates explicit presence. * * XXX this should really share code with entity_present() */ int ipmi_entity_present_sdr(ipmi_handle_t *ihp, ipmi_sdr_t *sdrp, boolean_t *valp) { uint16_t mask; uint8_t number, sensor_type, reading_type; ipmi_sdr_compact_sensor_t *csp; ipmi_sdr_full_sensor_t *fsp; ipmi_sensor_reading_t *srp; switch (sdrp->is_type) { case IPMI_SDR_TYPE_COMPACT_SENSOR: csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record; number = csp->is_cs_number; sensor_type = csp->is_cs_type; reading_type = csp->is_cs_reading_type; break; case IPMI_SDR_TYPE_FULL_SENSOR: fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record; number = fsp->is_fs_number; sensor_type = fsp->is_fs_type; reading_type = fsp->is_fs_reading_type; break; default: *valp = B_FALSE; return (0); } switch (reading_type) { case IPMI_RT_PRESENT: mask = IPMI_SR_PRESENT_ASSERT; break; case IPMI_RT_SPECIFIC: switch (sensor_type) { case IPMI_ST_PROCESSOR: mask = IPMI_EV_PROCESSOR_PRESENT; break; case IPMI_ST_POWER_SUPPLY: mask = IPMI_EV_POWER_SUPPLY_PRESENT; break; case IPMI_ST_MEMORY: mask = IPMI_EV_MEMORY_PRESENT; break; case IPMI_ST_BAY: mask = IPMI_EV_BAY_PRESENT; break; default: *valp = B_FALSE; return (0); } break; default: *valp = B_FALSE; return (0); } /* * If we've reached here, then we have a dedicated sensor that * indicates presence. */ if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) { if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) { *valp = B_FALSE; return (0); } return (-1); } *valp = (srp->isr_state & mask) != 0; return (0); } /* * This function follows the procedure documented in section 40 of the spec. * To quote the conclusion from section 40.2: * * Thus, the steps to detecting an Entity are: * * a) Scan the SDRs for sensors associated with the entity. * * b) If there is an active sensor that includes a presence bit, or the * entity has an active Entity Presence sensor, use the sensor to * determine the presence of the entity. * * c) Otherwise, check to see that there is at least one active sensor * associated with the entity. Do this by doing 'Get Sensor Readings' * to the sensors associated with the entity until a scanning sensor is * found. * * d) If there are no active sensors directly associated with the entity, * check the SDRs to see if the entity is a container entity in an * entity-association. If so, check to see if any of the contained * entities are present, if so, assume the container entity exists. * Note that this may need to be iterative, since it's possible to have * multi-level entity associations. * * e) If there are no active sensors for the entity, and the entity is not * the container entity in an active entity-assocation, then the entity * is present if (sic) there there is a FRU device for the entity, and * the FRU device is present. * * It should not be considered an error if a FRU device locator record is * present for a FRU device, but the FRU device is not there. * */ int ipmi_entity_present(ipmi_handle_t *ihp, ipmi_entity_t *ep, boolean_t *valp) { /* LINTED - alignment */ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); ipmi_entity_impl_t *cp; ipmi_entity_sdr_t *esp; ipmi_sdr_t *sdrp; uint16_t mask; uint8_t number, sensor_type, reading_type; ipmi_sensor_reading_t *srp; ipmi_sdr_compact_sensor_t *csp; ipmi_sdr_full_sensor_t *fsp; ipmi_sdr_fru_locator_t *frup; char *frudata; /* * Search the sensors for a present sensor or a discrete sensor that * indicates presence. */ for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL; esp = ipmi_list_next(esp)) { sdrp = esp->ies_sdr; switch (sdrp->is_type) { case IPMI_SDR_TYPE_COMPACT_SENSOR: csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record; number = csp->is_cs_number; sensor_type = csp->is_cs_type; reading_type = csp->is_cs_reading_type; break; case IPMI_SDR_TYPE_FULL_SENSOR: fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record; number = fsp->is_fs_number; sensor_type = fsp->is_fs_type; reading_type = fsp->is_fs_reading_type; break; default: continue; } switch (reading_type) { case IPMI_RT_PRESENT: mask = IPMI_SR_PRESENT_ASSERT; break; case IPMI_RT_SPECIFIC: switch (sensor_type) { case IPMI_ST_PROCESSOR: mask = IPMI_EV_PROCESSOR_PRESENT; break; case IPMI_ST_POWER_SUPPLY: mask = IPMI_EV_POWER_SUPPLY_PRESENT; break; case IPMI_ST_MEMORY: mask = IPMI_EV_MEMORY_PRESENT; break; case IPMI_ST_BAY: mask = IPMI_EV_BAY_PRESENT; break; default: continue; } break; default: continue; } /* * If we've reached here, then we have a dedicated sensor that * indicates presence. */ if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) { if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) { *valp = B_FALSE; return (0); } return (-1); } *valp = (srp->isr_state & mask) != 0; return (0); } /* * No explicit presence sensor was found. See if there is at least one * active sensor associated with the entity. */ for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL; esp = ipmi_list_next(esp)) { sdrp = esp->ies_sdr; switch (sdrp->is_type) { case IPMI_SDR_TYPE_COMPACT_SENSOR: csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record; number = csp->is_cs_number; break; case IPMI_SDR_TYPE_FULL_SENSOR: fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record; number = fsp->is_fs_number; break; default: continue; } if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) { if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) continue; return (-1); } if (srp->isr_scanning_enabled) { *valp = B_TRUE; return (0); } } /* * If this entity has children, then it is present if any of its * children are present. */ for (cp = ipmi_list_next(&eip->ie_child_list); cp != NULL; cp = ipmi_list_next(cp)) { if (ipmi_entity_present(ihp, &cp->ie_entity, valp) != 0) return (-1); if (*valp) return (0); } /* * If the FRU device is present, then the entity is present. */ for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL; esp = ipmi_list_next(esp)) { sdrp = esp->ies_sdr; if (sdrp->is_type != IPMI_SDR_TYPE_FRU_LOCATOR) continue; frup = (ipmi_sdr_fru_locator_t *)sdrp->is_record; if (ipmi_fru_read(ihp, frup, &frudata) >= 0) { ipmi_free(ihp, frudata); *valp = B_TRUE; return (0); } if (ipmi_errno(ihp) != EIPMI_NOT_PRESENT) return (-1); } *valp = B_FALSE; return (0); } static int ipmi_entity_refresh(ipmi_handle_t *ihp) { if (ipmi_hash_first(ihp->ih_entities) != NULL && !ipmi_sdr_changed(ihp)) return (0); if (ipmi_sdr_iter(ihp, ipmi_entity_visit, NULL) != 0) return (-1); return (0); } int ipmi_entity_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *, ipmi_entity_t *, void *), void *data) { ipmi_entity_impl_t *eip; int ret; if (ipmi_entity_refresh(ihp) != 0) return (-1); for (eip = ipmi_hash_first(ihp->ih_entities); eip != NULL; eip = ipmi_hash_next(ihp->ih_entities, eip)) { if (eip->ie_parent != NULL) continue; if ((ret = func(ihp, &eip->ie_entity, data)) != 0) return (ret); } return (0); } int ipmi_entity_iter_sdr(ipmi_handle_t *ihp, ipmi_entity_t *ep, int (*func)(ipmi_handle_t *, ipmi_entity_t *, const char *, ipmi_sdr_t *, void *), void *data) { /* LINTED - alignment */ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); ipmi_entity_sdr_t *isp; int ret; for (isp = ipmi_list_next(&eip->ie_sdr_list); isp != NULL; isp = ipmi_list_next(isp)) { if ((ret = func(ihp, ep, isp->ies_name, isp->ies_sdr, data)) != 0) return (ret); } return (0); } int ipmi_entity_iter_children(ipmi_handle_t *ihp, ipmi_entity_t *ep, int (*func)(ipmi_handle_t *, ipmi_entity_t *, void *), void *data) { /* LINTED - alignment */ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); ipmi_entity_impl_t *cp; int ret; for (cp = ipmi_list_next(&eip->ie_child_list); cp != NULL; cp = ipmi_list_next(cp)) { if ((ret = func(ihp, &cp->ie_entity, data)) != 0) return (ret); } return (0); } ipmi_entity_t * ipmi_entity_parent(ipmi_handle_t *ihp, ipmi_entity_t *ep) { /* LINTED - alignment */ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep); if (eip->ie_parent == NULL) { (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); return (NULL); } return (&eip->ie_parent->ie_entity); } ipmi_entity_t * ipmi_entity_lookup(ipmi_handle_t *ihp, uint8_t type, uint8_t instance) { ipmi_entity_t search; ipmi_entity_impl_t *eip; if (ipmi_entity_refresh(ihp) != 0) return (NULL); search.ie_type = type; search.ie_instance = instance; if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) { (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); return (NULL); } return (&eip->ie_entity); } ipmi_entity_t * ipmi_entity_lookup_sdr(ipmi_handle_t *ihp, const char *name) { ipmi_sdr_t *sdrp; uint8_t id, instance; boolean_t logical; if ((sdrp = ipmi_sdr_lookup(ihp, name)) == NULL) return (NULL); if (ipmi_entity_sdr_parse(sdrp, &id, &instance, &logical) != 0) { (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, "SDR record %s has no associated entity", name); return (NULL); } return (ipmi_entity_lookup(ihp, id, instance)); } static const void * ipmi_entity_hash_convert(const void *p) { const ipmi_entity_impl_t *eip = p; return (&eip->ie_entity); } static ulong_t ipmi_entity_hash_compute(const void *p) { const ipmi_entity_t *ep = p; return ((ep->ie_type << 8) | ep->ie_instance); } static int ipmi_entity_hash_compare(const void *a, const void *b) { const ipmi_entity_t *ea = a; const ipmi_entity_t *eb = b; if (ea->ie_type == eb->ie_type && ea->ie_instance == eb->ie_instance) return (0); else return (-1); } int ipmi_entity_init(ipmi_handle_t *ihp) { if ((ihp->ih_entities = ipmi_hash_create(ihp, offsetof(ipmi_entity_impl_t, ie_link), ipmi_entity_hash_convert, ipmi_entity_hash_compute, ipmi_entity_hash_compare)) == NULL) return (-1); return (0); } void ipmi_entity_clear(ipmi_handle_t *ihp) { ipmi_entity_impl_t *eip; ipmi_entity_sdr_t *esp; while ((eip = ipmi_hash_first(ihp->ih_entities)) != NULL) { while ((esp = ipmi_list_next(&eip->ie_sdr_list)) != NULL) { ipmi_list_delete(&eip->ie_sdr_list, esp); ipmi_free(ihp, esp); } ipmi_hash_remove(ihp->ih_entities, eip); ipmi_free(ihp, eip); } } void ipmi_entity_fini(ipmi_handle_t *ihp) { if (ihp->ih_entities != NULL) { ipmi_entity_clear(ihp); ipmi_hash_destroy(ihp->ih_entities); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include int ipmi_event_platform_message(ipmi_handle_t *ihp, ipmi_platform_event_message_t *pem) { ipmi_cmd_t cmd = { 0 }; cmd.ic_netfn = IPMI_NETFN_SE; cmd.ic_cmd = IPMI_CMD_PLATFORM_EVENT_MESSAGE; cmd.ic_dlen = sizeof (ipmi_platform_event_message_t); cmd.ic_data = pem; if (ipmi_send(ihp, &cmd) == NULL) return (-1); else return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2017, Joyent, Inc. */ #include #include #include "ipmi_impl.h" /* * Extracts bits between index h (high, inclusive) and l (low, exclusive) from * u, which must be an unsigned integer. */ #define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU)) /* * The default and minimum size in bytes that will be used when reading * the FRU inventory area. */ #define DEF_CHUNK_SZ 128 #define MIN_CHUNK_SZ 16 typedef struct ipmi_fru_read { uint8_t ifr_devid; uint8_t ifr_offset_lsb; uint8_t ifr_offset_msb; uint8_t ifr_count; } ipmi_fru_read_t; /* * returns: size of FRU inventory data in bytes, on success * -1, otherwise */ int ipmi_fru_read(ipmi_handle_t *ihp, ipmi_sdr_fru_locator_t *fru_loc, char **buf) { ipmi_cmd_t cmd, *resp; int ierrno; uint8_t count, devid, chunksz; uint16_t sz, offset = 0; ipmi_fru_read_t cmd_data_in; char *tmp; devid = fru_loc->_devid_or_slaveaddr._logical._is_fl_devid; /* * First we issue a command to retrieve the size of the specified FRU's * inventory area */ cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_cmd = IPMI_CMD_GET_FRU_INV_AREA; cmd.ic_data = &devid; cmd.ic_dlen = sizeof (uint8_t); cmd.ic_lun = 0; if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (resp->ic_dlen != 3) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (-1); } (void) memcpy(&sz, resp->ic_data, sizeof (uint16_t)); if ((tmp = malloc(sz)) == NULL) { (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL); return (-1); } chunksz = DEF_CHUNK_SZ; while (offset < sz) { cmd_data_in.ifr_devid = devid; cmd_data_in.ifr_offset_lsb = BITX(offset, 7, 0); cmd_data_in.ifr_offset_msb = BITX(offset, 15, 8); if ((sz - offset) < chunksz) cmd_data_in.ifr_count = sz - offset; else cmd_data_in.ifr_count = chunksz; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_cmd = IPMI_CMD_READ_FRU_DATA; cmd.ic_data = &cmd_data_in; cmd.ic_dlen = sizeof (ipmi_fru_read_t); cmd.ic_lun = 0; /* * The FRU area must be read in chunks as its total size will * be larger than what would fit in a single message. The * maximum size of a message can vary between platforms so * if while attempting to read a chunk we receive an error code * indicating that the requested chunk size is invalid, we will * perform a reverse exponential backoff of the chunk size until * either the read succeeds or we hit bottom, at which point * we'll fail the operation. */ if ((resp = ipmi_send(ihp, &cmd)) == NULL) { ierrno = ipmi_errno(ihp); if (chunksz > MIN_CHUNK_SZ && (ierrno == EIPMI_DATA_LENGTH_EXCEEDED || ierrno == EIPMI_INVALID_REQUEST)) { chunksz = chunksz >> 1; continue; } free(tmp); return (-1); } (void) memcpy(&count, resp->ic_data, sizeof (uint8_t)); if (count != cmd_data_in.ifr_count) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); free(tmp); return (-1); } (void) memcpy(tmp+offset, (char *)(resp->ic_data)+1, count); offset += count; } *buf = tmp; return (sz); } int ipmi_fru_parse_product(ipmi_handle_t *ihp, char *fru_area, ipmi_fru_prod_info_t *buf) { ipmi_fru_hdr_t fru_hdr; char *tmp; uint8_t len, typelen; (void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t)); /* * We get the offset to the product info area from the FRU common * header which is at the start of the FRU inventory area. * * The product info area is optional, so if the offset is NULL, * indicating that it doesn't exist, then we return an error. */ if (!fru_hdr.ifh_product_info_off) { (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); return (-1); } tmp = fru_area + (fru_hdr.ifh_product_info_off * 8) + 3; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_manuf_name); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_product_name); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_part_number); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_product_version); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_product_serial); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_asset_tag); return (0); } /* * The Board Info area is described in Sect 11 of the IPMI Platform Management * FRU Information Storage Definition (v1.1). */ int ipmi_fru_parse_board(ipmi_handle_t *ihp, char *fru_area, ipmi_fru_brd_info_t *buf) { ipmi_fru_hdr_t fru_hdr; char *tmp; uint8_t len, typelen; (void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t)); /* * We get the offset to the board info area from the FRU common * header which is at the start of the FRU inventory area. * * The board info area is optional, so if the offset is NULL, * indicating that it doesn't exist, then we return an error. */ if (!fru_hdr.ifh_board_info_off) { (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); return (-1); } tmp = fru_area + (fru_hdr.ifh_board_info_off * 8) + 3; (void) memcpy(buf->ifbi_manuf_date, tmp, 3); tmp += 3; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_manuf_name); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_board_name); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_product_serial); tmp += len + 1; (void) memcpy(&typelen, tmp, sizeof (uint8_t)); len = BITX(typelen, 5, 0); ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_part_number); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include /* * The (prime) number 137 happens to have the nice property that -- when * multiplied by two and added to 33 -- one gets a pretty long series of * primes: * * 307, 647, 1327, 2687, 5407, 10847, 21727, 43487 * * And beyond 43487, the numbers in the series have few factors or are prime. * That is, one can have a prime number and roughly double it to get another * prime number -- but the series starts at 137. A size of 137 buckets doesn't * particularly accommodate small hash tables, but we note that 13 also yields * a reasonable sequence when doubling it and adding 5: * * 13, 31, 67, 139, 283, 571 * * So we start with this second sequence, crossing over to the first when * the size is greater than 137. (And when reducing the size of the hash * table, we cross back when the size gets below 67.) */ #define IPMI_HASHCROSSOVER 137 #define IPMI_HASHCROSSUNDER 67 #define IPMI_HASHMINSIZE 13 static ulong_t ipmi_hash_double(ulong_t size) { ulong_t nsize; if (size < IPMI_HASHCROSSOVER) { nsize = (size * 2) + 5; return (nsize < IPMI_HASHCROSSOVER ? nsize : IPMI_HASHCROSSOVER); } return ((size * 2) + 33); } static ulong_t ipmi_hash_half(ulong_t size) { ulong_t nsize; if (size > IPMI_HASHCROSSUNDER) { nsize = (size - 33) / 2; return (nsize > IPMI_HASHCROSSUNDER ? nsize : IPMI_HASHCROSSUNDER); } nsize = (size - 5) / 2; return (nsize > IPMI_HASHMINSIZE ? nsize : IPMI_HASHMINSIZE); } ipmi_hash_t * ipmi_hash_create(ipmi_handle_t *hp, size_t linkoffs, const void *(*convert)(const void *elem), ulong_t (*compute)(const void *key), int (*compare)(const void *lkey, const void *rkey)) { ipmi_hash_t *ihp; if ((ihp = ipmi_zalloc(hp, sizeof (ipmi_hash_t))) == NULL) return (NULL); ihp->ih_handle = hp; ihp->ih_nbuckets = IPMI_HASHMINSIZE; ihp->ih_linkoffs = linkoffs; ihp->ih_convert = convert; ihp->ih_compute = compute; ihp->ih_compare = compare; if ((ihp->ih_buckets = ipmi_zalloc(hp, ihp->ih_nbuckets * sizeof (void *))) == NULL) { ipmi_free(hp, ihp); return (NULL); } return (ihp); } void ipmi_hash_destroy(ipmi_hash_t *ihp) { if (ihp != NULL) { ipmi_free(ihp->ih_handle, ihp->ih_buckets); ipmi_free(ihp->ih_handle, ihp); } } ulong_t ipmi_hash_strhash(const void *key) { ulong_t g, h = 0; const char *p; for (p = key; *p != '\0'; p++) { h = (h << 4) + *p; if ((g = (h & 0xf0000000)) != 0) { h ^= (g >> 24); h ^= g; } } return (h); } int ipmi_hash_strcmp(const void *lhs, const void *rhs) { return (strcmp(lhs, rhs)); } ulong_t ipmi_hash_ptrhash(const void *key) { return (*((const uintptr_t *)key) >> 4); } int ipmi_hash_ptrcmp(const void *lhs, const void *rhs) { const uintptr_t *l = lhs, *r = rhs; return (*l == *r ? 0 : -1); } static ulong_t ipmi_hash_compute(ipmi_hash_t *ihp, const void *elem) { return (ihp->ih_compute(ihp->ih_convert(elem)) % ihp->ih_nbuckets); } static void ipmi_hash_resize(ipmi_hash_t *ihp, ulong_t nsize) { size_t osize = ihp->ih_nbuckets; ipmi_handle_t *hp = ihp->ih_handle; ipmi_hash_link_t *link, **nbuckets; ulong_t idx, nidx; assert(nsize >= IPMI_HASHMINSIZE); if (nsize == osize) return; if ((nbuckets = ipmi_zalloc(hp, nsize * sizeof (void *))) == NULL) { /* * This routine can't fail, so we just eat the failure here. * The consequences of this failing are only for performance; * correctness is not affected by our inability to resize * the hash table. */ return; } ihp->ih_nbuckets = nsize; for (idx = 0; idx < osize; idx++) { while ((link = ihp->ih_buckets[idx]) != NULL) { void *elem; /* * For every hash element, we need to remove it from * this bucket, and rehash it given the new bucket * size. */ ihp->ih_buckets[idx] = link->ihl_next; elem = (void *)((uintptr_t)link - ihp->ih_linkoffs); nidx = ipmi_hash_compute(ihp, elem); link->ihl_next = nbuckets[nidx]; nbuckets[nidx] = link; } } ipmi_free(hp, ihp->ih_buckets); ihp->ih_buckets = nbuckets; } void * ipmi_hash_lookup(ipmi_hash_t *ihp, const void *search) { ulong_t idx = ihp->ih_compute(search) % ihp->ih_nbuckets; ipmi_hash_link_t *hl; for (hl = ihp->ih_buckets[idx]; hl != NULL; hl = hl->ihl_next) { void *elem = (void *)((uintptr_t)hl - ihp->ih_linkoffs); if (ihp->ih_compare(ihp->ih_convert(elem), search) == 0) return (elem); } return (NULL); } void * ipmi_hash_first(ipmi_hash_t *ihp) { void *link = ipmi_list_next(&(ihp)->ih_list); if (link == NULL) return (NULL); return ((void *)((uintptr_t)link - ihp->ih_linkoffs)); } void * ipmi_hash_next(ipmi_hash_t *ihp, void *elem) { void *link = ipmi_list_next((uintptr_t)elem + ihp->ih_linkoffs); if (link == NULL) return (NULL); return ((void *)((uintptr_t)link - ihp->ih_linkoffs)); } void ipmi_hash_insert(ipmi_hash_t *ihp, void *elem) { ipmi_hash_link_t *link = (void *)((uintptr_t)elem + ihp->ih_linkoffs); ulong_t idx = ipmi_hash_compute(ihp, elem); assert(ipmi_hash_lookup(ihp, ihp->ih_convert(elem)) == NULL); link->ihl_next = ihp->ih_buckets[idx]; ihp->ih_buckets[idx] = link; ipmi_list_append(&ihp->ih_list, link); if (++ihp->ih_nelements > ihp->ih_nbuckets / 2) ipmi_hash_resize(ihp, ipmi_hash_double(ihp->ih_nbuckets)); } void ipmi_hash_remove(ipmi_hash_t *ihp, void *elem) { ulong_t idx = ipmi_hash_compute(ihp, elem); ipmi_hash_link_t *link = (void *)((uintptr_t)elem + ihp->ih_linkoffs); ipmi_hash_link_t **hlp = &ihp->ih_buckets[idx]; for (; *hlp != NULL; hlp = &(*hlp)->ihl_next) { if (*hlp == link) break; } assert(*hlp != NULL); *hlp = (*hlp)->ihl_next; ipmi_list_delete(&ihp->ih_list, link); assert(ihp->ih_nelements > 0); if (--ihp->ih_nelements < ihp->ih_nbuckets / 4) ipmi_hash_resize(ihp, ipmi_hash_half(ihp->ih_nbuckets)); } size_t ipmi_hash_count(ipmi_hash_t *ihp) { return (ihp->ih_nelements); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _IPMI_IMPL_H #define _IPMI_IMPL_H #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct ipmi_list { struct ipmi_list *l_prev; struct ipmi_list *l_next; } ipmi_list_t; typedef struct ipmi_hash_link { ipmi_list_t ihl_list; /* next on list of all elements */ struct ipmi_hash_link *ihl_next; /* next on this bucket */ } ipmi_hash_link_t; typedef struct ipmi_hash { ipmi_handle_t *ih_handle; /* handle to library state */ ipmi_hash_link_t **ih_buckets; /* array of buckets */ size_t ih_nbuckets; /* number of buckets */ size_t ih_nelements; /* number of elements */ ipmi_list_t ih_list; /* list of all elements */ size_t ih_linkoffs; /* offset of ipmi_hash_link in elem */ const void *(*ih_convert)(const void *); /* key conversion function */ ulong_t (*ih_compute)(const void *); /* hash computing function */ int (*ih_compare)(const void *, const void *); /* compare function */ } ipmi_hash_t; typedef struct ipmi_transport { void * (*it_open)(struct ipmi_handle *, nvlist_t *); void (*it_close)(void *); int (*it_send)(void *, struct ipmi_cmd *, struct ipmi_cmd *, int *); } ipmi_transport_t; struct ipmi_handle { ipmi_transport_t *ih_transport; void *ih_tdata; ipmi_cmd_t ih_response; int ih_errno; uint16_t ih_reservation; int ih_retries; ipmi_hash_t *ih_sdr_cache; uint32_t ih_sdr_ts; ipmi_deviceid_t *ih_deviceid; uint32_t ih_deviceid_len; char *ih_firmware_rev; char ih_errmsg[1024]; char ih_errbuf[1024]; ipmi_list_t ih_users; ipmi_hash_t *ih_entities; int ih_completion; }; /* * Error handling */ extern int ipmi_set_error(ipmi_handle_t *, int, const char *, ...); /* * Memory allocation */ extern void *ipmi_alloc(ipmi_handle_t *, size_t); extern void *ipmi_zalloc(ipmi_handle_t *, size_t); extern void ipmi_free(ipmi_handle_t *, void *); extern void *impi_realloc(ipmi_handle_t *, void *, size_t); extern char *ipmi_strdup(ipmi_handle_t *, const char *); /* * Supported transports */ extern ipmi_transport_t ipmi_transport_bmc; extern ipmi_transport_t ipmi_transport_lan; /* * Primitives for converting */ typedef struct ipmi_name_trans { int int_value; const char *int_name; } ipmi_name_trans_t; typedef struct ipmi_sensor_trans { uint8_t ist_key; uint8_t ist_value; ipmi_name_trans_t ist_mask[1]; } ipmi_sensor_trans_t; extern ipmi_name_trans_t ipmi_entity_table[]; extern ipmi_name_trans_t ipmi_sensor_type_table[]; extern ipmi_name_trans_t ipmi_reading_type_table[]; extern ipmi_name_trans_t ipmi_errno_table[]; extern ipmi_name_trans_t ipmi_threshold_state_table[]; extern ipmi_name_trans_t ipmi_units_type_table[]; extern ipmi_sensor_trans_t ipmi_reading_state_table[]; extern ipmi_sensor_trans_t ipmi_specific_state_table[]; /* * Miscellaneous routines */ extern int ipmi_sdr_init(ipmi_handle_t *); extern void ipmi_sdr_clear(ipmi_handle_t *); extern void ipmi_sdr_fini(ipmi_handle_t *); extern void ipmi_user_clear(ipmi_handle_t *); extern int ipmi_entity_init(ipmi_handle_t *); extern void ipmi_entity_clear(ipmi_handle_t *); extern void ipmi_entity_fini(ipmi_handle_t *); extern int ipmi_convert_bcd(int); extern void ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf); extern boolean_t ipmi_is_sun_ilom(ipmi_deviceid_t *); /* * List routines */ #define ipmi_list_prev(elem) ((void *)(((ipmi_list_t *)(elem))->l_prev)) #define ipmi_list_next(elem) ((void *)(((ipmi_list_t *)(elem))->l_next)) extern void ipmi_list_append(ipmi_list_t *, void *); extern void ipmi_list_prepend(ipmi_list_t *, void *); extern void ipmi_list_insert_before(ipmi_list_t *, void *, void *); extern void ipmi_list_insert_after(ipmi_list_t *, void *, void *); extern void ipmi_list_delete(ipmi_list_t *, void *); /* * Hash table routines */ extern ipmi_hash_t *ipmi_hash_create(ipmi_handle_t *, size_t, const void *(*convert)(const void *), ulong_t (*compute)(const void *), int (*compare)(const void *, const void *)); extern void ipmi_hash_destroy(ipmi_hash_t *); extern void *ipmi_hash_lookup(ipmi_hash_t *, const void *); extern void ipmi_hash_insert(ipmi_hash_t *, void *); extern void ipmi_hash_remove(ipmi_hash_t *, void *); extern size_t ipmi_hash_count(ipmi_hash_t *); extern ulong_t ipmi_hash_strhash(const void *); extern int ipmi_hash_strcmp(const void *, const void *); extern ulong_t ipmi_hash_ptrhash(const void *); extern int ipmi_hash_ptrcmp(const void *, const void *); extern void *ipmi_hash_first(ipmi_hash_t *); extern void *ipmi_hash_next(ipmi_hash_t *, void *); #ifdef __cplusplus } #endif #endif /* _IPMI_IMPL_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libipmi.h" #include "ipmi_lan.h" #include "ipmi_impl.h" #define DEF_IPMI_LAN_TIMEOUT 3 /* seconds */ #define DEF_IPMI_LAN_NUM_RETRIES 5 #define IPMI_LAN_CHANNEL_E 0x0e typedef struct ipmi_rs { uint8_t ir_data[IPMI_BUF_SIZE]; int ir_dlen; ipmi_msg_hdr_t ir_ihdr; uint8_t ir_ccode; } ipmi_rs_t; static ipmi_rs_t *ipmi_lan_poll_recv(ipmi_handle_t *); typedef struct ipmi_rq_entry { ipmi_list_t ire_list; ipmi_cmd_t ire_req; uint8_t ire_target_cmd; uint8_t ire_rq_seq; uint8_t *ire_msg_data; int ire_msg_len; } ipmi_rq_entry_t; ipmi_rq_entry_t *ipmi_req_entries = NULL; /* * LAN transport-specific data */ typedef struct ipmi_lan { ipmi_handle_t *il_ihp; char il_host[MAXHOSTNAMELEN + 1]; uint16_t il_port; char il_user[17]; char il_authcode[IPMI_AUTHCODE_BUF_SIZE + 1]; uint8_t il_challenge[16]; uint32_t il_session_id; int il_sd; boolean_t il_send_authcode; boolean_t il_session_active; uint8_t il_authtype; uint8_t il_privlvl; uint8_t il_num_retries; uint32_t il_in_seq; uint32_t il_timeout; struct sockaddr_in il_addr; socklen_t il_addrlen; } ipmi_lan_t; /* * Calculate and returns IPMI checksum * * Checksum algorithm is described in Section 13.8 * * d: buffer to check * s: position in buffer to start checksum from */ static uint8_t ipmi_csum(uint8_t *d, int s) { uint8_t c = 0; for (; s > 0; s--, d++) c += *d; return (-c); } static ipmi_rq_entry_t * ipmi_req_add_entry(ipmi_handle_t *ihp, ipmi_cmd_t *req) { ipmi_rq_entry_t *e; if ((e = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t))) == NULL) return (NULL); (void) memcpy(&e->ire_req, req, sizeof (ipmi_cmd_t)); ipmi_list_append(&ipmi_req_entries->ire_list, e); return (e); } /*ARGSUSED*/ static ipmi_rq_entry_t * ipmi_req_lookup_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd) { ipmi_rq_entry_t *e; for (e = ipmi_list_next(&ipmi_req_entries->ire_list); e != NULL; e = ipmi_list_next(e)) if (e->ire_rq_seq == seq && e->ire_req.ic_cmd == cmd) return (e); return (NULL); } static void ipmi_req_remove_entry(ipmi_handle_t *ihp, uint8_t seq, uint8_t cmd) { ipmi_rq_entry_t *e; e = ipmi_req_lookup_entry(ihp, seq, cmd); if (e) { ipmi_list_delete(&ipmi_req_entries->ire_list, e); ipmi_free(ihp, e->ire_msg_data); ipmi_free(ihp, e); } } static void ipmi_req_clear_entries(ipmi_handle_t *ihp) { ipmi_rq_entry_t *e; while ((e = ipmi_list_next(&ipmi_req_entries->ire_list)) != NULL) { ipmi_list_delete(&ipmi_req_entries->ire_list, e); ipmi_free(ihp, e); } } static int get_random(void *buf, uint_t len) { int fd; assert(buf != NULL && len > 0); if ((fd = open("/dev/urandom", O_RDONLY)) < 0) return (-1); if (read(fd, buf, len) < 0) { (void) close(fd); return (-1); } (void) close(fd); return (0); } static int ipmi_lan_send_packet(ipmi_handle_t *ihp, uint8_t *data, int dlen) { ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; return (send(ilp->il_sd, data, dlen, 0)); } static ipmi_rs_t * ipmi_lan_recv_packet(ipmi_handle_t *ihp) { static ipmi_rs_t rsp; fd_set read_set, err_set; struct timeval tmout; ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; int ret; FD_ZERO(&read_set); FD_SET(ilp->il_sd, &read_set); FD_ZERO(&err_set); FD_SET(ilp->il_sd, &err_set); tmout.tv_sec = ilp->il_timeout; tmout.tv_usec = 0; ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout); if (ret < 0 || FD_ISSET(ilp->il_sd, &err_set) || !FD_ISSET(ilp->il_sd, &read_set)) return (NULL); /* * The first read may return ECONNREFUSED because the rmcp ping * packet--sent to UDP port 623--will be processed by both the * BMC and the OS. * * The problem with this is that the ECONNREFUSED takes * priority over any other received datagram; that means that * the Connection Refused shows up _before_ the response packet, * regardless of the order they were sent out. (unless the * response is read before the connection refused is returned) */ ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0); if (ret < 0) { FD_ZERO(&read_set); FD_SET(ilp->il_sd, &read_set); FD_ZERO(&err_set); FD_SET(ilp->il_sd, &err_set); tmout.tv_sec = ilp->il_timeout; tmout.tv_usec = 0; ret = select(ilp->il_sd + 1, &read_set, NULL, &err_set, &tmout); if (ret < 0) { if (FD_ISSET(ilp->il_sd, &err_set) || !FD_ISSET(ilp->il_sd, &read_set)) return (NULL); ret = recv(ilp->il_sd, &rsp.ir_data, IPMI_BUF_SIZE, 0); if (ret < 0) return (NULL); } } if (ret == 0) return (NULL); rsp.ir_data[ret] = '\0'; rsp.ir_dlen = ret; return (&rsp); } /* * ASF/RMCP Pong Message * * See section 13.2.4 */ struct rmcp_pong { rmcp_hdr_t rp_rmcp; asf_hdr_t rp_asf; uint32_t rp_iana; uint32_t rp_oem; uint8_t rp_sup_entities; uint8_t rp_sup_interact; uint8_t rp_reserved[6]; }; /* * parse response RMCP "pong" packet * * return -1 if ping response not received * returns 0 if IPMI is NOT supported * returns 1 if IPMI is supported */ /*ARGSUSED*/ static int ipmi_handle_pong(ipmi_handle_t *ihp, ipmi_rs_t *rsp) { struct rmcp_pong *pong; if (rsp == NULL) return (-1); /*LINTED: E_BAD_PTR_CAST_ALIGN*/ pong = (struct rmcp_pong *)rsp->ir_data; return ((pong->rp_sup_entities & 0x80) ? 1 : 0); } /* * Build and send RMCP presence ping message */ static int ipmi_lan_ping(ipmi_handle_t *ihp) { rmcp_hdr_t rmcp_ping; asf_hdr_t asf_ping; uint8_t *data; int rv, dlen = sizeof (rmcp_ping) + sizeof (asf_ping); (void) memset(&rmcp_ping, 0, sizeof (rmcp_ping)); rmcp_ping.rh_version = RMCP_VERSION_1; rmcp_ping.rh_msg_class = RMCP_CLASS_ASF; rmcp_ping.rh_seq = 0xff; (void) memset(&asf_ping, 0, sizeof (asf_ping)); asf_ping.ah_iana = htonl(ASF_RMCP_IANA); asf_ping.ah_msg_type = ASF_TYPE_PING; if ((data = ipmi_zalloc(ihp, dlen)) == NULL) return (-1); (void) memcpy(data, &rmcp_ping, sizeof (rmcp_ping)); (void) memcpy(data + sizeof (rmcp_ping), &asf_ping, sizeof (asf_ping)); rv = ipmi_lan_send_packet(ihp, data, dlen); ipmi_free(ihp, data); if (rv < 0) return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL)); if (ipmi_lan_poll_recv(ihp) == NULL) return (ipmi_set_error(ihp, EIPMI_LAN_PING_FAILED, NULL)); return (0); } static ipmi_rs_t * ipmi_lan_poll_recv(ipmi_handle_t *ihp) { rmcp_hdr_t rmcp_rsp; ipmi_rs_t *rsp; ipmi_rq_entry_t *entry; int off = 0, rv; ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; uint8_t rsp_authtype; rsp = ipmi_lan_recv_packet(ihp); while (rsp != NULL) { /* parse response headers */ (void) memcpy(&rmcp_rsp, rsp->ir_data, 4); switch (rmcp_rsp.rh_msg_class) { case RMCP_CLASS_ASF: /* ping response packet */ rv = ipmi_handle_pong(ihp, rsp); return ((rv <= 0) ? NULL : rsp); case RMCP_CLASS_IPMI: /* handled by rest of function */ break; default: /* Invalid RMCP class */ rsp = ipmi_lan_recv_packet(ihp); continue; } off = sizeof (rmcp_hdr_t); rsp_authtype = rsp->ir_data[off]; if (ilp->il_send_authcode && (rsp_authtype || ilp->il_authtype)) off += 26; else off += 10; (void) memcpy(&rsp->ir_ihdr, (void *)(rsp->ir_data + off), sizeof (rsp->ir_ihdr)); rsp->ir_ihdr.imh_seq = rsp->ir_ihdr.imh_seq >> 2; off += sizeof (rsp->ir_ihdr); rsp->ir_ccode = rsp->ir_data[off++]; entry = ipmi_req_lookup_entry(ihp, rsp->ir_ihdr.imh_seq, rsp->ir_ihdr.imh_cmd); if (entry) { ipmi_req_remove_entry(ihp, rsp->ir_ihdr.imh_seq, rsp->ir_ihdr.imh_cmd); } else { rsp = ipmi_lan_recv_packet(ihp); continue; } break; } /* shift response data to start of array */ if (rsp && rsp->ir_dlen > off) { rsp->ir_dlen -= off + 1; (void) memmove(rsp->ir_data, rsp->ir_data + off, rsp->ir_dlen); (void) memset(rsp->ir_data + rsp->ir_dlen, 0, IPMI_BUF_SIZE - rsp->ir_dlen); } return (rsp); } /* * IPMI LAN Request Message Format * * See section 13.8 * * +---------------------+ * | rmcp_hdr_t | 4 bytes * +---------------------+ * | v15_session_hdr_t | 9 bytes * +---------------------+ * | [authcode] | 16 bytes (if AUTHTYPE != none) * +---------------------+ * | msg length | 1 byte * +---------------------+ * | ipmi_msg_hdr_t | 6 bytes * +---------------------+ * | [msg data] | variable * +---------------------+ * | msg data checksum | 1 byte * +---------------------+ */ static ipmi_rq_entry_t * ipmi_lan_build_cmd(ipmi_handle_t *ihp, ipmi_cmd_t *req) { ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; rmcp_hdr_t rmcp_hdr; v15_session_hdr_t session_hdr; ipmi_msg_hdr_t msg_hdr; uint8_t *msg; int cs, tmp, off = 0, len; ipmi_rq_entry_t *entry; static int curr_seq = 0; if (curr_seq >= 64) curr_seq = 0; if ((entry = ipmi_req_add_entry(ihp, req)) == NULL) return (NULL); len = req->ic_dlen + 29; if (ilp->il_send_authcode && ilp->il_authtype) len += 16; if ((msg = ipmi_zalloc(ihp, len)) == NULL) /* ipmi_errno set */ return (NULL); /* RMCP header */ (void) memset(&rmcp_hdr, 0, sizeof (rmcp_hdr)); rmcp_hdr.rh_version = RMCP_VERSION_1; rmcp_hdr.rh_msg_class = RMCP_CLASS_IPMI; rmcp_hdr.rh_seq = 0xff; (void) memcpy(msg, &rmcp_hdr, sizeof (rmcp_hdr)); off = sizeof (rmcp_hdr); /* IPMI session header */ (void) memset(&session_hdr, 0, sizeof (session_hdr)); if (! ilp->il_send_authcode) session_hdr.sh_authtype = 0x00; else /* hardcode passwd authentication */ session_hdr.sh_authtype = 0x04; (void) memcpy(&session_hdr.sh_seq, &ilp->il_in_seq, sizeof (uint32_t)); (void) memcpy(&session_hdr.sh_id, &ilp->il_session_id, sizeof (uint32_t)); (void) memcpy(msg + off, &session_hdr, sizeof (session_hdr)); off += sizeof (session_hdr); /* IPMI session authcode */ if (ilp->il_send_authcode && ilp->il_authtype) { (void) memcpy(msg + off, ilp->il_authcode, 16); off += 16; } /* message length */ msg[off++] = req->ic_dlen + 7; cs = off; /* IPMI message header */ (void) memset(&msg_hdr, 0, sizeof (msg_hdr)); msg_hdr.imh_addr1 = IPMI_BMC_SLAVE_ADDR; msg_hdr.imh_lun = req->ic_lun; msg_hdr.imh_netfn = req->ic_netfn; tmp = off - cs; msg_hdr.imh_csum = ipmi_csum(msg + cs, tmp); cs = off; msg_hdr.imh_addr2 = IPMI_BMC_SLAVE_ADDR; entry->ire_rq_seq = curr_seq++; msg_hdr.imh_seq = entry->ire_rq_seq << 2; msg_hdr.imh_cmd = req->ic_cmd; (void) memcpy(msg + off, &msg_hdr, sizeof (msg_hdr)); off += sizeof (msg_hdr); /* message data */ if (req->ic_dlen != 0) { (void) memcpy(msg + off, req->ic_data, req->ic_dlen); off += req->ic_dlen; } /* message data checksum */ tmp = off - cs; msg[off++] = ipmi_csum(msg + cs, tmp); if (ilp->il_in_seq) { ilp->il_in_seq++; if (ilp->il_in_seq == 0) ilp->il_in_seq++; } entry->ire_msg_len = off; entry->ire_msg_data = msg; return (entry); } static int ipmi_lan_send(void *data, ipmi_cmd_t *cmd, ipmi_cmd_t *response, int *completion) { ipmi_lan_t *ilp = (ipmi_lan_t *)data; ipmi_rq_entry_t *entry = NULL; ipmi_rs_t *rsp = NULL; uint_t try = 0; for (;;) { if ((entry = ipmi_lan_build_cmd(ilp->il_ihp, cmd)) == NULL) return (-1); if (ipmi_lan_send_packet(ilp->il_ihp, entry->ire_msg_data, entry->ire_msg_len) < 0) { if (++try >= ilp->il_num_retries) return (-1); (void) usleep(5000); continue; } (void) usleep(100); if ((rsp = ipmi_lan_poll_recv(ilp->il_ihp)) != NULL) break; (void) usleep(5000); ipmi_req_remove_entry(ilp->il_ihp, entry->ire_rq_seq, entry->ire_req.ic_cmd); if (++try >= ilp->il_num_retries) return (-1); } response->ic_netfn = rsp->ir_ihdr.imh_netfn; response->ic_lun = rsp->ir_ihdr.imh_lun; response->ic_cmd = rsp->ir_ihdr.imh_cmd; if (rsp->ir_ccode != 0) { *completion = rsp->ir_ccode; response->ic_dlen = 0; response->ic_data = NULL; } else { *completion = 0; response->ic_dlen = rsp->ir_dlen; response->ic_data = rsp->ir_data; } return (0); } /* * IPMI Get Session Challenge Command * * Copies the returned session ID and 16-byte challenge string to the supplied * buffers * * See section 22.16 */ static int ipmi_get_session_challenge_cmd(ipmi_handle_t *ihp, uint32_t *session_id, uint8_t *challenge) { ipmi_cmd_t cmd, resp; ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; char msg_data[17]; int ccode; (void) memset(msg_data, 0, 17); switch (ilp->il_authtype) { case IPMI_SESSION_AUTHTYPE_NONE: msg_data[0] = 0x00; break; case IPMI_SESSION_AUTHTYPE_MD2: msg_data[0] = 0x01; break; case IPMI_SESSION_AUTHTYPE_MD5: msg_data[0] = 0x02; break; case IPMI_SESSION_AUTHTYPE_PASSWORD: msg_data[0] = 0x04; break; case IPMI_SESSION_AUTHTYPE_OEM: msg_data[0] = 0x05; break; } (void) memcpy(msg_data + 1, ilp->il_user, 16); cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_SESSION_CHALLENGE; cmd.ic_data = msg_data; cmd.ic_dlen = 17; if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0 || ccode) return (ipmi_set_error(ihp, EIPMI_LAN_CHALLENGE, NULL)); (void) memcpy(session_id, resp.ic_data, 4); (void) memcpy(challenge, (uint8_t *)resp.ic_data + 4, 16); return (0); } /* * IPMI Activate Session Command * * See section 22.17 */ static int ipmi_activate_session_cmd(ipmi_handle_t *ihp) { ipmi_cmd_t cmd, resp; ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; uint8_t msg_data[22], *resp_data; int ccode; cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_ACTIVATE_SESSION; switch (ilp->il_authtype) { case IPMI_SESSION_AUTHTYPE_NONE: msg_data[0] = 0x00; break; case IPMI_SESSION_AUTHTYPE_MD2: msg_data[0] = 0x01; break; case IPMI_SESSION_AUTHTYPE_MD5: msg_data[0] = 0x02; break; case IPMI_SESSION_AUTHTYPE_PASSWORD: msg_data[0] = 0x04; break; case IPMI_SESSION_AUTHTYPE_OEM: msg_data[0] = 0x05; break; } msg_data[1] = ilp->il_privlvl; (void) memcpy(msg_data + 2, ilp->il_challenge, 16); /* setup initial outbound sequence number */ (void) get_random(msg_data + 18, 4); cmd.ic_data = msg_data; cmd.ic_dlen = 22; ilp->il_send_authcode = B_TRUE; if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0 || ccode) { ilp->il_send_authcode = B_FALSE; return (ipmi_set_error(ihp, EIPMI_LAN_SESSION, NULL)); } resp_data = (uint8_t *)resp.ic_data; (void) memcpy(&ilp->il_session_id, resp_data + 1, 4); ilp->il_in_seq = resp_data[8] << 24 | resp_data[7] << 16 | resp_data[6] << 8 | resp_data[5]; if (ilp->il_in_seq == 0) ++ilp->il_in_seq; return (0); } /* * See section 22.18 * * returns privilege level or -1 on error */ static int ipmi_set_session_privlvl_cmd(ipmi_handle_t *ihp, uint8_t privlvl) { ipmi_cmd_t cmd, resp; int ret = 0, ccode; if (privlvl > IPMI_SESSION_PRIV_OEM) return (ipmi_set_error(ihp, EIPMI_BADPARAM, NULL)); cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_SET_SESSION_PRIVLVL; cmd.ic_data = &privlvl; cmd.ic_dlen = 1; if (ipmi_lan_send(ihp->ih_tdata, &cmd, &resp, &ccode) != 0) ret = ipmi_set_error(ihp, EIPMI_LAN_SETPRIV, NULL); return (ret); } /* * See section 22.19 */ static int ipmi_close_session_cmd(ipmi_handle_t *ihp) { ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; ipmi_cmd_t cmd, resp; uint8_t msg_data[4]; int ret = 0, ccode; if (! ilp->il_session_active) return (-1); (void) memcpy(&msg_data, &ilp->il_session_id, 4); cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_CLOSE_SESSION; cmd.ic_data = msg_data; cmd.ic_dlen = 4; if (ipmi_lan_send(ilp, &cmd, &resp, &ccode) != 0) ret = -1; return (ret); } /* * IPMI LAN Session Activation * * See section 13.14 * * 1. send "RMCP Presence Ping" message, response message will * indicate whether the platform supports IPMI * 2. send "Get Channel Authentication Capabilities" command * with AUTHTYPE = none, response packet will contain information * about supported challenge/response authentication types * 3. send "Get Session Challenge" command with AUTHTYPE = none * and indicate the authentication type in the message, response * packet will contain challenge string and temporary session ID. * 4. send "Activate Session" command, authenticated with AUTHTYPE * sent in previous message. Also sends the initial value for * the outbound sequence number for BMC. * 5. BMC returns response confirming session activation and * session ID for this session and initial inbound sequence. */ static int ipmi_lan_activate_session(ipmi_handle_t *ihp) { ipmi_lan_t *ilp = (ipmi_lan_t *)ihp->ih_tdata; ipmi_channel_auth_caps_t *ac; if (ipmi_lan_ping(ihp) != 0) return (-1); if ((ac = ipmi_get_channel_auth_caps(ihp, IPMI_LAN_CHANNEL_E, ilp->il_privlvl)) == NULL) return (-1); /* * For the sake of simplicity, we're just supporting basic password * authentication. If this authentication type is not supported then * we'll bail here. */ if (!(ac->cap_authtype & IPMI_SESSION_AUTHTYPE_PASSWORD)) { free(ac); return (ipmi_set_error(ihp, EIPMI_LAN_PASSWD_NOTSUP, NULL)); } free(ac); if (ipmi_get_session_challenge_cmd(ihp, &ilp->il_session_id, ilp->il_challenge) != 0) return (-1); if (ipmi_activate_session_cmd(ihp) != 0) return (-1); ilp->il_session_active = B_TRUE; if (ipmi_set_session_privlvl_cmd(ihp, ilp->il_privlvl) != 0) return (-1); return (0); } static void ipmi_lan_close(void *data) { ipmi_lan_t *ilp = (ipmi_lan_t *)data; if (ilp->il_session_active) (void) ipmi_close_session_cmd(ilp->il_ihp); if (ilp->il_sd >= 0) (void) close(ilp->il_sd); ipmi_req_clear_entries(ilp->il_ihp); ipmi_free(ilp->il_ihp, ipmi_req_entries); ipmi_free(ilp->il_ihp, ilp); } static void * ipmi_lan_open(ipmi_handle_t *ihp, nvlist_t *params) { int rc; struct hostent *host; ipmi_lan_t *ilp; char *hostname, *user, *authcode; if ((ilp = ipmi_zalloc(ihp, sizeof (ipmi_lan_t))) == NULL) { /* ipmi errno set */ return (NULL); } ilp->il_ihp = ihp; ihp->ih_tdata = ilp; /* * Parse the parameters passed in the params nvlist. The following * parameters are required * IPMI_LAN_HOST, IPMI_LAN_USER and IPMI_LAN_PASSWD * * If any of these were not specified then we abort */ if (nvlist_lookup_string(params, IPMI_LAN_HOST, &hostname) || nvlist_lookup_string(params, IPMI_LAN_USER, &user) || nvlist_lookup_string(params, IPMI_LAN_PASSWD, &authcode)) { ipmi_free(ihp, ilp); (void) ipmi_set_error(ihp, EIPMI_BADPARAM, NULL); return (NULL); } (void) strncpy(ilp->il_host, hostname, MAXHOSTNAMELEN); (void) strncpy(ilp->il_user, user, 16); (void) strncpy(ilp->il_authcode, authcode, 16); /* * IPMI_LAN_PORT is an optional parameter and defaults to port 623 * IPMI_LAN_PRIVLVL is also optional and defaults to admin * IPMI_LAN_TIMEOUT is optional and will default to 3 seconds * IPMI_LAN_NUM_RETIES is optional and will default to 5 */ if (nvlist_lookup_uint16(params, IPMI_LAN_PORT, &ilp->il_port)) ilp->il_port = RMCP_UDP_PORT; if (nvlist_lookup_uint8(params, IPMI_LAN_PRIVLVL, &ilp->il_privlvl)) ilp->il_privlvl = IPMI_SESSION_PRIV_ADMIN; if (nvlist_lookup_uint32(params, IPMI_LAN_TIMEOUT, &ilp->il_timeout)) ilp->il_timeout = DEF_IPMI_LAN_TIMEOUT; if (nvlist_lookup_uint8(params, IPMI_LAN_NUM_RETRIES, &ilp->il_num_retries)) ilp->il_num_retries = DEF_IPMI_LAN_NUM_RETRIES; ilp->il_authtype = IPMI_SESSION_AUTHTYPE_PASSWORD; /* * Open up and connect a UDP socket between us and the service * processor */ ilp->il_addr.sin_family = AF_INET; ilp->il_addr.sin_port = htons(ilp->il_port); rc = inet_pton(AF_INET, (const char *)ilp->il_host, &ilp->il_addr.sin_addr); if (rc <= 0) { if ((host = gethostbyname((const char *)ilp->il_host)) == NULL) { ipmi_free(ihp, ilp); (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL); return (NULL); } ilp->il_addr.sin_family = host->h_addrtype; (void) memcpy(&ilp->il_addr.sin_addr, host->h_addr, host->h_length); } if ((ilp->il_sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { ipmi_free(ihp, ilp); (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL); return (NULL); } if (connect(ilp->il_sd, (struct sockaddr *)&ilp->il_addr, sizeof (struct sockaddr_in)) < 0) { ipmi_lan_close(ilp); (void) ipmi_set_error(ihp, EIPMI_LAN_OPEN_FAILED, NULL); return (NULL); } if ((ipmi_req_entries = ipmi_zalloc(ihp, sizeof (ipmi_rq_entry_t))) == NULL) return (NULL); /* * Finally we start up the IPMI LAN session */ if ((rc = ipmi_lan_activate_session(ihp)) < 0) { ipmi_lan_close(ilp); return (NULL); } return (ilp); } ipmi_transport_t ipmi_transport_lan = { ipmi_lan_open, ipmi_lan_close, ipmi_lan_send }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef IPMI_LAN_H #define IPMI_LAN_H #ifdef __cplusplus extern "C" { #endif #pragma pack(1) #define IPMI_CMD_GET_SESSION_CHALLENGE 0x39 #define IPMI_CMD_ACTIVATE_SESSION 0x3a #define IPMI_CMD_SET_SESSION_PRIVLVL 0x3b #define IPMI_CMD_CLOSE_SESSION 0x3c #define IPMI_AUTHCODE_BUF_SIZE 20 /* * See section 22.13 */ #define IPMI_SESSION_AUTHTYPE_NONE 0x01 #define IPMI_SESSION_AUTHTYPE_MD2 0x02 #define IPMI_SESSION_AUTHTYPE_MD5 0x04 #define IPMI_SESSION_AUTHTYPE_PASSWORD 0x10 #define IPMI_SESSION_AUTHTYPE_OEM 0x20 #define IPMI_SESSION_PRIV_UNSPECIFIED 0x0 #define IPMI_SESSION_PRIV_CALLBACK 0x1 #define IPMI_SESSION_PRIV_USER 0x2 #define IPMI_SESSION_PRIV_OPERATOR 0x3 #define IPMI_SESSION_PRIV_ADMIN 0x4 #define IPMI_SESSION_PRIV_OEM 0x5 #define IPMI_BMC_SLAVE_ADDR 0x20 #define IPMI_BUF_SIZE 1024 #define IPMI_REMOTE_SWID 0x81 /* * The primary RMCP port */ #define RMCP_UDP_PORT 623 /* * The ASF IANA Enterprise Number */ #define ASF_RMCP_IANA 4542 /* * ASF Message Types for presence ping and pong */ #define ASF_TYPE_PING 0x80 #define ASF_TYPE_PONG 0x40 /* * ASF message header * * See section 13.2.3 */ typedef struct asf_hdr { uint32_t ah_iana; uint8_t ah_msg_type; uint8_t ah_msg_tag; uint8_t __reserved1; uint8_t ah_dlen; } asf_hdr_t; /* * RMCP message header * * See section 13.1.3 */ #define RMCP_VERSION_1 0x06 #define RMCP_CLASS_ASF 0x06 #define RMCP_CLASS_IPMI 0x07 #define RMCP_CLASS_OEM 0x08 typedef struct rmcp_hdr { uint8_t rh_version; uint8_t __reserved1; uint8_t rh_seq; DECL_BITFIELD3( rh_msg_class:5, __reserved2:2, rh_msg_type:1); } rmcp_hdr_t; /* * IPMI Session Header * * The IPMI session header contains some optional payload fields that are only * present in RMCP+ sessions or if the payload type is "OEM explicit". This * structure is only intended to represent the session header for IPMI v1.5 * messages. * * See section 13.6 */ typedef struct v15_session_hdr { uint8_t sh_authtype; uint32_t sh_seq; uint32_t sh_id; } v15_session_hdr_t; /* * IPMI Lan Message Header * * See section 13.8 */ typedef struct ipmi_msg_hdr { uint8_t imh_addr1; DECL_BITFIELD2( imh_lun:2, imh_netfn:6); uint8_t imh_csum; uint8_t imh_addr2; uint8_t imh_seq; uint8_t imh_cmd; } ipmi_msg_hdr_t; #pragma pack() #ifdef __cplusplus } #endif #endif /* IPMI_LAN_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Query and configure LAN interfaces over IPMI. This is done through the * complicated get/set LAN Configuration Parameters command. This queries or * sets the parameters one per command in series. We hide this implementation * detail and instead export a single structure to consumers. */ #include #include #include #include "ipmi_impl.h" typedef struct ipmi_cmd_lan_get_config { DECL_BITFIELD3( ilgc_number :4, __reserved :3, ilgc_revonly :1); uint8_t ilgc_param; uint8_t ilgc_set; uint8_t ilgc_block; } ipmi_cmd_lan_get_config_t; typedef struct ipmi_cmd_lan_set_config { DECL_BITFIELD2( ilsc_number :4, __reserved :4); uint8_t ilsc_param; uint8_t ilsc_data[18]; } ipmi_cmd_lan_set_config_t; #define IPMI_LAN_SET_LEN(dlen) \ (offsetof(ipmi_cmd_lan_set_config_t, ilsc_data) + (dlen)) #define IPMI_LAN_PARAM_SET_IN_PROGRESS 0 #define IPMI_LAN_PARAM_IP_ADDR 3 #define IPMI_LAN_PARAM_IP_SOURCE 4 #define IPMI_LAN_PARAM_MAC_ADDR 5 #define IPMI_LAN_PARAM_SUBNET_MASK 6 #define IPMI_LAN_PARAM_GATEWAY_ADDR 12 #define IPMI_LAN_SET_COMPLETE 0x0 #define IPMI_LAN_SET_INPROGRESS 0x1 #define IPMI_LAN_SET_COMMIT 0x2 typedef struct ipmi_lan_entry { int ile_param; int ile_mask; int ile_set; int ile_block; size_t ile_offset; size_t ile_len; } ipmi_lan_entry_t; static ipmi_lan_entry_t ipmi_lan_table[] = { { IPMI_LAN_PARAM_IP_ADDR, IPMI_LAN_SET_IPADDR, 0, 0, offsetof(ipmi_lan_config_t, ilc_ipaddr), sizeof (uint32_t) }, { IPMI_LAN_PARAM_IP_SOURCE, IPMI_LAN_SET_IPADDR_SOURCE, 0, 0, offsetof(ipmi_lan_config_t, ilc_ipaddr_source), sizeof (uint8_t) }, { IPMI_LAN_PARAM_MAC_ADDR, IPMI_LAN_SET_MACADDR, 0, 0, offsetof(ipmi_lan_config_t, ilc_macaddr), 6 * sizeof (uint8_t) }, { IPMI_LAN_PARAM_SUBNET_MASK, IPMI_LAN_SET_SUBNET, 0, 0, offsetof(ipmi_lan_config_t, ilc_subnet), sizeof (uint32_t) }, { IPMI_LAN_PARAM_GATEWAY_ADDR, IPMI_LAN_SET_GATEWAY_ADDR, 0, 0, offsetof(ipmi_lan_config_t, ilc_gateway_addr), sizeof (uint32_t) } }; #define IPMI_LAN_NENTRIES \ (sizeof (ipmi_lan_table) / sizeof (ipmi_lan_table[0])) static int ipmi_lan_get_param(ipmi_handle_t *ihp, int channel, int param, int set, int block, void *data, size_t len) { ipmi_cmd_t cmd, *rsp; ipmi_cmd_lan_get_config_t lcmd = { 0 }; lcmd.ilgc_number = channel; lcmd.ilgc_param = param; lcmd.ilgc_set = set; lcmd.ilgc_block = block; cmd.ic_netfn = IPMI_NETFN_TRANSPORT; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_LAN_CONFIG; cmd.ic_data = &lcmd; cmd.ic_dlen = sizeof (lcmd); if ((rsp = ipmi_send(ihp, &cmd)) == NULL) { switch (ihp->ih_completion) { case 0x80: (void) ipmi_set_error(ihp, EIPMI_BADPARAM, NULL); break; } return (-1); } if (rsp->ic_dlen < len + 1) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); bcopy((uint8_t *)rsp->ic_data + 1, data, len); return (0); } int ipmi_lan_get_config(ipmi_handle_t *ihp, int channel, ipmi_lan_config_t *cfgp) { uint8_t set; int i; ipmi_lan_entry_t *lep; if (ipmi_lan_get_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, 0, 0, &set, sizeof (set)) != 0) return (-1); if (set & IPMI_LAN_SET_INPROGRESS) cfgp->ilc_set_in_progress = B_TRUE; else cfgp->ilc_set_in_progress = B_FALSE; for (i = 0; i < IPMI_LAN_NENTRIES; i++) { lep = &ipmi_lan_table[i]; if (ipmi_lan_get_param(ihp, channel, lep->ile_param, lep->ile_set, lep->ile_block, (char *)cfgp + lep->ile_offset, lep->ile_len) != 0) return (-1); } return (0); } static int ipmi_lan_set_param(ipmi_handle_t *ihp, int channel, int param, void *data, size_t len) { ipmi_cmd_t cmd; ipmi_cmd_lan_set_config_t lcmd = { 0 }; lcmd.ilsc_number = channel; lcmd.ilsc_param = param; bcopy(data, lcmd.ilsc_data, len); cmd.ic_netfn = IPMI_NETFN_TRANSPORT; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_SET_LAN_CONFIG; cmd.ic_data = &lcmd; cmd.ic_dlen = IPMI_LAN_SET_LEN(len); if (ipmi_send(ihp, &cmd) == NULL) { switch (ihp->ih_completion) { case 0x80: (void) ipmi_set_error(ihp, EIPMI_BADPARAM, NULL); break; case 0x81: (void) ipmi_set_error(ihp, EIPMI_BUSY, NULL); break; case 0x82: (void) ipmi_set_error(ihp, EIPMI_READONLY, NULL); break; case 0x83: (void) ipmi_set_error(ihp, EIPMI_WRITEONLY, NULL); break; } return (-1); } return (0); } int ipmi_lan_set_config(ipmi_handle_t *ihp, int channel, ipmi_lan_config_t *cfgp, int mask) { uint8_t set; int i; ipmi_lan_entry_t *lep; /* * Cancel any pending transaction, then open a new transaction. */ set = IPMI_LAN_SET_COMPLETE; if (ipmi_lan_set_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, &set, sizeof (set)) != 0) return (-1); set = IPMI_LAN_SET_INPROGRESS; if (ipmi_lan_set_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, &set, sizeof (set)) != 0) return (-1); /* * Iterate over all parameters and set them. */ for (i = 0; i < IPMI_LAN_NENTRIES; i++) { lep = &ipmi_lan_table[i]; if (!(lep->ile_mask & mask)) continue; if (ipmi_lan_set_param(ihp, channel, lep->ile_param, (char *)cfgp + lep->ile_offset, lep->ile_len) != 0) { /* * On some systems, setting the mode to DHCP may cause * the command to timeout, presumably because it is * waiting for the setting to take effect. If we see * completion code 0xc3 (command timeout) while setting * the DHCP value, just ignore it. */ if (mask != IPMI_LAN_SET_IPADDR_SOURCE || cfgp->ilc_ipaddr_source != IPMI_LAN_SRC_DHCP || ihp->ih_completion != 0xC3) return (-1); } } /* * Commit the transaction. */ set = IPMI_LAN_SET_COMPLETE; if (ipmi_lan_set_param(ihp, channel, IPMI_LAN_PARAM_SET_IN_PROGRESS, &set, sizeof (set)) != 0) return (-1); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Embedded Linked Lists * * Simple doubly-linked list implementation. This implementation assumes that * each list element contains an embedded ipmi_list_t (previous and next * pointers), which is typically the first member of the element struct. * An additional ipmi_list_t is used to store the head (l_next) and tail * (l_prev) pointers. The current head and tail list elements have their * previous and next pointers set to NULL, respectively. */ #include #include void ipmi_list_append(ipmi_list_t *lp, void *new) { ipmi_list_t *p = lp->l_prev; /* p = tail list element */ ipmi_list_t *q = new; /* q = new list element */ lp->l_prev = q; q->l_prev = p; q->l_next = NULL; if (p != NULL) { assert(p->l_next == NULL); p->l_next = q; } else { assert(lp->l_next == NULL); lp->l_next = q; } } void ipmi_list_prepend(ipmi_list_t *lp, void *new) { ipmi_list_t *p = new; /* p = new list element */ ipmi_list_t *q = lp->l_next; /* q = head list element */ lp->l_next = p; p->l_prev = NULL; p->l_next = q; if (q != NULL) { assert(q->l_prev == NULL); q->l_prev = p; } else { assert(lp->l_prev == NULL); lp->l_prev = p; } } void ipmi_list_insert_before(ipmi_list_t *lp, void *before_me, void *new) { ipmi_list_t *p = before_me; ipmi_list_t *q = new; if (p == NULL || p->l_prev == NULL) { ipmi_list_prepend(lp, new); return; } q->l_prev = p->l_prev; q->l_next = p; p->l_prev = q; q->l_prev->l_next = q; } void ipmi_list_insert_after(ipmi_list_t *lp, void *after_me, void *new) { ipmi_list_t *p = after_me; ipmi_list_t *q = new; if (p == NULL || p->l_next == NULL) { ipmi_list_append(lp, new); return; } q->l_next = p->l_next; q->l_prev = p; p->l_next = q; q->l_next->l_prev = q; } void ipmi_list_delete(ipmi_list_t *lp, void *existing) { ipmi_list_t *p = existing; if (p->l_prev != NULL) p->l_prev->l_next = p->l_next; else lp->l_next = p->l_next; if (p->l_next != NULL) p->l_next->l_prev = p->l_prev; else lp->l_prev = p->l_prev; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, Joyent, Inc. */ #include #include #include #include "ipmi_impl.h" ipmi_deviceid_t * ipmi_get_deviceid(ipmi_handle_t *ihp) { ipmi_cmd_t cmd, *resp; uint16_t id_prod; if (ihp->ih_deviceid != NULL) return (ihp->ih_deviceid); cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_DEVICEID; cmd.ic_data = NULL; cmd.ic_dlen = 0; if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); if (resp->ic_dlen < sizeof (ipmi_deviceid_t)) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } /* * The devid response data may include additional data beyond the end of * the normal structure, so we copy the entire response. */ if ((ihp->ih_deviceid = ipmi_alloc(ihp, resp->ic_dlen)) == NULL) return (NULL); (void) memcpy(ihp->ih_deviceid, resp->ic_data, resp->ic_dlen); id_prod = LE_IN16(&ihp->ih_deviceid->id_product); (void) memcpy(&ihp->ih_deviceid->id_product, &id_prod, sizeof (id_prod)); ihp->ih_deviceid_len = resp->ic_dlen; return (ihp->ih_deviceid); } /* * Returns the firmware revision as a string. This does the work of converting * the deviceid data into a human readable string (decoding the BCD values). * It also encodes the fact that Sun ILOM includes the additional micro revision * at the end of the deviceid information. */ const char * ipmi_firmware_version(ipmi_handle_t *ihp) { ipmi_deviceid_t *dp; uint8_t *auxrev; size_t len; char rev[128]; int i; if (ihp->ih_firmware_rev != NULL) return (ihp->ih_firmware_rev); if ((dp = ipmi_get_deviceid(ihp)) == NULL) return (NULL); /* * Start with the major an minor revision numbers */ (void) snprintf(rev, sizeof (rev), "%d.%d", dp->id_firm_major, ipmi_convert_bcd(dp->id_firm_minor)); if (ipmi_is_sun_ilom(dp) && ihp->ih_deviceid_len >= sizeof (ipmi_deviceid_t) + 4) { /* * With Sun ILOM we have the micro revision at the end of the * deviceid. The first two bytes of the aux revision field are * the platform version and release version. */ auxrev = (uint8_t *)dp + sizeof (ipmi_deviceid_t); for (i = 0; i < 2; i++) { if (auxrev[i] == 0) continue; len = strlen(rev); (void) snprintf(rev + len, sizeof (rev) - len, ".%u", auxrev[i]); } } if ((ihp->ih_firmware_rev = ipmi_strdup(ihp, rev)) == NULL) return (NULL); return (ihp->ih_firmware_rev); } /* * IPMI Get Channel Authentication Capabilities Command * See Section 22.13 * * Caller is responsible for free'ing returned ipmi_channel_auth_caps_t */ ipmi_channel_auth_caps_t * ipmi_get_channel_auth_caps(ipmi_handle_t *ihp, uint8_t channel, uint8_t priv) { ipmi_cmd_t cmd, *resp; uint8_t msg_data[2]; ipmi_channel_auth_caps_t *caps; if (channel > 0xF) { (void) ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, NULL); return (NULL); } msg_data[0] = channel; msg_data[1] = priv; cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_cmd = IPMI_CMD_GET_CHANNEL_AUTH_CAPS; cmd.ic_data = msg_data; cmd.ic_dlen = sizeof (msg_data); cmd.ic_lun = 0; if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); if (resp->ic_dlen < sizeof (ipmi_channel_auth_caps_t)) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } if ((caps = ipmi_alloc(ihp, sizeof (ipmi_channel_auth_caps_t))) == NULL) /* ipmi errno set */ return (NULL); (void) memcpy(caps, resp->ic_data, sizeof (ipmi_channel_auth_caps_t)); return (caps); } ipmi_channel_info_t * ipmi_get_channel_info(ipmi_handle_t *ihp, int number) { ipmi_cmd_t cmd, *rsp; uint8_t channel; if (number > 0xF) { (void) ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, NULL); return (NULL); } channel = (uint8_t)number; cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_CHANNEL_INFO; cmd.ic_data = &channel; cmd.ic_dlen = sizeof (channel); if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); if (rsp->ic_dlen < sizeof (ipmi_channel_info_t)) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } return (rsp->ic_data); } /* * IPMI Chassis Identify Command * See Section 28.5 */ int ipmi_chassis_identify(ipmi_handle_t *ihp, boolean_t enable) { ipmi_cmd_t cmd; uint8_t msg_data[2]; if (enable) { msg_data[0] = 0; msg_data[1] = 1; } else { msg_data[0] = 0; msg_data[1] = 0; } cmd.ic_netfn = IPMI_NETFN_CHASSIS; cmd.ic_cmd = IPMI_CMD_CHASSIS_IDENTIFY; cmd.ic_data = msg_data; cmd.ic_dlen = sizeof (msg_data); cmd.ic_lun = 0; if (ipmi_send(ihp, &cmd) == NULL) return (-1); return (0); } /* * caller is responsible for free'ing returned structure */ ipmi_chassis_status_t * ipmi_chassis_status(ipmi_handle_t *ihp) { ipmi_cmd_t cmd, *rsp; ipmi_chassis_status_t *chs; cmd.ic_netfn = IPMI_NETFN_CHASSIS; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_CHASSIS_STATUS; cmd.ic_data = NULL; cmd.ic_dlen = 0; if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); if (rsp->ic_dlen < sizeof (ipmi_chassis_status_t)) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } if ((chs = ipmi_alloc(ihp, sizeof (ipmi_chassis_status_t))) == NULL) { /* ipmi errno set */ return (NULL); } (void) memcpy(chs, rsp->ic_data, sizeof (ipmi_chassis_status_t)); return (chs); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include "ipmi_impl.h" /* * This macros are used by ipmi_sdr_conv_reading. They were taken verbatim from * the source for ipmitool (v1.88) */ #define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & \ (1<<((bits)-1))) | (val)) : (val)) #define __TO_TOL(mtol) (uint16_t)(BSWAP_16(mtol) & 0x3f) #define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | \ ((BSWAP_16(mtol) & 0xc0) << 2)), 10)) #define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & \ 0xff000000) >> 24) | \ ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10)) #define __TO_ACC(bacc) (uint32_t)(((BSWAP_32(bacc) & 0x3f0000) >> 16) | \ ((BSWAP_32(bacc) & 0xf000) >> 6)) #define __TO_ACC_EXP(bacc) (uint32_t)((BSWAP_32(bacc) & 0xc00) >> 10) #define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4),\ 4)) #define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4)) #define SDR_SENSOR_L_LINEAR 0x00 #define SDR_SENSOR_L_LN 0x01 #define SDR_SENSOR_L_LOG10 0x02 #define SDR_SENSOR_L_LOG2 0x03 #define SDR_SENSOR_L_E 0x04 #define SDR_SENSOR_L_EXP10 0x05 #define SDR_SENSOR_L_EXP2 0x06 #define SDR_SENSOR_L_1_X 0x07 #define SDR_SENSOR_L_SQR 0x08 #define SDR_SENSOR_L_CUBE 0x09 #define SDR_SENSOR_L_SQRT 0x0a #define SDR_SENSOR_L_CUBERT 0x0b #define SDR_SENSOR_L_NONLINEAR 0x70 /* * Analog sensor reading data formats * * See Section 43.1 */ #define IPMI_DATA_FMT_UNSIGNED 0 #define IPMI_DATA_FMT_ONESCOMP 1 #define IPMI_DATA_FMT_TWOSCOMP 2 #define IPMI_SDR_HDR_SZ offsetof(ipmi_sdr_t, is_record) typedef struct ipmi_sdr_cache_ent { char *isc_name; uint8_t isc_entity_id; uint8_t isc_entity_inst; struct ipmi_sdr *isc_sdr; ipmi_hash_link_t isc_link; } ipmi_sdr_cache_ent_t; typedef struct ipmi_cmd_get_sdr { uint16_t ic_gs_resid; uint16_t ic_gs_recid; uint8_t ic_gs_offset; uint8_t ic_gs_len; } ipmi_cmd_get_sdr_t; typedef struct ipmi_rsp_get_sdr { uint16_t ir_gs_next; uint8_t ir_gs_record[1]; } ipmi_rsp_get_sdr_t; /* * "Get SDR Repostiory Info" command. */ ipmi_sdr_info_t * ipmi_sdr_get_info(ipmi_handle_t *ihp) { ipmi_cmd_t cmd, *rsp; ipmi_sdr_info_t *sip; uint16_t tmp16; uint32_t tmp32; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_SDR_INFO; cmd.ic_dlen = 0; cmd.ic_data = NULL; if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); sip = rsp->ic_data; tmp16 = LE_IN16(&sip->isi_record_count); (void) memcpy(&sip->isi_record_count, &tmp16, sizeof (tmp16)); tmp16 = LE_IN16(&sip->isi_free_space); (void) memcpy(&sip->isi_free_space, &tmp16, sizeof (tmp16)); tmp32 = LE_IN32(&sip->isi_add_ts); (void) memcpy(&sip->isi_add_ts, &tmp32, sizeof (tmp32)); tmp32 = LE_IN32(&sip->isi_erase_ts); (void) memcpy(&sip->isi_erase_ts, &tmp32, sizeof (tmp32)); return (sip); } /* * Issue the "Reserve SDR Repository" command. */ static int ipmi_sdr_reserve_repository(ipmi_handle_t *ihp) { ipmi_cmd_t cmd, *rsp; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_RESERVE_SDR_REPOSITORY; cmd.ic_dlen = 0; cmd.ic_data = NULL; if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (-1); ihp->ih_reservation = *((uint16_t *)rsp->ic_data); return (0); } /* * Returns B_TRUE if the repository has changed since the cached copy was last * referenced. */ boolean_t ipmi_sdr_changed(ipmi_handle_t *ihp) { ipmi_sdr_info_t *sip; if ((sip = ipmi_sdr_get_info(ihp)) == NULL) return (B_TRUE); return (sip->isi_add_ts > ihp->ih_sdr_ts || sip->isi_erase_ts > ihp->ih_sdr_ts || ipmi_hash_first(ihp->ih_sdr_cache) == NULL); } /* * Refresh the cache of sensor data records. */ int ipmi_sdr_refresh(ipmi_handle_t *ihp) { uint16_t id; ipmi_sdr_t *sdr; ipmi_sdr_cache_ent_t *ent; size_t namelen; uint8_t type, e_id = 0, e_inst = 0; char *name; ipmi_sdr_info_t *sip; uint32_t isi_add_ts, isi_erase_ts; if ((sip = ipmi_sdr_get_info(ihp)) == NULL) return (-1); (void) memcpy(&isi_add_ts, &sip->isi_add_ts, sizeof (uint32_t)); (void) memcpy(&isi_erase_ts, &sip->isi_erase_ts, sizeof (uint32_t)); if (isi_add_ts <= ihp->ih_sdr_ts && isi_erase_ts <= ihp->ih_sdr_ts && ipmi_hash_first(ihp->ih_sdr_cache) != NULL) return (0); ipmi_sdr_clear(ihp); ipmi_entity_clear(ihp); ihp->ih_sdr_ts = MAX(isi_add_ts, isi_erase_ts); /* * Iterate over all existing SDRs and add them to the cache. */ id = IPMI_SDR_FIRST; while (id != IPMI_SDR_LAST) { if ((sdr = ipmi_sdr_get(ihp, id, &id)) == NULL) goto error; /* * Extract the name from the record-specific data. */ switch (sdr->is_type) { case IPMI_SDR_TYPE_GENERIC_LOCATOR: { ipmi_sdr_generic_locator_t *glp = (ipmi_sdr_generic_locator_t *) sdr->is_record; namelen = glp->is_gl_idlen; type = glp->is_gl_idtype; name = glp->is_gl_idstring; e_id = glp->is_gl_entity; e_inst = glp->is_gl_instance; break; } case IPMI_SDR_TYPE_FRU_LOCATOR: { ipmi_sdr_fru_locator_t *flp = (ipmi_sdr_fru_locator_t *) sdr->is_record; namelen = flp->is_fl_idlen; name = flp->is_fl_idstring; type = flp->is_fl_idtype; e_id = flp->is_fl_entity; e_inst = flp->is_fl_instance; break; } case IPMI_SDR_TYPE_COMPACT_SENSOR: { ipmi_sdr_compact_sensor_t *csp = (ipmi_sdr_compact_sensor_t *) sdr->is_record; uint16_t tmp; namelen = csp->is_cs_idlen; type = csp->is_cs_idtype; name = csp->is_cs_idstring; e_id = csp->is_cs_entity_id; e_inst = csp->is_cs_entity_instance; tmp = LE_IN16(&csp->is_cs_assert_mask); (void) memcpy(&csp->is_cs_assert_mask, &tmp, sizeof (tmp)); tmp = LE_IN16(&csp->is_cs_deassert_mask); (void) memcpy(&csp->is_cs_deassert_mask, &tmp, sizeof (tmp)); tmp = LE_IN16(&csp->is_cs_reading_mask); (void) memcpy(&csp->is_cs_reading_mask, &tmp, sizeof (tmp)); break; } case IPMI_SDR_TYPE_FULL_SENSOR: { ipmi_sdr_full_sensor_t *fsp = (ipmi_sdr_full_sensor_t *) sdr->is_record; uint16_t tmp; namelen = fsp->is_fs_idlen; type = fsp->is_fs_idtype; name = fsp->is_fs_idstring; e_id = fsp->is_fs_entity_id; e_inst = fsp->is_fs_entity_instance; tmp = LE_IN16(&fsp->is_fs_assert_mask); (void) memcpy(&fsp->is_fs_assert_mask, &tmp, sizeof (tmp)); tmp = LE_IN16(&fsp->is_fs_deassert_mask); (void) memcpy(&fsp->is_fs_deassert_mask, &tmp, sizeof (tmp)); tmp = LE_IN16(&fsp->is_fs_reading_mask); (void) memcpy(&fsp->is_fs_reading_mask, &tmp, sizeof (tmp)); break; } case IPMI_SDR_TYPE_EVENT_ONLY: { ipmi_sdr_event_only_t *esp = (ipmi_sdr_event_only_t *) sdr->is_record; namelen = esp->is_eo_idlen; type = esp->is_eo_idtype; name = esp->is_eo_idstring; e_id = esp->is_eo_entity_id; e_inst = esp->is_eo_entity_instance; break; } case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR: { ipmi_sdr_management_locator_t *msp = (ipmi_sdr_management_locator_t *) sdr->is_record; namelen = msp->is_ml_idlen; type = msp->is_ml_idtype; name = msp->is_ml_idstring; e_id = msp->is_ml_entity_id; e_inst = msp->is_ml_entity_instance; break; } case IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION: { ipmi_sdr_management_confirmation_t *mcp = (ipmi_sdr_management_confirmation_t *) sdr->is_record; uint16_t tmp; name = NULL; tmp = LE_IN16(&mcp->is_mc_product); (void) memcpy(&mcp->is_mc_product, &tmp, sizeof (tmp)); break; } default: name = NULL; } if ((ent = ipmi_zalloc(ihp, sizeof (ipmi_sdr_cache_ent_t))) == NULL) { free(sdr); goto error; } ent->isc_sdr = sdr; ent->isc_entity_id = e_id; ent->isc_entity_inst = e_inst; if (name != NULL) { if ((ent->isc_name = ipmi_alloc(ihp, namelen + 1)) == NULL) { ipmi_free(ihp, ent->isc_sdr); ipmi_free(ihp, ent); goto error; } ipmi_decode_string(type, namelen, name, ent->isc_name); } /* * This should never happen. It means that the SP has returned * a SDR record twice, with the same name and ID. This has * been observed on service processors that don't correctly * return SDR_LAST during iteration, so assume we've looped in * the SDR and return gracefully. */ if (ipmi_hash_lookup(ihp->ih_sdr_cache, ent) != NULL) { ipmi_free(ihp, ent->isc_sdr); ipmi_free(ihp, ent->isc_name); ipmi_free(ihp, ent); break; } ipmi_hash_insert(ihp->ih_sdr_cache, ent); } return (0); error: ipmi_sdr_clear(ihp); ipmi_entity_clear(ihp); return (-1); } /* * Hash routines. We allow lookup by name, but since not all entries have * names, we fall back to the entry pointer, which is guaranteed to be unique. * The end result is that entities without names cannot be looked up, but will * show up during iteration. */ static const void * ipmi_sdr_hash_convert(const void *p) { return (p); } static ulong_t ipmi_sdr_hash_compute(const void *p) { const ipmi_sdr_cache_ent_t *ep = p; if (ep->isc_name) return (ipmi_hash_strhash(ep->isc_name)); else return (ipmi_hash_ptrhash(ep)); } static int ipmi_sdr_hash_compare(const void *a, const void *b) { const ipmi_sdr_cache_ent_t *ap = a; const ipmi_sdr_cache_ent_t *bp = b; if (ap->isc_name == NULL || bp->isc_name == NULL) return (-1); if (strcmp(ap->isc_name, bp->isc_name) != 0) return (-1); /* * When looking up only by name we return the first matching name. For * a more precise match, callers can optionally specify an IPMI entity * ID and instance that must also match. */ if (ap->isc_entity_id != IPMI_ET_UNSPECIFIED && bp->isc_entity_id != IPMI_ET_UNSPECIFIED) { if (ap->isc_entity_id != bp->isc_entity_id || ap->isc_entity_inst != bp->isc_entity_inst) return (-1); } return (0); } int ipmi_sdr_init(ipmi_handle_t *ihp) { if ((ihp->ih_sdr_cache = ipmi_hash_create(ihp, offsetof(ipmi_sdr_cache_ent_t, isc_link), ipmi_sdr_hash_convert, ipmi_sdr_hash_compute, ipmi_sdr_hash_compare)) == NULL) return (-1); return (0); } void ipmi_sdr_clear(ipmi_handle_t *ihp) { ipmi_sdr_cache_ent_t *ent; while ((ent = ipmi_hash_first(ihp->ih_sdr_cache)) != NULL) { ipmi_hash_remove(ihp->ih_sdr_cache, ent); ipmi_free(ihp, ent->isc_sdr); ipmi_free(ihp, ent->isc_name); ipmi_free(ihp, ent); } } void ipmi_sdr_fini(ipmi_handle_t *ihp) { if (ihp->ih_sdr_cache != NULL) { ipmi_sdr_clear(ihp); ipmi_hash_destroy(ihp->ih_sdr_cache); } } ipmi_sdr_t * ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next) { uint8_t offset = IPMI_SDR_HDR_SZ, count = 0, chunksz = 16, sdr_sz; ipmi_cmd_t cmd, *rsp; ipmi_cmd_get_sdr_t req; ipmi_sdr_t *sdr; int i = 0; char *buf; req.ic_gs_resid = ihp->ih_reservation; req.ic_gs_recid = id; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_SDR; cmd.ic_dlen = sizeof (req); cmd.ic_data = &req; /* * The size of the SDR is contained in the 5th byte of the SDR header, * so we'll read the first 5 bytes to get the size, so we know how big * to make the buffer. */ req.ic_gs_offset = 0; req.ic_gs_len = IPMI_SDR_HDR_SZ; for (i = 0; i < ihp->ih_retries; i++) { if ((rsp = ipmi_send(ihp, &cmd)) != NULL) break; if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION) return (NULL); if (ipmi_sdr_reserve_repository(ihp) != 0) return (NULL); req.ic_gs_resid = ihp->ih_reservation; } if (rsp == NULL) return (NULL); sdr = (ipmi_sdr_t *)((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record; sdr_sz = sdr->is_length; if ((buf = ipmi_zalloc(ihp, sdr_sz + IPMI_SDR_HDR_SZ)) == NULL) { (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL); return (NULL); } (void) memcpy(buf, (void *)sdr, IPMI_SDR_HDR_SZ); /* * Some SDRs can be bigger than the buffer sizes for a given bmc * interface. Therefore we break up the process of reading in an entire * SDR into multiple smaller reads. */ while (count < sdr_sz) { req.ic_gs_offset = offset; if (chunksz > (sdr_sz - count)) chunksz = sdr_sz - count; req.ic_gs_len = chunksz; rsp = ipmi_send(ihp, &cmd); if (rsp != NULL) { count += chunksz; sdr = (ipmi_sdr_t *) ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record; (void) memcpy(buf+offset, (void *)sdr, chunksz); offset += chunksz; i = 0; } else if (ipmi_errno(ihp) == EIPMI_INVALID_RESERVATION) { if (i >= ihp->ih_retries || ipmi_sdr_reserve_repository(ihp) != 0) { free(buf); return (NULL); } req.ic_gs_resid = ihp->ih_reservation; i++; } else { free(buf); return (NULL); } } *next = ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_next; return ((ipmi_sdr_t *)buf); } int ipmi_sdr_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *, const char *, ipmi_sdr_t *, void *), void *data) { ipmi_sdr_cache_ent_t *ent; int ret; if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL && ipmi_sdr_refresh(ihp) != 0) return (-1); for (ent = ipmi_hash_first(ihp->ih_sdr_cache); ent != NULL; ent = ipmi_hash_next(ihp->ih_sdr_cache, ent)) { if ((ret = func(ihp, ent->isc_name, ent->isc_sdr, data)) != 0) return (ret); } return (0); } ipmi_sdr_t * ipmi_sdr_lookup(ipmi_handle_t *ihp, const char *idstr) { return (ipmi_sdr_lookup_precise(ihp, idstr, IPMI_ET_UNSPECIFIED, 0)); } ipmi_sdr_t * ipmi_sdr_lookup_precise(ipmi_handle_t *ihp, const char *idstr, uint8_t e_id, uint8_t e_inst) { ipmi_sdr_cache_ent_t *ent, search; if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL && ipmi_sdr_refresh(ihp) != 0) return (NULL); search.isc_name = (char *)idstr; search.isc_sdr = NULL; search.isc_entity_id = e_id; search.isc_entity_inst = e_inst; if ((ent = ipmi_hash_lookup(ihp->ih_sdr_cache, &search)) == NULL) { (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); return (NULL); } return (ent->isc_sdr); } static void * ipmi_sdr_lookup_common(ipmi_handle_t *ihp, const char *idstr, uint8_t type) { ipmi_sdr_t *sdrp; if ((sdrp = ipmi_sdr_lookup(ihp, idstr)) == NULL) return (NULL); if (sdrp->is_type != type) { (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); return (NULL); } return (sdrp->is_record); } ipmi_sdr_fru_locator_t * ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr) { return (ipmi_sdr_lookup_common(ihp, idstr, IPMI_SDR_TYPE_FRU_LOCATOR)); } ipmi_sdr_generic_locator_t * ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr) { return (ipmi_sdr_lookup_common(ihp, idstr, IPMI_SDR_TYPE_GENERIC_LOCATOR)); } ipmi_sdr_compact_sensor_t * ipmi_sdr_lookup_compact_sensor(ipmi_handle_t *ihp, const char *idstr) { return (ipmi_sdr_lookup_common(ihp, idstr, IPMI_SDR_TYPE_COMPACT_SENSOR)); } ipmi_sdr_full_sensor_t * ipmi_sdr_lookup_full_sensor(ipmi_handle_t *ihp, const char *idstr) { return (ipmi_sdr_lookup_common(ihp, idstr, IPMI_SDR_TYPE_FULL_SENSOR)); } /* * Mostly taken from ipmitool source v1.88 * * This function converts the raw sensor reading returned by * ipmi_get_sensor_reading to a unit-based value of type double. */ int ipmi_sdr_conv_reading(ipmi_sdr_full_sensor_t *sensor, uint8_t val, double *result) { int m, b, k1, k2; m = __TO_M(sensor->is_fs_mtol); b = __TO_B(sensor->is_fs_bacc); k1 = __TO_B_EXP(sensor->is_fs_bacc); k2 = __TO_R_EXP(sensor->is_fs_bacc); switch (sensor->is_fs_analog_fmt) { case IPMI_DATA_FMT_UNSIGNED: *result = (double)(((m * val) + (b * pow(10, k1))) * pow(10, k2)); break; case IPMI_DATA_FMT_ONESCOMP: if (val & 0x80) val++; /* FALLTHRU */ case IPMI_DATA_FMT_TWOSCOMP: *result = (double)(((m * (int8_t)val) + (b * pow(10, k1))) * pow(10, k2)); break; default: /* This sensor does not return a numeric reading */ return (-1); } switch (sensor->is_fs_sensor_linear_type) { case SDR_SENSOR_L_LN: *result = log(*result); break; case SDR_SENSOR_L_LOG10: *result = log10(*result); break; case SDR_SENSOR_L_LOG2: *result = (double)(log(*result) / log(2.0)); break; case SDR_SENSOR_L_E: *result = exp(*result); break; case SDR_SENSOR_L_EXP10: *result = pow(10.0, *result); break; case SDR_SENSOR_L_EXP2: *result = pow(2.0, *result); break; case SDR_SENSOR_L_1_X: *result = pow(*result, -1.0); /* 1/x w/o exception */ break; case SDR_SENSOR_L_SQR: *result = pow(*result, 2.0); break; case SDR_SENSOR_L_CUBE: *result = pow(*result, 3.0); break; case SDR_SENSOR_L_SQRT: *result = sqrt(*result); break; case SDR_SENSOR_L_CUBERT: *result = cbrt(*result); break; case SDR_SENSOR_L_LINEAR: default: break; } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include "ipmi_impl.h" /* * 31.2 Get SEL Info Command. */ ipmi_sel_info_t * ipmi_sel_get_info(ipmi_handle_t *ihp) { ipmi_cmd_t cmd, *rsp; ipmi_sel_info_t *ip; uint16_t tmp16; uint32_t tmp32; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_SEL_INFO; cmd.ic_dlen = 0; cmd.ic_data = NULL; if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); ip = (ipmi_sel_info_t *)rsp->ic_data; tmp16 = LE_IN16(&ip->isel_entries); (void) memcpy(&ip->isel_entries, &tmp16, sizeof (tmp16)); tmp16 = LE_IN16(&ip->isel_free); (void) memcpy(&ip->isel_free, &tmp16, sizeof (tmp16)); tmp32 = LE_IN32(&ip->isel_add_ts); (void) memcpy(&ip->isel_add_ts, &tmp32, sizeof (tmp32)); tmp32 = LE_IN32(&ip->isel_erase_ts); (void) memcpy(&ip->isel_erase_ts, &tmp32, sizeof (tmp32)); return (ip); } typedef struct ipmi_cmd_get_sel_entry { uint16_t ic_sel_ent_resid; uint16_t ic_sel_ent_recid; uint8_t ic_sel_ent_offset; uint8_t ic_sel_ent_bytes; } ipmi_cmd_get_sel_entry_t; ipmi_sel_event_t * ipmi_sel_get_entry(ipmi_handle_t *ihp, uint16_t id) { ipmi_cmd_t cmd, *rsp; ipmi_sel_event_t *evp; ipmi_cmd_get_sel_entry_t data; uint32_t tmp; data.ic_sel_ent_resid = 0; data.ic_sel_ent_recid = LE_16(id); data.ic_sel_ent_offset = 0; data.ic_sel_ent_bytes = 0xFF; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_SEL_ENTRY; cmd.ic_dlen = sizeof (data); cmd.ic_data = &data; if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); if (rsp->ic_dlen < sizeof (ipmi_sel_event_t)) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } evp = (ipmi_sel_event_t *)rsp->ic_data; evp->isel_ev_next = LE_IN16(&evp->isel_ev_next); evp->isel_ev_recid = LE_IN16(&evp->isel_ev_recid); if (evp->isel_ev_rectype == IPMI_SEL_SYSTEM || evp->isel_ev_rectype >= IPMI_SEL_OEM_LO) { tmp = LE_IN32(&evp->isel_ev_ts); (void) memcpy(&evp->isel_ev_ts, &tmp, sizeof (tmp)); } return (evp); } /* * SEL time management. For the purposes of libipmi we assume that the SDR * repository and SEL share the same timebase, even though the spec allows for * separate time sources. Hence no function to set the SDR repository time. */ int ipmi_sel_get_time(ipmi_handle_t *ihp, uint32_t *tp) { ipmi_cmd_t cmd, *rsp; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_SEL_TIME; cmd.ic_dlen = 0; cmd.ic_data = NULL; if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (rsp->ic_dlen < sizeof (uint32_t)) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); *tp = LE_IN32(rsp->ic_data); return (0); } int ipmi_sel_set_time(ipmi_handle_t *ihp, uint32_t t) { ipmi_cmd_t cmd; t = LE_32(t); cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_SET_SEL_TIME; cmd.ic_dlen = sizeof (t); cmd.ic_data = &t; if (ipmi_send(ihp, &cmd) == NULL) return (-1); return (0); } int ipmi_sel_get_utc_offset(ipmi_handle_t *ihp, int *offp) { ipmi_cmd_t cmd, *rsp; int16_t off16; cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_GET_SEL_UTC_OFFSET; cmd.ic_dlen = 0; cmd.ic_data = NULL; if ((rsp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (rsp->ic_dlen < sizeof (uint16_t)) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); off16 = LE_IN16(rsp->ic_data); *offp = off16; return (0); } int ipmi_sel_set_utc_offset(ipmi_handle_t *ihp, int off) { ipmi_cmd_t cmd; int16_t off16 = off; off16 = LE_16(off16); cmd.ic_netfn = IPMI_NETFN_STORAGE; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_SET_SEL_UTC_OFFSET; cmd.ic_dlen = sizeof (off16); cmd.ic_data = &off16; if (ipmi_send(ihp, &cmd) == NULL) return (-1); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include "ipmi_impl.h" ipmi_sensor_reading_t * ipmi_get_sensor_reading(ipmi_handle_t *ihp, uint8_t id) { ipmi_cmd_t cmd, *resp; ipmi_sensor_reading_t *srp; cmd.ic_netfn = IPMI_NETFN_SE; cmd.ic_cmd = IPMI_CMD_GET_SENSOR_READING; cmd.ic_lun = 0; cmd.ic_data = &id; cmd.ic_dlen = sizeof (id); if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); /* * The upper half of the state field is optional, so if it's not * present, then set it to zero. We also need to convert to the * native endianness. */ if (resp->ic_dlen < sizeof (ipmi_sensor_reading_t) - sizeof (uint8_t)) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } srp = resp->ic_data; if (resp->ic_dlen < sizeof (ipmi_sensor_reading_t)) (void) memset((char *)srp + resp->ic_dlen, '\0', sizeof (ipmi_sensor_reading_t) - resp->ic_dlen); srp->isr_state = LE_IN16(&srp->isr_state); return (srp); } int ipmi_set_sensor_reading(ipmi_handle_t *ihp, ipmi_set_sensor_reading_t *req) { ipmi_set_sensor_reading_t realreq; ipmi_cmd_t cmd, *resp; uint16_t tmp; /* * Convert states to little endian. */ (void) memcpy(&realreq, req, sizeof (realreq)); tmp = LE_IN16(&realreq.iss_assert_state); (void) memcpy(&realreq.iss_assert_state, &tmp, sizeof (tmp)); tmp = LE_IN16(&realreq.iss_deassert_state); (void) memcpy(&realreq.iss_deassert_state, &tmp, sizeof (tmp)); cmd.ic_netfn = IPMI_NETFN_SE; cmd.ic_cmd = IPMI_CMD_SET_SENSOR_READING; cmd.ic_lun = 0; cmd.ic_data = &realreq; cmd.ic_dlen = sizeof (realreq); if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (resp->ic_dlen != 0) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); return (0); } int ipmi_get_sensor_thresholds(ipmi_handle_t *ihp, ipmi_sensor_thresholds_t *thresh, uint8_t id) { ipmi_cmd_t cmd, *resp; cmd.ic_netfn = IPMI_NETFN_SE; cmd.ic_cmd = IPMI_CMD_GET_SENSOR_THRESHOLDS; cmd.ic_lun = 0; cmd.ic_data = &id; cmd.ic_dlen = sizeof (id); if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (resp->ic_dlen < sizeof (ipmi_sensor_thresholds_t)) { return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); } (void) memcpy(thresh, resp->ic_data, sizeof (ipmi_sensor_thresholds_t)); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include "ipmi_impl.h" #define IPMI_CMD_SUNOEM_LED_GET 0x21 #define IPMI_CMD_SUNOEM_LED_SET 0x22 typedef struct ipmi_cmd_sunoem_led_set { DECL_BITFIELD2( ic_sls_channel_msb :1, /* device slave address */ ic_sls_slaveaddr :7); /* (from SDR record) */ uint8_t ic_sls_type; /* led type */ DECL_BITFIELD2( __reserved :1, /* device access address */ ic_sls_accessaddr :7); /* (from SDR record */ uint8_t ic_sls_hwinfo; /* OEM hardware info */ uint8_t ic_sls_mode; /* LED mode */ uint8_t ic_sls_eid; /* entity ID */ uint8_t ic_sls_einst; /* entity instance */ uint8_t ic_sls_force; /* force direct access */ uint8_t ic_sls_role; /* BMC authorization */ } ipmi_cmd_sunoem_led_set_t; typedef struct ipmi_cmd_sunoem_led_get { DECL_BITFIELD2( ic_slg_channel_msb :1, /* device slave address */ ic_slg_slaveaddr :7); /* (from SDR record) */ uint8_t ic_slg_type; /* led type */ DECL_BITFIELD2( __reserved :1, /* device access address */ ic_slg_accessaddr :7); /* (from SDR record */ uint8_t ic_slg_hwinfo; /* OEM hardware info */ uint8_t ic_slg_eid; /* entity ID */ uint8_t ic_slg_einst; /* entity instance */ uint8_t ic_slg_force; /* force direct access */ } ipmi_cmd_sunoem_led_get_t; #define IPMI_SUNOEM_LED_TYPE_OK2RM 0 #define IPMI_SUNOEM_LED_TYPE_SERVICE 1 #define IPMI_SUNOEM_LED_TYPE_ACT 2 #define IPMI_SUNOEM_LED_TYPE_LOCATE 3 #define IPMI_SUNOEM_LED_TYPE_ANY 0xFF boolean_t ipmi_is_sun_ilom(ipmi_deviceid_t *dp) { return (ipmi_devid_manufacturer(dp) == IPMI_OEM_SUN && ipmi_devid_product(dp) == IPMI_PROD_SUN_ILOM); } static int check_sunoem(ipmi_handle_t *ihp) { ipmi_deviceid_t *devid; if ((devid = ipmi_get_deviceid(ihp)) == NULL) return (-1); if (!ipmi_is_sun_ilom(devid)) return (ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, NULL)); return (0); } static int ipmi_send_sunoem_led_set(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_set_t *req) { ipmi_cmd_t cmd, *resp; cmd.ic_netfn = IPMI_NETFN_OEM; cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_SET; cmd.ic_lun = 0; cmd.ic_data = req; cmd.ic_dlen = sizeof (*req); if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (resp->ic_dlen != 0) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); return (0); } static int ipmi_send_sunoem_led_get(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_get_t *req, uint8_t *result) { ipmi_cmd_t cmd, *resp; cmd.ic_netfn = IPMI_NETFN_OEM; cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_GET; cmd.ic_lun = 0; cmd.ic_data = req; cmd.ic_dlen = sizeof (*req); if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (resp->ic_dlen != 1) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); *result = *((uint8_t *)resp->ic_data); return (0); } int ipmi_sunoem_led_set(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev, uint8_t mode) { ipmi_cmd_sunoem_led_set_t cmd = { 0 }; if (check_sunoem(ihp) != 0) return (-1); cmd.ic_sls_slaveaddr = dev->is_gl_slaveaddr; cmd.ic_sls_channel_msb = dev->is_gl_channel_msb; cmd.ic_sls_type = dev->is_gl_oem; cmd.ic_sls_accessaddr = dev->is_gl_accessaddr; cmd.ic_sls_hwinfo = dev->is_gl_oem; cmd.ic_sls_mode = mode; cmd.ic_sls_eid = dev->is_gl_entity; cmd.ic_sls_einst = dev->is_gl_instance; return (ipmi_send_sunoem_led_set(ihp, &cmd)); } int ipmi_sunoem_led_get(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev, uint8_t *mode) { ipmi_cmd_sunoem_led_get_t cmd = { 0 }; if (check_sunoem(ihp) != 0) return (-1); cmd.ic_slg_slaveaddr = dev->is_gl_slaveaddr; cmd.ic_slg_channel_msb = dev->is_gl_channel_msb; cmd.ic_slg_type = dev->is_gl_oem; cmd.ic_slg_accessaddr = dev->is_gl_accessaddr; cmd.ic_slg_hwinfo = dev->is_gl_oem; cmd.ic_slg_eid = dev->is_gl_entity; cmd.ic_slg_einst = dev->is_gl_instance; return (ipmi_send_sunoem_led_get(ihp, &cmd, mode)); } int ipmi_sunoem_uptime(ipmi_handle_t *ihp, uint32_t *uptime, uint32_t *gen) { ipmi_cmd_t cmd, *resp; uint8_t unused; if (check_sunoem(ihp) != 0) return (-1); cmd.ic_netfn = IPMI_NETFN_OEM; cmd.ic_lun = 0; cmd.ic_cmd = IPMI_CMD_SUNOEM_UPTIME; cmd.ic_dlen = sizeof (unused); cmd.ic_data = &unused; if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (resp->ic_dlen != 2 * sizeof (uint32_t)) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); if (uptime) *uptime = BE_IN32(&((uint32_t *)resp->ic_data)[0]); if (gen) *gen = BE_IN32(&((uint32_t *)resp->ic_data)[1]); return (0); } int ipmi_sunoem_update_fru(ipmi_handle_t *ihp, ipmi_sunoem_fru_t *req) { ipmi_cmd_t cmd, *resp; if (check_sunoem(ihp) != 0) return (-1); switch (req->isf_type) { case IPMI_SUNOEM_FRU_DIMM: req->isf_datalen = sizeof (req->isf_data.dimm); break; case IPMI_SUNOEM_FRU_CPU: req->isf_datalen = sizeof (req->isf_data.cpu); break; case IPMI_SUNOEM_FRU_BIOS: req->isf_datalen = sizeof (req->isf_data.bios); break; case IPMI_SUNOEM_FRU_DISK: req->isf_datalen = sizeof (req->isf_data.disk); break; } cmd.ic_netfn = IPMI_NETFN_OEM; cmd.ic_cmd = IPMI_CMD_SUNOEM_FRU_UPDATE; cmd.ic_lun = 0; cmd.ic_dlen = offsetof(ipmi_sunoem_fru_t, isf_data) + req->isf_datalen; cmd.ic_data = req; if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (-1); if (resp->ic_dlen != 0) return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL)); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include "ipmi_impl.h" typedef struct ipmi_user_impl { ipmi_list_t iu_list; ipmi_user_t iu_user; } ipmi_user_impl_t; /* * Get User Access. See section 22.27. * * See libipmi.h for a complete description of IPMI reference material. */ typedef struct ipmi_get_user_access_req { DECL_BITFIELD2( igua_channel :4, __reserved1 :4); DECL_BITFIELD2( igua_uid :2, __reserved2 :6); } ipmi_get_user_access_req_t; #define IPMI_CMD_GET_USER_ACCESS 0x44 typedef struct ipmi_get_user_access { DECL_BITFIELD2( igua_max_uid :4, __reserved1 :4); DECL_BITFIELD2( igua_enable_status :4, igua_enabled_uid :4); DECL_BITFIELD2( __reserved2 :4, igua_fixed_uid :4); DECL_BITFIELD5( __reserved3 :1, igua_only_callback :1, igua_link_auth_enable :1, igua_ipmi_msg_enable :1, igua_privilege_level :4); } ipmi_get_user_access_t; #define IPMI_USER_ENABLE_UNSPECIFIED 0x00 #define IPMI_USER_ENABLE_SETPASSWD 0x01 #define IPMI_USER_DISABLE_SETPASSWD 0x02 #define IPMI_USER_CHANNEL_CURRENT 0xe /* * Get User Name. See section 22.29 */ #define IPMI_CMD_GET_USER_NAME 0x46 /* * Set User Password. See section 22.30 */ #define IPMI_CMD_SET_USER_PASSWORD 0x47 typedef struct ipmi_set_user_password { DECL_BITFIELD3( isup_uid :6, __reserved1 :1, isup_len20 :1); DECL_BITFIELD2( isup_op :2, __reserved2 :6); char isup_passwd[20]; } ipmi_set_user_password_t; #define IPMI_PASSWORD_OP_DISABLE 0x0 #define IPMI_PASSWORD_OP_ENABLE 0x1 #define IPMI_PASSWORD_OP_SET 0x2 #define IPMI_PASSWORD_OP_TEST 0x3 static ipmi_get_user_access_t * ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid) { ipmi_cmd_t cmd, *resp; ipmi_get_user_access_req_t req = { 0 }; req.igua_channel = channel; req.igua_uid = uid; cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; cmd.ic_lun = 0; cmd.ic_data = &req; cmd.ic_dlen = sizeof (req); if ((resp = ipmi_send(ihp, &cmd)) == NULL) { /* * If sessions aren't supported on the current channel, some * service processors (notably Sun's ILOM) will return an * invalid request completion code (0xCC). For these SPs, we * translate this to the more appropriate EIPMI_INVALID_COMMAND. */ if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, NULL); return (NULL); } if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } return (resp->ic_data); } static const char * ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid) { ipmi_cmd_t cmd, *resp; cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_cmd = IPMI_CMD_GET_USER_NAME; cmd.ic_lun = 0; cmd.ic_data = &uid; cmd.ic_dlen = sizeof (uid); if ((resp = ipmi_send(ihp, &cmd)) == NULL) return (NULL); if (resp->ic_dlen < 16) { (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); return (NULL); } return (resp->ic_data); } void ipmi_user_clear(ipmi_handle_t *ihp) { ipmi_user_impl_t *uip; while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) { ipmi_list_delete(&ihp->ih_users, uip); ipmi_free(ihp, uip->iu_user.iu_name); ipmi_free(ihp, uip); } } /* * Returns user information in a well-defined structure. */ int ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *), void *data) { ipmi_get_user_access_t *resp; uint8_t i, uid_max; ipmi_user_impl_t *uip; ipmi_user_t *up; const char *name; uint8_t channel; ipmi_deviceid_t *devid; ipmi_user_clear(ihp); channel = IPMI_USER_CHANNEL_CURRENT; /* * Get the number of active users on the system by requesting the first * user ID (1). */ if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) { /* * Some versions of the Sun ILOM have a bug which prevent the * GET USER ACCESS command from succeeding over the default * channel. If this fails and we are on ILOM, then attempt to * use the standard channel (1) instead. */ if ((devid = ipmi_get_deviceid(ihp)) == NULL) return (-1); if (!ipmi_is_sun_ilom(devid)) return (-1); channel = 1; if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) return (-1); } uid_max = resp->igua_max_uid; for (i = 1; i <= uid_max; i++) { if (i != 1 && (resp = ipmi_get_user_access(ihp, channel, i)) == NULL) return (-1); if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL) return (-1); up = &uip->iu_user; up->iu_enabled = resp->igua_enabled_uid; up->iu_uid = i; up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable; up->iu_link_auth_enable = resp->igua_link_auth_enable; up->iu_priv = resp->igua_privilege_level; ipmi_list_append(&ihp->ih_users, uip); /* * If we are requesting a username that doesn't have a * supported username, we may get an INVALID REQUEST response. * If this is the case, then continue as if there is no known * username. */ if ((name = ipmi_get_user_name(ihp, i)) == NULL) { if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) continue; else return (-1); } if (*name == '\0') continue; if ((up->iu_name = ipmi_strdup(ihp, name)) == NULL) return (-1); } for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL; uip = ipmi_list_next(uip)) { if (func(&uip->iu_user, data) != 0) return (-1); } return (0); } typedef struct ipmi_user_cb { const char *uic_name; uint8_t uic_uid; ipmi_user_t *uic_result; } ipmi_user_cb_t; static int ipmi_user_callback(ipmi_user_t *up, void *data) { ipmi_user_cb_t *cbp = data; if (cbp->uic_result != NULL) return (0); if (up->iu_name) { if (strcmp(up->iu_name, cbp->uic_name) == 0) cbp->uic_result = up; } else if (up->iu_uid == cbp->uic_uid) { cbp->uic_result = up; } return (0); } ipmi_user_t * ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name) { ipmi_user_cb_t cb = { 0 }; cb.uic_name = name; cb.uic_result = NULL; if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) return (NULL); if (cb.uic_result == NULL) (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, "no such user"); return (cb.uic_result); } ipmi_user_t * ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid) { ipmi_user_cb_t cb = { 0 }; cb.uic_uid = uid; cb.uic_result = NULL; if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) return (NULL); if (cb.uic_result == NULL) (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, "no such user"); return (cb.uic_result); } int ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd) { ipmi_set_user_password_t req = { 0 }; ipmi_cmd_t cmd; req.isup_uid = uid; req.isup_op = IPMI_PASSWORD_OP_SET; if (strlen(passwd) > 19) return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, "password length must be less than 20 characters")); if (strlen(passwd) > 15) req.isup_len20 = 1; (void) strcpy(req.isup_passwd, passwd); cmd.ic_netfn = IPMI_NETFN_APP; cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD; cmd.ic_lun = 0; cmd.ic_data = &req; if (req.isup_len20) cmd.ic_dlen = sizeof (req); else cmd.ic_dlen = sizeof (req) - 4; if (ipmi_send(ihp, &cmd) == NULL) return (-1); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "ipmi_impl.h" /* * Extracts bits between index h (high, inclusive) and l (low, exclusive) from * u, which must be an unsigned integer. */ #define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU)) /* * Error handling */ int ipmi_set_error(ipmi_handle_t *ihp, int error, const char *fmt, ...) { va_list ap; va_start(ap, fmt); ihp->ih_errno = error; if (fmt == NULL) ihp->ih_errmsg[0] = '\0'; else (void) vsnprintf(ihp->ih_errmsg, sizeof (ihp->ih_errmsg), fmt, ap); va_end(ap); return (-1); } int ipmi_errno(ipmi_handle_t *ihp) { return (ihp->ih_errno); } /* ARGSUSED */ const char * ipmi_errmsg(ipmi_handle_t *ihp) { int i; const char *str; str = NULL; for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) { if (ipmi_errno_table[i].int_value == ihp->ih_errno) { str = ipmi_errno_table[i].int_name; break; } } if (str == NULL && (str = strerror(ihp->ih_errno)) == NULL) str = "unknown failure"; if (ihp->ih_errmsg[0] == '\0') return (str); (void) snprintf(ihp->ih_errbuf, sizeof (ihp->ih_errbuf), "%s: %s", str, ihp->ih_errmsg); return (ihp->ih_errbuf); } /* * Memory allocation */ void * ipmi_alloc(ipmi_handle_t *ihp, size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL); return (ptr); } void * ipmi_zalloc(ipmi_handle_t *ihp, size_t size) { void *ptr; if ((ptr = calloc(size, 1)) == NULL) (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL); return (ptr); } char * ipmi_strdup(ipmi_handle_t *ihp, const char *str) { char *ptr; if ((ptr = strdup(str)) == NULL) (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL); return (ptr); } /* ARGSUSED */ void ipmi_free(ipmi_handle_t *ihp, void *ptr) { free(ptr); } /* * Translation between #defines and strings. */ void ipmi_entity_name(uint8_t id, char *buf, size_t len) { ipmi_name_trans_t *ntp; for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) { if (ntp->int_value == id) { (void) strlcpy(buf, ntp->int_name, len); return; } } (void) snprintf(buf, len, "0x%02x", id); } void ipmi_sensor_type_name(uint8_t type, char *buf, size_t len) { ipmi_name_trans_t *ntp; for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) { if (ntp->int_value == type) { (void) strlcpy(buf, ntp->int_name, len); return; } } (void) snprintf(buf, len, "0x%02x", type); } void ipmi_sensor_units_name(uint8_t type, char *buf, size_t len) { ipmi_name_trans_t *ntp; for (ntp = &ipmi_units_type_table[0]; ntp->int_name != NULL; ntp++) { if (ntp->int_value == type) { (void) strlcpy(buf, ntp->int_name, len); return; } } (void) snprintf(buf, len, "0x%02x", type); } void ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type, char *buf, size_t len) { uint8_t val; ipmi_name_trans_t *ntp; if (reading_type == IPMI_RT_SPECIFIC) { val = sensor_type; ntp = &ipmi_sensor_type_table[0]; } else { val = reading_type; ntp = &ipmi_reading_type_table[0]; } for (; ntp->int_name != NULL; ntp++) { if (ntp->int_value == val) { (void) strlcpy(buf, ntp->int_name, len); return; } } if (reading_type == IPMI_RT_SPECIFIC) (void) snprintf(buf, len, "%02x/%02x", reading_type, sensor_type); else (void) snprintf(buf, len, "%02x", reading_type); } /* * Converts a BCD decimal value to an integer. */ int ipmi_convert_bcd(int value) { int ret = 0; int digit; int i; for (i = 7; i >= 0; i--) { digit = ((value & (0xf << (i * 4))) >> (i * 4)); ret += digit * 10 * i; } return (ret); } /* * See sections 43.15 and 43.16 * * This is a utility function for decoding the strings that are packed into * sensor data records. If the type is 6-bit packed ASCII, then it converts * the string to an 8-bit ASCII string and copies that into the suuplied buffer. * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is. */ void ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf) { int i, j = 0, chunks, leftovers; uint8_t tmp, lo; if (len == 0) { *buf = '\0'; return; } /* * If the type is 8-bit ASCII, we can simply copy the string and return */ if (type == 0x3) { (void) strncpy(buf, data, len); *(buf+len) = '\0'; return; } else if (type == 0x1 || type == 0x0) { /* * Yuck - they either used BCD plus encoding, which we don't * currently handle, or they used an unspecified encoding type. * In these cases we'll set buf to an empty string. We still * need to return the length so that we can get to the next * record. */ *buf = '\0'; return; } /* * Otherwise, it's 6-bit packed ASCII, so we have to convert the * data first */ chunks = len / 3; leftovers = len % 3; /* * First we decode the 6-bit string in chunks of 3 bytes as far as * possible */ for (i = 0; i < chunks; i++) { tmp = BITX(*(data+j), 5, 0); *buf++ = (char)(tmp + 32); lo = BITX(*(data+j++), 7, 6); tmp = BITX(*(data+j), 3, 0); tmp = (tmp << 2) | lo; *buf++ = (char)(tmp + 32); lo = BITX(*(data+j++), 7, 4); tmp = BITX(*(data+j), 1, 0); tmp = (tmp << 4) | lo; *buf++ = (char)(tmp + 32); tmp = BITX(*(data+j++), 7, 2); *buf++ = (char)(tmp + 32); } switch (leftovers) { case 1: tmp = BITX(*(data+j), 5, 0); *buf++ = (char)(tmp + 32); break; case 2: tmp = BITX(*(data+j), 5, 0); *buf++ = (char)(tmp + 32); lo = BITX(*(data+j++), 7, 6); tmp = BITX(*(data+j), 3, 0); tmp = (tmp << 2) | lo; *buf++ = (char)(tmp + 32); break; } *buf = '\0'; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2018, Joyent, Inc. */ #include #include #include "ipmi_impl.h" ipmi_handle_t * ipmi_open(int *errp, char **msg, uint_t xport_type, nvlist_t *params) { ipmi_handle_t *ihp; static char errmsg[48]; if (msg) *msg = NULL; if ((ihp = calloc(1, sizeof (ipmi_handle_t))) == NULL) { *errp = EIPMI_NOMEM; if (msg) *msg = "memory allocation failure"; return (NULL); } switch (xport_type) { case IPMI_TRANSPORT_BMC: ihp->ih_transport = &ipmi_transport_bmc; break; case IPMI_TRANSPORT_LAN: ihp->ih_transport = &ipmi_transport_lan; break; default: *msg = "invalid transport type specified"; return (NULL); } ihp->ih_retries = 3; if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp, params)) == NULL || ipmi_sdr_init(ihp) != 0 || ipmi_entity_init(ihp) != 0) { *errp = ihp->ih_errno; if (msg) { (void) strncpy(errmsg, ipmi_errmsg(ihp), 47); errmsg[47] = '\0'; *msg = errmsg; } ipmi_close(ihp); return (NULL); } return (ihp); } void ipmi_close(ipmi_handle_t *ihp) { if (ihp->ih_transport && ihp->ih_tdata) ihp->ih_transport->it_close(ihp->ih_tdata); ipmi_free(ihp, ihp->ih_deviceid); ipmi_free(ihp, ihp->ih_firmware_rev); ipmi_user_clear(ihp); ipmi_sdr_fini(ihp); ipmi_entity_fini(ihp); free(ihp); } /* * See section 5.2 for a description of the completion codes. */ static struct ipmi_err_conv { int bmc_err; int ipmi_err; } ipmi_errtable[] = { { 0xC0, EIPMI_BUSY }, { 0xC1, EIPMI_INVALID_COMMAND }, { 0xC2, EIPMI_INVALID_COMMAND }, { 0xC3, EIPMI_COMMAND_TIMEOUT }, { 0xC4, EIPMI_NOSPACE }, { 0xC5, EIPMI_INVALID_RESERVATION }, { 0xC6, EIPMI_INVALID_REQUEST }, { 0xC7, EIPMI_INVALID_REQUEST }, { 0xC8, EIPMI_INVALID_REQUEST }, { 0xC9, EIPMI_INVALID_REQUEST }, { 0xCA, EIPMI_DATA_LENGTH_EXCEEDED }, { 0xCB, EIPMI_NOT_PRESENT }, { 0xCC, EIPMI_INVALID_REQUEST }, { 0xCD, EIPMI_INVALID_COMMAND }, { 0xCE, EIPMI_UNAVAILABLE }, { 0xCF, EIPMI_UNAVAILABLE }, { 0xD0, EIPMI_BUSY }, { 0xD1, EIPMI_BUSY }, { 0xD2, EIPMI_BUSY }, { 0xD3, EIPMI_NOT_PRESENT }, { 0xD4, EIPMI_ACCESS }, { 0xD5, EIPMI_UNAVAILABLE }, { 0xD6, EIPMI_UNAVAILABLE }, { 0xFF, EIPMI_UNSPECIFIED }, }; #define IPMI_ERROR_COUNT \ (sizeof (ipmi_errtable) / sizeof (ipmi_errtable[0])) ipmi_cmd_t * ipmi_send(ipmi_handle_t *ihp, ipmi_cmd_t *cmd) { int i; if (ihp->ih_transport->it_send(ihp->ih_tdata, cmd, &ihp->ih_response, &ihp->ih_completion) != 0) return (NULL); if (ihp->ih_completion != 0) { for (i = 0; i < IPMI_ERROR_COUNT; i++) { if (ihp->ih_completion == ipmi_errtable[i].bmc_err) { (void) ipmi_set_error(ihp, ipmi_errtable[i].ipmi_err, "IPMI completion code 0x%x", ihp->ih_completion); return (NULL); } } (void) ipmi_set_error(ihp, EIPMI_UNKNOWN, "IPMI completion code 0x%x", ihp->ih_completion); return (NULL); } return (&ihp->ih_response); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Joyent, Inc. All rights reserved. */ #ifndef _LIBIPMI_H #define _LIBIPMI_H #include #include #include /* * Private interfaces for communicating with attached services over IPMI. This * library is designed for system software communicating with Illumos-supported * service processors over /dev/ipmi0. It is not a generic IPMI library. * * Documentation references refer to "Intelligent Platform Management Interface * Specification Second Generation v2.0", document revision 1.0 with Februrary * 15, 2006 Markup from "IPMI v2.0 Addenda, Errata, and Clarifications Revision * 3". */ #ifdef __cplusplus extern "C" { #endif typedef struct ipmi_handle ipmi_handle_t; #pragma pack(1) /* * Basic netfn definitions. See section 5.1. */ #define IPMI_NETFN_CHASSIS 0x0 #define IPMI_NETFN_BRIDGE 0x2 #define IPMI_NETFN_SE 0x4 #define IPMI_NETFN_APP 0x6 #define IPMI_NETFN_FIRMWARE 0x8 #define IPMI_NETFN_STORAGE 0xa #define IPMI_NETFN_TRANSPORT 0x0C #define IPMI_NETFN_OEM 0x2e /* * Error definitions */ #define EIPMI_BASE 2000 typedef enum { EIPMI_NOMEM = EIPMI_BASE, /* memory allocation failure */ EIPMI_BMC_OPEN_FAILED, /* failed to open /dev/ipmi0 */ EIPMI_BMC_PUTMSG, /* failed to send message to /dev/ipmi0 */ EIPMI_BMC_GETMSG, /* failed to read response from /dev/ipmi0 */ EIPMI_BMC_RESPONSE, /* response from /dev/ipmi0 failed */ EIPMI_INVALID_COMMAND, /* invalid command */ EIPMI_COMMAND_TIMEOUT, /* command timeout */ EIPMI_DATA_LENGTH_EXCEEDED, /* maximum data length exceeded */ EIPMI_SEND_FAILED, /* failed to send BMC request */ EIPMI_UNSPECIFIED, /* unspecified BMC error */ EIPMI_UNKNOWN, /* unknown error */ EIPMI_BAD_RESPONSE, /* received unexpected response */ EIPMI_BAD_RESPONSE_LENGTH, /* unexpected response length */ EIPMI_INVALID_RESERVATION, /* invalid or cancelled reservation */ EIPMI_NOT_PRESENT, /* requested entity not present */ EIPMI_INVALID_REQUEST, /* malformed request data */ EIPMI_BUSY, /* service processor is busy */ EIPMI_NOSPACE, /* service processor is out of space */ EIPMI_UNAVAILABLE, /* service processor is unavailable */ EIPMI_ACCESS, /* insufficient privileges */ EIPMI_BADPARAM, /* parameter is not supported */ EIPMI_READONLY, /* attempt to write read-only param */ EIPMI_WRITEONLY, /* attempt to read write-only param */ EIPMI_LAN_OPEN_FAILED, /* failed to open socket */ EIPMI_LAN_PING_FAILED, /* RMCP Ping message failed */ EIPMI_LAN_PASSWD_NOTSUP, /* password authentication not supported */ EIPMI_LAN_CHALLENGE, /* failure getting challenge */ EIPMI_LAN_SESSION, /* failure activating session */ EIPMI_LAN_SETPRIV /* failure setting session privs */ } ipmi_errno_t; /* * Basic library functions. * * The ipmi_handle is the primary interface to the library. The library itself * is not MT-safe, but it is safe within a single handle. Multithreaded clients * should either open multiple handles, or otherwise synchronize access to the * same handle. * * There is a single command response buffer that is stored with the handle, to * simplify memory management in the caller. The memory referenced by a command * response is only valid until the next command is issued. The caller is * responsible for making a copy of the response if it is needed. */ extern ipmi_handle_t *ipmi_open(int *, char **, uint_t xport_type, nvlist_t *); /* * Constants for nvpair names for the params nvlist that is passed to * ipmi_open(). If the IPMI_TRANSPORT_BMC is desired, then it is sufficient * to just specify NULL for the params nvlist. * * For IPMI_TRANSPORT_LAN, the params nvlist must contain the following * nvpairs: * * IPMI_LAN_HOST, IPMI_LAN_USER, IPMI_LAN_PASSWD * * IPMI_LAN_PORT is optional and will default to 623 * IPMI_LAN_PRIVLVL is optional and will default to admin * IPMI_LAN_TIMEOUT is optional and will default to 3 seconds * IPMI_LAN_NUM_RETIES is optional and will default to 5 */ #define IPMI_TRANSPORT_TYPE "transport-type" #define IPMI_TRANSPORT_BMC 0x01 #define IPMI_TRANSPORT_LAN 0x02 #define IPMI_LAN_HOST "lan-host" #define IPMI_LAN_PORT "lan-port" #define IPMI_LAN_USER "lan-user" #define IPMI_LAN_PASSWD "lan-passwd" #define IPMI_LAN_PRIVLVL "lan-privlvl" #define IPMI_LAN_TIMEOUT "lan-timeout" #define IPMI_LAN_NUM_RETRIES "lan-num-retries" extern void ipmi_close(ipmi_handle_t *); extern int ipmi_errno(ipmi_handle_t *); extern const char *ipmi_errmsg(ipmi_handle_t *); /* * Raw requests. See section 5. */ typedef struct ipmi_cmd { uint8_t ic_netfn:6; uint8_t ic_lun:2; uint8_t ic_cmd; uint16_t ic_dlen; void *ic_data; } ipmi_cmd_t; extern ipmi_cmd_t *ipmi_send(ipmi_handle_t *, ipmi_cmd_t *); /* * Retrieve basic information about the IPMI device. See section 20.1 "Get * Device ID Command". */ #define IPMI_CMD_GET_DEVICEID 0x01 typedef struct ipmi_deviceid { uint8_t id_devid; DECL_BITFIELD3( id_dev_rev :4, __reserved :3, id_dev_sdrs :1); DECL_BITFIELD2( id_firm_major :7, id_dev_available :1); uint8_t id_firm_minor; uint8_t id_ipmi_rev; uint8_t id_dev_support; uint8_t id_manufacturer[3]; uint8_t id_product[2]; } ipmi_deviceid_t; #define IPMI_OEM_SUN 0x2a #define IPMI_PROD_SUN_ILOM 0x4701 ipmi_deviceid_t *ipmi_get_deviceid(ipmi_handle_t *); #define ipmi_devid_manufacturer(dp) \ ((dp)->id_manufacturer[0] | \ ((dp)->id_manufacturer[1] << 8) | \ ((dp)->id_manufacturer[2] << 16)) #define ipmi_devid_product(dp) \ ((dp)->id_product[0] | \ ((dp)->id_product[1] << 8)) const char *ipmi_firmware_version(ipmi_handle_t *); /* * Get Channel Auth Caps. See section 22.13. */ typedef struct ipmi_channel_auth_caps { uint8_t cap_channel; DECL_BITFIELD3( cap_authtype :6, __reserved1 :1, cap_ipmirev2 :1); DECL_BITFIELD5( cap_anon :3, cap_peruser :1, cap_permesg :1, cap_kgstatus :1, __reserved2 :2); uint8_t cap_ext; uint8_t cap_oemid[3]; uint8_t cap_oemaux; } ipmi_channel_auth_caps_t; #define IPMI_CMD_GET_CHANNEL_AUTH_CAPS 0x38 extern ipmi_channel_auth_caps_t *ipmi_get_channel_auth_caps(ipmi_handle_t *, uint8_t, uint8_t); /* * Get Channel Info. See section 22.24. */ typedef struct ipmi_channel_info { DECL_BITFIELD2( ici_number :4, __reserved1 :4); DECL_BITFIELD2( ici_medium :7, __reserved2 :1); DECL_BITFIELD2( ici_protocol :5, __reserved3 :3); DECL_BITFIELD3( ici_session_count :6, ici_single_session :1, ici_multi_Session :1); uint8_t ici_vendor[3]; uint8_t ici_auxinfo[2]; } ipmi_channel_info_t; #define IPMI_CMD_GET_CHANNEL_INFO 0x42 /* * Channel Numbers. See section 6.3. */ #define IPMI_CHANNEL_PRIMARY 0x0 #define IPMI_CHANNEL_MIN 0x1 #define IPMI_CHANNEL_MAX 0xB #define IPMI_CHANNEL_CURRENT 0xE #define IPMI_CHANNEL_SYSTEM 0xF extern ipmi_channel_info_t *ipmi_get_channel_info(ipmi_handle_t *, int); /* * Channel Protocol Types. See section 6.4. */ #define IPMI_PROTOCOL_IPMB 0x1 #define IPMI_PROTOCOL_ICMB 0x2 #define IPMI_PROTOCOL_SMBUS 0x4 #define IPMI_PROTOCOL_KCS 0x5 #define IPMI_PROTOCOL_SMIC 0x6 #define IPMI_PROTOCOL_BT10 0x7 #define IPMI_PROTOCOL_BT15 0x8 #define IPMI_PROTOCOL_TMODE 0x9 #define IPMI_PROTOCOL_OEM1 0xC #define IPMI_PROTOCOL_OEM2 0xD #define IPMI_PROTOCOL_OEM3 0xE #define IPMI_PROTOCOL_OEM4 0xF /* * Channel Medium Types. See section 6.5. */ #define IPMI_MEDIUM_IPMB 0x1 #define IPMI_MEDIUM_ICMB10 0x2 #define IPMI_MEDIUM_ICMB09 0x3 #define IPMI_MEDIUM_8023LAN 0x4 #define IPMI_MEDIUM_RS232 0x5 #define IPMI_MEDIUM_OTHERLAN 0x6 #define IPMI_MEDIUM_PCISMBUS 0x7 #define IPMI_MEDIUM_SMBUS10 0x8 #define IPMI_MEDIUM_SMBUS20 0x9 #define IPMI_MEDIUM_USB1 0xA #define IPMI_MEDIUM_USB2 0xB #define IPMI_MEDIUM_SYSTEM 0xC /* * LAN Configuration. See section 23. While the underlying mechanism is * implemented via a sequence of get/set parameter commands, we assume that * consumers prefer to get and set information in chunks, and therefore expose * the configuration as a structure, with some of the less useful fields * removed. When making changes, the consumer specifies which fields to apply * along with the structure the library takes care of the rest of the work. * * This can be expanded in the future as needed. */ typedef struct ipmi_lan_config { boolean_t ilc_set_in_progress; uint32_t ilc_ipaddr; uint8_t ilc_ipaddr_source; uint8_t ilc_macaddr[6]; uint32_t ilc_subnet; uint32_t ilc_gateway_addr; } ipmi_lan_config_t; #define IPMI_LAN_SRC_UNSPECIFIED 0x0 #define IPMI_LAN_SRC_STATIC 0x1 #define IPMI_LAN_SRC_DHCP 0x2 #define IPMI_LAN_SRC_BIOS 0x3 #define IPMI_LAN_SRC_OTHER 0x4 #define IPMI_LAN_SET_IPADDR 0x01 #define IPMI_LAN_SET_IPADDR_SOURCE 0x02 #define IPMI_LAN_SET_MACADDR 0x04 #define IPMI_LAN_SET_SUBNET 0x08 #define IPMI_LAN_SET_GATEWAY_ADDR 0x10 #define IPMI_CMD_SET_LAN_CONFIG 0x01 #define IPMI_CMD_GET_LAN_CONFIG 0x02 extern int ipmi_lan_get_config(ipmi_handle_t *, int, ipmi_lan_config_t *); extern int ipmi_lan_set_config(ipmi_handle_t *, int, ipmi_lan_config_t *, int); /* * SEL (System Event Log) commands. Currently the library only provides * commands for reading the SEL. */ /* * 31.2 Get SEL Info Command */ #define IPMI_CMD_GET_SEL_INFO 0x40 typedef struct ipmi_sel_info { uint8_t isel_version; uint16_t isel_entries; uint16_t isel_free; uint32_t isel_add_ts; uint32_t isel_erase_ts; DECL_BITFIELD6( isel_supp_allocation :1, isel_supp_reserve :1, isel_supp_partial :1, isel_supp_delete :1, __reserved :3, isel_overflow :1); } ipmi_sel_info_t; extern ipmi_sel_info_t *ipmi_sel_get_info(ipmi_handle_t *); extern boolean_t ipmi_sdr_changed(ipmi_handle_t *); extern int ipmi_sdr_refresh(ipmi_handle_t *); /* * 32.1 SEL Event Records */ typedef struct ipmi_sel_event { uint16_t isel_ev_next; uint16_t isel_ev_recid; uint8_t isel_ev_rectype; uint32_t isel_ev_ts; DECL_BITFIELD2( isel_ev_software :1, isel_ev_addr_or_id :7); DECL_BITFIELD3( isel_ev_lun :2, __reserved :2, isel_ev_channel :4); uint8_t isel_ev_rev; uint8_t isel_ev_sensor_type; uint8_t isel_ev_sensor_number; DECL_BITFIELD2( isel_ev_type :7, isel_ev_dir :1); uint8_t isel_ev_data[3]; } ipmi_sel_event_t; #define IPMI_EV_REV15 0x04 #define IPMI_EV_REV1 0x03 #define IPMI_SEL_SYSTEM 0x02 #define IPMI_SEL_OEMTS_LO 0xC0 #define IPMI_SEL_OEMTS_HI 0xDF #define IPMI_SEL_OEM_LO 0xE0 #define IPMI_SEL_OEM_HI 0xFF #define IPMI_EV_ASSERT 0x0 #define IPMI_EV_DEASSERT 0x1 /* * 32.2 OEM SEL Record (with timestamp) */ typedef struct ipmi_sel_oem_ts { uint16_t isel_oem_next; uint16_t isel_oem_id; uint8_t isel_oem_type; uint32_t isel_oem_ts; uint8_t isel_oem_devid[3]; uint8_t isel_oem_data[6]; } ipmi_sel_oem_ts_t; /* * 32.3 OEM SEL Record (no timestamp) */ typedef struct ipmi_sel_oem { uint16_t isel_oem_next; uint16_t isel_oem_id; uint8_t isel_oem_type; uint8_t isel_oem_data[13]; } ipmi_sel_oem_t; /* * 29.3 Platform Event Message Command. */ typedef struct ipmi_platform_event_message { uint8_t ipem_generator; uint8_t ipem_rev; uint8_t ipem_sensor_type; uint8_t ipem_sensor_num; DECL_BITFIELD2( ipem_event_type :7, ipem_event_dir :1); uint8_t ipem_event_data[3]; } ipmi_platform_event_message_t; #define IPMI_CMD_PLATFORM_EVENT_MESSAGE 0x02 extern int ipmi_event_platform_message(ipmi_handle_t *, ipmi_platform_event_message_t *); /* * 29.7 Event Data Field Formats. Consumers can cast the data field of the * event record to the appropriate type depending on the sensor class. */ typedef struct ipmi_event_threshold { DECL_BITFIELD3( iev_offset :4, iev_desc_byte3 :2, iev_desc_byte2 :2); uint8_t iev_reading; uint8_t iev_threshold; } ipmi_event_threshold_t; #define IPMI_EV_DESC_UNSPECIFIED 0x00 #define IPMI_EV_DESC_TRIGGER 0x01 #define IPMI_EV_DESC_OEM 0x02 #define IPMI_EV_DESC_SPECIFIC 0x03 typedef struct ipmi_event_discrete { DECL_BITFIELD3( iev_offset :4, iev_desc_byte3 :2, iev_desc_byte2 :2); DECL_BITFIELD2( iev_offset_type :4, iev_offset_severity :4); uint8_t iev_oem_code; } ipmi_event_discrete_t; #define IPMI_EV_DESC_PREVSTATE 0x01 #define IPMI_EV_DESC_SPECIFIC 0x03 typedef struct ipmi_event_oem { DECL_BITFIELD3( iev_offset :4, iev_desc_byte3 :2, iev_desc_byte2 :2); DECL_BITFIELD2( iev_offset_type :4, iev_offset_severity :4); uint8_t iev_oem_code; } ipmi_event_oem_t; /* * Get SEL Entry Command. See section 31.5. We don't support partial reads, so * this interface is quite a bit simpler than in the spec. We default to * returning event records, though the consumer should check the type field and * cast it to the appropriate type if it is no IPMI_SEL_SYSTEM. */ #define IPMI_CMD_GET_SEL_ENTRY 0x43 extern ipmi_sel_event_t *ipmi_sel_get_entry(ipmi_handle_t *, uint16_t); #define IPMI_SEL_FIRST_ENTRY 0x0000 #define IPMI_SEL_LAST_ENTRY 0xFFFF /* * SEL time management. See sections 31.10 and 31.11. */ #define IPMI_CMD_GET_SEL_TIME 0x48 #define IPMI_CMD_SET_SEL_TIME 0x49 #define IPMI_CMD_GET_SEL_UTC_OFFSET 0x5C #define IPMI_CMD_SET_SEL_UTC_OFFSET 0x5D extern int ipmi_sel_get_time(ipmi_handle_t *, uint32_t *); extern int ipmi_sel_set_time(ipmi_handle_t *, uint32_t); extern int ipmi_sel_get_utc_offset(ipmi_handle_t *, int *); extern int ipmi_sel_set_utc_offset(ipmi_handle_t *, int); /* * SDR (Sensor Device Record) requests. A cache of the current SDR repository * is kept as part of the IPMI handle and updated when necessary. This does the * work of processing the SDR names and providing an easy way to lookup * individual records and iterate over all records. */ /* * Get SDR Repository Info Command. See section 33.9. */ #define IPMI_CMD_GET_SDR_INFO 0x20 typedef struct ipmi_sdr_info { uint8_t isi_version; uint16_t isi_record_count; uint16_t isi_free_space; uint32_t isi_add_ts; uint32_t isi_erase_ts; DECL_BITFIELD7( isi_supp_allocation :1, isi_supp_reserve :1, isi_supp_partial :1, isi_supp_delete :1, __reserved :1, isi_modal :2, isi_overflow :1); } ipmi_sdr_info_t; extern ipmi_sdr_info_t *ipmi_sdr_get_info(ipmi_handle_t *); /* * Reserve repository command. See section 33.11. */ #define IPMI_CMD_RESERVE_SDR_REPOSITORY 0x22 /* * Get SDR command. See section 33.12. This command accesses the raw SDR * repository. Clients can also use the lookup functions to retrieve a * particular SDR record by name. * * The list of possible types is indicated in the sub-chapters of section 43. */ typedef struct ipmi_sdr { uint16_t is_id; uint8_t is_version; uint8_t is_type; uint8_t is_length; uint8_t is_record[1]; } ipmi_sdr_t; #define IPMI_CMD_GET_SDR 0x23 #define IPMI_SDR_FIRST 0x0000 #define IPMI_SDR_LAST 0xFFFF extern ipmi_sdr_t *ipmi_sdr_get(ipmi_handle_t *, uint16_t, uint16_t *); /* * Full Sensor Record. See 43.1 */ #define IPMI_SDR_TYPE_FULL_SENSOR 0x01 typedef struct ipmi_sdr_full_sensor { /* RECORD KEY BYTES */ uint8_t is_fs_owner; DECL_BITFIELD3( is_fs_sensor_lun :2, __reserved1 :2, is_fs_channel :4); uint8_t is_fs_number; /* RECORD BODY BYTES */ uint8_t is_fs_entity_id; DECL_BITFIELD2( is_fs_entity_instance :7, is_fs_entity_logical :1); DECL_BITFIELD8( is_fs_sensor_scanning_enabled :1, is_fs_event_generation_enabled :1, is_fs_init_sensor_type :1, is_fs_init_hysteresis :1, is_fs_init_thresholds :1, is_fs_init_events :1, is_fs_init_scanning :1, is_fs_settable :1); DECL_BITFIELD5( is_fs_event_support :2, is_fs_threshold_support :2, is_fs_hysteresis_support :2, is_fs_rearm_support :1, is_fs_ignore :1); uint8_t is_fs_type; uint8_t is_fs_reading_type; uint16_t is_fs_assert_mask; uint16_t is_fs_deassert_mask; uint16_t is_fs_reading_mask; DECL_BITFIELD4( is_fs_units_isprcnt :1, is_fs_mod_unit :2, is_fs_rate_unit :3, is_fs_analog_fmt :2); uint8_t is_fs_unit2; uint8_t is_fs_unit3; /* Linearization */ DECL_BITFIELD2( is_fs_sensor_linear_type :7, __reserved2 :1); /* M, Tolerance */ uint16_t is_fs_mtol; /* B, Accuracy, R exp, B exp */ uint32_t is_fs_bacc; DECL_BITFIELD4( is_fs_nominal_reading_spec :1, is_fs_normal_max_spec :1, is_fs_normal_min_spec :1, __reserved3 :5); uint8_t is_fs_nominal_reading; uint8_t is_fs_normal_maximum; uint8_t is_fs_normal_minimum; uint8_t is_fs_max; uint8_t is_fs_min; uint8_t is_fs_upper_nonrecov; uint8_t is_fs_upper_critical; uint8_t is_fs_upper_noncrit; uint8_t is_fs_lower_nonrecov; uint8_t is_fs_lower_critical; uint8_t is_fs_lower_noncrit; uint8_t is_fs_hysteresis_positive; uint8_t is_fs_hysteresis_negative; uint16_t __reserved4; uint8_t is_fs_oem; DECL_BITFIELD3( is_fs_idlen :5, __reserved5 :1, is_fs_idtype :2); char is_fs_idstring[1]; } ipmi_sdr_full_sensor_t; #define IPMI_SDR_TYPE_COMPACT_SENSOR 0x02 /* * Compact Sensor Record. See section 43.2 */ typedef struct ipmi_sdr_compact_sensor { /* RECORD KEY BYTES */ uint8_t is_cs_owner; DECL_BITFIELD3( is_cs_sensor_lun :2, is_cs_fru_lun :2, is_cs_channel :4); uint8_t is_cs_number; /* RECORD BODY BYTES */ uint8_t is_cs_entity_id; DECL_BITFIELD2( is_cs_entity_instance :7, is_cs_entity_logical :1); DECL_BITFIELD8( is_cs_sensor_scanning_enabled :1, is_cs_event_generation_enabled :1, is_cs_init_sensor_type :1, is_cs_init_hysteresis :1, __reserved1 :1, is_cs_init_events :1, is_cs_init_scanning :1, is_cs_settable :1); DECL_BITFIELD5( is_cs_event_support :2, is_cs_threshold_support :2, is_cs_hysteresis_support :2, is_cs_rearm_support :1, is_cs_ignore :1); uint8_t is_cs_type; uint8_t is_cs_reading_type; uint16_t is_cs_assert_mask; uint16_t is_cs_deassert_mask; uint16_t is_cs_reading_mask; DECL_BITFIELD4( is_cs_units_isprcnt :1, is_cs_mod_unit :2, is_cs_rate_unit :3, __reserved2 :2); uint8_t is_cs_unit2; uint8_t is_cs_unit3; DECL_BITFIELD3( is_cs_share_count :4, is_cs_modifier_type :2, is_cs_direction :2); DECL_BITFIELD2( is_cs_modifier_offset :7, is_cs_sharing :1); uint8_t is_cs_hysteresis_positive; uint8_t is_cs_hysteresis_negative; uint16_t __reserved3; uint8_t __reserved4; uint8_t is_cs_oem; DECL_BITFIELD3( is_cs_idlen :5, __reserved5 :1, is_cs_idtype :2); char is_cs_idstring[1]; } ipmi_sdr_compact_sensor_t; /* * Threshold sensor masks for is_cs_assert_mask and is_cs_deassert_mask. */ #define IPMI_SENSOR_RETURN_NONRECOV 0x4000 #define IPMI_SENSOR_RETURN_CRIT 0x2000 #define IPMI_SENSOR_RETURN_NONCRIT 0x1000 #define IPMI_SENSOR_MASK_UPPER_NONRECOV_HI 0x0800 #define IPMI_SENSOR_MASK_UPPER_NONRECOV_LO 0x0400 #define IPMI_SENSOR_MASK_UPPER_CRIT_HI 0x0200 #define IPMI_SENSOR_MASK_UPPER_CRIT_LO 0x0100 #define IPMI_SENSOR_MASK_UPPER_NONCRIT_HI 0x0080 #define IPMI_SENSOR_MASK_UPPER_NONCRIT_LO 0x0040 #define IPMI_SENSOR_MASK_LOWER_NONRECOV_HI 0x0020 #define IPMI_SENSOR_MASK_LOWER_NONRECOV_LO 0x0010 #define IPMI_SENSOR_MASK_LOWER_CRIT_HI 0x0008 #define IPMI_SENSOR_MASK_LOWER_CRIT_LO 0x0004 #define IPMI_SENSOR_MASK_LOWER_NONCRIT_HI 0x0002 #define IPMI_SENSOR_MASK_LOWER_NONCRIT_LO 0x0001 /* * Threshold sensor masks for is_cs_reading_mask. */ #define IPMI_SENSOR_SETTABLE_UPPER_NONRECOV 0x2000 #define IPMI_SENSOR_SETTABLE_UPPER_CRIT 0x1000 #define IPMI_SENSOR_SETTABLE_UPPER_NONCRIT 0x0800 #define IPMI_SENSOR_SETTABLE_LOWER_NONRECOV 0x0400 #define IPMI_SENSOR_SETTABLE_LOWER_CRIT 0x0200 #define IPMI_SENSOR_SETTABLE_LOWER_NONCRIT 0x0100 #define IPMI_SENSOR_READABLE_UPPER_NONRECOV 0x0020 #define IPMI_SENSOR_READABLE_UPPER_CRIT 0x0010 #define IPMI_SENSOR_READABLE_UPPER_NONCRIT 0x0008 #define IPMI_SENSOR_READABLE_LOWER_NONRECOV 0x0004 #define IPMI_SENSOR_READABLE_LOWER_CRIT 0x0002 #define IPMI_SENSOR_READABLE_LOWER_NONCRIT 0x0001 /* * Values for is_cs_reading_type. See table 42-2. */ #define IPMI_RT_THRESHOLD 0x01 #define IPMI_RT_USAGE 0x02 #define IPMI_RT_STATE 0x03 #define IPMI_RT_PREDFAIL 0x04 #define IPMI_RT_LIMIT 0x05 #define IPMI_RT_PERFORMANCE 0x06 #define IPMI_RT_SEVERITY 0x07 #define IPMI_RT_PRESENT 0x08 #define IPMI_RT_ENABLED 0x09 #define IPMI_RT_AVAILABILITY 0x0A #define IPMI_RT_REDUNDANCY 0x0B #define IPMI_RT_ACPI 0x0C #define IPMI_RT_SPECIFIC 0x6F /* * Bitmasks based on above reading types. See table 42-2 */ #define IPMI_SR_THRESHOLD_LOWER_NONCRIT_LOW 0x0001 #define IPMI_SR_THRESHOLD_LOWER_NONCRIT_HIGH 0x0002 #define IPMI_SR_THRESHOLD_LOWER_CRIT_LOW 0x0004 #define IPMI_SR_THRESHOLD_LOWER_CRIT_HIGH 0x0008 #define IPMI_SR_THRESHOLD_LOWER_NONRECOV_LOW 0x0010 #define IPMI_SR_THRESHOLD_LOWER_NONRECOV_HIGH 0x0020 #define IPMI_SR_THRESHOLD_UPPER_NONCRIT_LOW 0x0040 #define IPMI_SR_THRESHOLD_UPPER_NONCRIT_HIGH 0x0080 #define IPMI_SR_THRESHOLD_UPPER_CRIT_LOW 0x0100 #define IPMI_SR_THRESHOLD_UPPER_CRIT_HIGH 0x0200 #define IPMI_SR_THRESHOLD_UPPER_NONRECOV_LOW 0x0400 #define IPMI_SR_THRESHOLD_UPPER_NONRECOV_HIGH 0x0800 #define IPMI_SR_USAGE_IDLE 0x0001 #define IPMI_SR_USAGE_ACTIVE 0x0002 #define IPMI_SR_USAGE_BUSY 0x0004 #define IPMI_SR_STATE_DEASSERT 0x0001 #define IPMI_SR_STATE_ASSERT 0x0002 #define IPMI_SR_PREDFAIL_DEASSERT 0x0001 #define IPMI_SR_PREDFAIL_ASSERT 0x0002 #define IPMI_SR_LIMIT_NOTEXCEEDED 0x0001 #define IPMI_SR_LIMIT_EXCEEDED 0x0002 #define IPMI_SR_PERFORMANCE_MET 0x0001 #define IPMI_SR_PERFORMANCE_LAGS 0x0002 #define IPMI_SR_SEVERITY_TO_OK 0x0001 #define IPMI_SR_SEVERITY_OK_TO_NONCRIT 0x0002 #define IPMI_SR_SEVERITY_LESS_TO_CRIT 0x0004 #define IPMI_SR_SEVERITY_LESS_TO_NONRECOV 0x0008 #define IPMI_SR_SEVERITY_MORE_TO_NONCRIT 0x0010 #define IPMI_SR_SEVERITY_NONRECOV_TO_CRIT 0x0020 #define IPMI_SR_SEVERITY_TO_NONRECOV 0x0040 #define IPMI_SR_SEVERITY_MONITOR 0x0080 #define IPMI_SR_SEVERITY_INFO 0x0100 #define IPMI_SR_PRESENT_DEASSERT 0x0001 #define IPMI_SR_PRESENT_ASSERT 0x0002 #define IPMI_SR_ENABLED_DEASSERT 0x0001 #define IPMI_SR_ENABLED_ASSERT 0x0002 #define IPMI_SR_AVAILABILITY_RUNNING 0x0001 #define IPMI_SR_AVAILABILITY_INTEST 0x0002 #define IPMI_SR_AVAILABILITY_POWEROFF 0x0004 #define IPMI_SR_AVAILABILITY_ONLINE 0x0008 #define IPMI_SR_AVAILABILITY_OFFLINE 0x0010 #define IPMI_SR_AVAILABILITY_OFFDUTY 0x0020 #define IPMI_SR_AVAILABILITY_DEGRADED 0x0040 #define IPMI_SR_AVAILABILITY_POWERSAVE 0x0080 #define IPMI_SR_AVAILABILITY_INSTALLERR 0x0100 #define IPMI_SR_REDUNDANCY_FULL 0x0001 #define IPMI_SR_REDUNDANCY_LOST 0x0002 #define IPMI_SR_REDUNDANCY_DEGRADED 0x0004 #define IPMI_SR_REDUNDANCY_NONE_MINIMAL 0x0008 #define IPMI_SR_REDUNDANCY_NONE_REGAINED 0x0010 #define IPMI_SR_REDUNDANCY_NONE_INSUFFFICIENT 0x0020 #define IPMI_SR_REDUNDANCY_DEG_FROM_FULL 0x0040 #define IPMI_SR_REDUNDANCY_DEG_FROM_NON 0x0080 #define IPMI_SR_ACPI_DO 0x0001 #define IPMI_SR_ACPI_D1 0x0002 #define IPMI_SR_ACPI_D2 0x0004 #define IPMI_SR_ACPI_D3 0x0008 /* * Bitmasks for sensor-specific reading type (0x6F). See section 42.2. */ #define IPMI_ST_RESERVED 0x00 #define IPMI_ST_TEMP 0x01 #define IPMI_ST_VOLTAGE 0x02 #define IPMI_ST_CURRENT 0x03 #define IPMI_ST_FAN 0x04 #define IPMI_ST_PHYSICAL 0x05 #define IPMI_EV_PHYSICAL_GENERAL 0x0001 #define IPMI_EV_PHYSICAL_BAY 0x0002 #define IPMI_EV_PHYSICAL_CARD 0x0004 #define IPMI_EV_PHYSICAL_PROCESSOR 0x0008 #define IPMI_EV_PHYSICAL_LAN 0x0010 #define IPMI_EV_PHYSICAL_DOCK 0x0020 #define IPMI_EV_PHYSICAL_FAN 0x0040 #define IPMI_ST_PLATFORM 0x06 #define IPMI_EV_PLATFORM_SECURE 0x0001 #define IPMI_EV_PLATFORM_USER_PASS 0x0002 #define IPMI_EV_PLATFORM_SETUP_PASS 0x0004 #define IPMI_EV_PLATFORM_NETWORK_PASS 0x0008 #define IPMI_EV_PLATFORM_OTHER_PASS 0x0010 #define IPMI_EV_PLATFORM_OUT_OF_BAND 0x0020 #define IPMI_ST_PROCESSOR 0x07 #define IPMI_EV_PROCESSOR_IERR 0x0001 #define IPMI_EV_PROCESSOR_THERMAL 0x0002 #define IPMI_EV_PROCESSOR_FRB1 0x0004 #define IPMI_EV_PROCESSOR_FRB2 0x0008 #define IPMI_EV_PROCESSOR_FRB3 0x0010 #define IPMI_EV_PROCESSOR_CONFIG 0x0020 #define IPMI_EV_PROCESSOR_SMBIOS 0x0040 #define IPMI_EV_PROCESSOR_PRESENT 0x0080 #define IPMI_EV_PROCESSOR_DISABLED 0x0100 #define IPMI_EV_PROCESSOR_TERMINATOR 0x0200 #define IPMI_EV_PROCESSOR_THROTTLED 0x0400 #define IPMI_ST_POWER_SUPPLY 0x08 #define IPMI_EV_POWER_SUPPLY_PRESENT 0x0001 #define IPMI_EV_POWER_SUPPLY_FAILURE 0x0002 #define IPMI_EV_POWER_SUPPLY_PREDFAIL 0x0004 #define IPMI_EV_POWER_SUPPLY_INPUT_LOST 0x0008 #define IPMI_EV_POWER_SUPPLY_INPUT_RANGE 0x0010 #define IPMI_EV_POWER_SUPPLY_INPUT_RANGE_PRES 0x0020 #define IPMI_EV_POWER_SUPPLY_CONFIG_ERR 0x0040 #define IPMI_ST_POWER_UNIT 0x09 #define IPMI_EV_POWER_UNIT_OFF 0x0001 #define IPMI_EV_POWER_UNIT_CYCLE 0x0002 #define IPMI_EV_POWER_UNIT_240_DOWN 0x0004 #define IPMI_EV_POWER_UNIT_INTERLOCK_DOWN 0x0008 #define IPMI_EV_POWER_UNIT_AC_LOST 0x0010 #define IPMI_EV_POWER_UNIT_SOFT_FAILURE 0x0020 #define IPMI_EV_POWER_UNIT_FAIL 0x0040 #define IPMI_EV_POWER_UNIT_PREDFAIL 0x0080 #define IPMI_ST_COOLING 0x0A #define IPMI_ST_OTHER 0x0B #define IPMI_ST_MEMORY 0x0C #define IPMI_EV_MEMORY_CE 0x0001 #define IPMI_EV_MEMORY_UE 0x0002 #define IPMI_EV_MEMORY_PARITY 0x0004 #define IPMI_EV_MEMORY_SCRUB_FAIL 0x0008 #define IPMI_EV_MEMORY_DISABLED 0x0010 #define IPMI_EV_MEMORY_CE_LOG_LIMIT 0x0020 #define IPMI_EV_MEMORY_PRESENT 0x0040 #define IPMI_EV_MEMORY_CONFIG_ERR 0x0080 #define IPMI_EV_MEMORY_SPARE 0x0100 #define IPMI_EV_MEMORY_THROTTLED 0x0200 #define IPMI_EV_MEMORY_OVERTEMP 0x0400 #define IPMI_ST_BAY 0x0D #define IPMI_EV_BAY_PRESENT 0x0001 #define IPMI_EV_BAY_FAULT 0x0002 #define IPMI_EV_BAY_PREDFAIL 0x0004 #define IPMI_EV_BAY_SPARE 0x0008 #define IPMI_EV_BAY_CHECK 0x0010 #define IPMI_EV_BAY_CRITICAL 0x0020 #define IPMI_EV_BAY_FAILED 0x0040 #define IPMI_EV_BAY_REBUILDING 0x0080 #define IPMI_EV_BAY_ABORTED 0x0100 #define IPMI_ST_POST_RESIZE 0x0E #define IPMI_ST_FIRMWARE 0x0F #define IPMI_EV_FIRMWARE_ERROR 0x0001 #define IPMI_EV_FIRMWARE_HANG 0x0002 #define IPMI_EV_FIRMWARE_PROGRESS 0x0004 #define IPMI_ST_EVENT_LOG 0x10 #define IPMI_EV_EVENT_LOG_CE 0x0001 #define IPMI_EV_EVENT_LOG_TYPE 0x0002 #define IPMI_EV_EVENT_LOG_RESET 0x0004 #define IPMI_EV_EVENT_LOG_ALL 0x0008 #define IPMI_EV_EVENT_LOG_FULL 0x0010 #define IPMI_EV_EVENT_LOG_ALMOST_FULL 0x0020 #define IPMI_ST_WATCHDOG1 0x11 #define IPMI_EV_WATCHDOG_BIOS_RESET 0x0001 #define IPMI_EV_WATCHDOG_OS_RESET 0x0002 #define IPMI_EV_WATCHDOG_OS_SHUTDOWN 0x0004 #define IPMI_EV_WATCHDOG_OS_PWR_DOWN 0x0008 #define IPMI_EV_WATCHDOG_OS_PWR_CYCLE 0x0010 #define IPMI_EV_WATCHDOG_OS_NMI_DIAG 0x0020 #define IPMI_EV_WATCHDOG_EXPIRED 0x0040 #define IPMI_EV_WATCHDOG_PRE_TIMEOUT_INT 0x0080 #define IPMI_ST_SYSTEM 0x12 #define IPMI_EV_STSTEM_RECONF 0x0001 #define IPMI_EV_STSTEM_BOOT 0x0002 #define IPMI_EV_STSTEM_UNKNOWN_HW_FAILURE 0x0004 #define IPMI_EV_STSTEM_AUX_LOG_UPDATED 0x0008 #define IPMI_EV_STSTEM_PEF_ACTION 0x0010 #define IPMI_EV_SYSTEM_TIMETAMP_CLOCKSYNC 0x0020 #define IPMI_ST_CRITICAL 0x13 #define IPMI_EV_CRITICAL_EXT_NMI 0x0001 #define IPMI_EV_CRITICAL_BUS_TIMOEOUT 0x0002 #define IPMI_EV_CRITICAL_IO_NMI 0x0004 #define IPMI_EV_CRITICAL_SW_NMI 0x0008 #define IPMI_EV_CRITICAL_PCI_PERR 0x0010 #define IPMI_EV_CRITICAL_PCI_SERR 0x0020 #define IPMI_EV_CRITICAL_EISA_FAILSAFE 0x0040 #define IPMI_EV_CRITICAL_BUS_CE 0x0080 #define IPMI_EV_CRITICAL_BUS_UE 0x0100 #define IPMI_EV_CRITICAL_FATAL_NMI 0x0200 #define IPMI_EV_CRITICAL_BUS_FATAL_ERR 0x0400 #define IPMI_EV_CRITICAL_BUS_DEGRADED 0x0800 #define IPMI_ST_BUTTON 0x14 #define IPMI_EV_BUTTON_PWR 0x0001 #define IPMI_EV_BUTTON_SLEEP 0x0002 #define IPMI_EV_BUTTON_RESET 0x0004 #define IPMI_EV_BUTTON_FRU_LATCH 0x0008 #define IPMI_EV_BUTTON_FRU_SERVICE 0x0010 #define IPMI_ST_MODULE 0x15 #define IPMI_ST_MICROCONTROLLER 0x16 #define IPMI_ST_CARD 0x17 #define IPMI_ST_CHASSIS 0x18 #define IPMI_ST_CHIPSET 0x19 #define IPMI_EV_CHIPSET_PWR_CTL_FAIL 0x0001 #define IPMI_ST_FRU 0x1A #define IPMI_ST_CABLE 0x1B #define IPMI_EV_CABLE_CONNECTED 0x0001 #define IPMI_EV_CABLE_CONFIG_ERR 0x0002 #define IPMI_ST_TERMINATOR 0x1C #define IPMI_ST_BOOT 0x1D #define IPMI_EV_BOOT_BIOS_PWR_UP 0x0001 #define IPMI_EV_BOOT_BIOS_HARD_RESET 0x0002 #define IPMI_EV_BOOT_BIOS_WARM_RESET 0x0004 #define IPMI_EV_BOOT_PXE_BOOT 0x0008 #define IPMI_EV_BOOT_DIAG_BOOT 0x0010 #define IPMI_EV_BOOT_OS_HARD_RESET 0x0020 #define IPMI_EV_BOOT_OS_WARM_RESET 0x0040 #define IPMI_EV_BOOT_SYS_RESTART 0x0080 #define IPMI_ST_BOOT_ERROR 0x1E #define IPMI_EV_BOOT_ERROR_NOMEDIA 0x0001 #define IPMI_EV_BOOT_ERROR_NON_BOOTABLE_DISK 0x0002 #define IPMI_EV_BOOT_ERROR_NO_PXE_SERVER 0x0004 #define IPMI_EV_BOOT_ERROR_INV_BOOT_SECT 0x0008 #define IPMI_EV_BOOT_ERROR_USR_SELECT_TIMEOUT 0x0010 #define IPMI_ST_BOOT_OS 0x1F #define IPMI_EV_BOOT_OS_A_DRV_BOOT_COMPLETE 0x0001 #define IPMI_EV_BOOT_OS_C_DRV_BOOT_COMPLETE 0x0002 #define IPMI_EV_BOOT_OS_PXE_BOOT_COMPLETE 0x0004 #define IPMI_EV_BOOT_OS_DIAG_BOOT_COMPLETE 0x0008 #define IPMI_EV_BOOT_OS_CDROM_BOOT_COMPLETE 0x0010 #define IPMI_EV_BOOT_OS_ROM_BOOT_COMPLETE 0x0020 #define IPMI_EV_BOOT_OS_UNSPEC_BOOT_COMPLETE 0x0040 #define IPMI_ST_OS_SHUTDOWN 0x20 #define IPMI_EV_OS_SHUTDOWN_LOADING 0x0001 #define IPMI_EV_OS_SHUTDOWN_CRASH 0x0002 #define IPMI_EV_OS_STOP_GRACEFUL 0x0004 #define IPMI_EV_OS_SHUTDOWN_GRACEFUL 0x0008 #define IPMI_EV_OS_SHUTDOWN_PEF 0x0010 #define IPMI_EV_OS_SHUTDOWN_BMC 0x0020 #define IPMI_ST_SLOT 0x21 #define IPMI_EV_SLOT_FAULT_ASSERTED 0x0001 #define IPMI_EV_SLOT_IDENTIFY_ASSERTED 0x0002 #define IPMI_EV_SLOT_CONNECTED 0x0004 #define IPMI_EV_SLOT_INSTALL_READY 0x0008 #define IPMI_EV_SLOT_REMOVE_READY 0x0010 #define IPMI_EV_SLOT_PWR_OFF 0x0020 #define IPMI_EV_SLOT_REMOVED 0x0040 #define IPMI_EV_SLOT_INTERLOCK_ASSERTED 0x0080 #define IPMI_EV_SLOT_DISABLED 0x0100 #define IPMI_EV_SLOT_SPARE_DEVICE 0x0200 #define IPMI_ST_ACPI 0x22 #define IPMI_EV_ACPI_PSTATE_S0_G0 0x0001 #define IPMI_EV_ACPI_PSTATE_S1 0x0002 #define IPMI_EV_ACPI_PSTATE_S2 0x0004 #define IPMI_EV_ACPI_PSTATE_S3 0x0008 #define IPMI_EV_ACPI_PSTATE_S4 0x0010 #define IPMI_EV_ACPI_PSTATE_S5_G2_SOFT_OFF 0x0020 #define IPMI_EV_ACPI_PSTATE_S4_S5_SOFT_OFF 0x0040 #define IPMI_EV_ACPI_PSATTE_G3_MECH_OFF 0x0080 #define IPMI_EV_ACPI_PSTATE_S1_S2_S3_SLEEP 0x0100 #define IPMI_EV_ACPI_PSTATE_G1_SLEEP 0x0200 #define IPMI_EV_ACPI_PSTATE_S5_OVERRIDE 0x0400 #define IPMI_EV_ACPI_PSTATE_LEGACY_ON 0x0800 #define IPMI_EV_ACPI_PSTATE_LEGACY_OFF 0x1000 #define IPMI_EV_ACPI_PSTATE_UNKNOWN 0x2000 #define IPMI_ST_WATCHDOG2 0x23 #define IPMI_EV_WATCHDOG2_EXPIRED 0x0001 #define IPMI_EV_WATCHDOG2_HARD_RESET 0x0002 #define IPMI_EV_WATCHDOG2_PWR_DOWN 0x0004 #define IPMI_EV_WATCHDOG2_PWR_CYCLE 0x0008 #define IPMI_EV_WATCHDOG2_RESERVED1 0x0010 #define IPMI_EV_WATCHDOG2_RESERVED2 0x0020 #define IPMI_EV_WATCHDOG2_RESERVED3 0x0040 #define IPMI_EV_WATCHDOG2_RESERVED4 0x0080 #define IPMI_EV_WATCHDOG2_TIMEOUT_INT 0x0100 #define IPMI_ST_ALERT 0x24 #define IPMI_EV_ALERT_PLAT_PAGE 0x0001 #define IPMI_EV_ALERT_PLAT_LAN_ALERT 0x0002 #define IPMI_EV_ALERT_PLAT_EVT_TRAP 0x0004 #define IPMI_EV_ALERT_PLAT_SNMP_TRAP 0x0008 #define IPMI_ST_PRESENCE 0x25 #define IPMI_EV_PRESENCE_PRESENT 0x0001 #define IPMI_EV_PRESENCE_ABSENT 0x0002 #define IPMI_EV_PRESENCE_DISABLED 0x0004 #define IPMI_ST_ASIC 0x26 #define IPMI_ST_LAN 0x27 #define IPMI_EV_LAN_HEARTBEAT_LOST 0x0001 #define IPMI_EV_LAN_HEARTBEAT 0x0002 #define IPMI_ST_HEALTH 0x28 #define IPMI_EV_HEALTH_SENSOR_ACC_DEGRADED 0x0001 #define IPMI_EV_HEALTH_CNTLR_ACC_DEGRADED 0x0002 #define IPMI_EV_HEALTH_CNTLR_OFFLINE 0x0004 #define IPMI_EV_HEALTH_CNTLR_UNAVAIL 0x0008 #define IPMI_EV_HEALTH_SENSOR_FAILURE 0x0010 #define IPMI_EV_HEALTH_FRU_FAILURE 0x0020 #define IPMI_ST_BATTERY 0x29 #define IPMI_EV_BATTERY_LOW 0x0001 #define IPMI_EV_BATTERY_FAILED 0x0002 #define IPMI_EV_BATTERY_PRESENCE 0x0004 #define IPMI_ST_AUDIT 0x2A #define IPMI_EV_AUDIT_SESSION_ACTIVATED 0x0001 #define IPMI_EV_AUDIT_SESSION_DEACTIVATED 0x0002 #define IPMI_ST_VERSION 0x2B #define IPMI_EV_VERSION_HW_CHANGE 0x0001 #define IPMI_EV_VERSION_SW_CHANGE 0x0002 #define IPMI_EV_VERSION_HW_INCOMPATIBLE 0x0004 #define IPMI_EV_VERSION_SW_INCOMPATIBLE 0x0008 #define IPMI_EV_VERSION_HW_INVAL 0x0010 #define IPMI_EV_VERSION_SW_INVAL 0x0020 #define IPMI_EV_VERSION_HW_CHANGE_SUCCESS 0x0040 #define IPMI_EV_VERSION_SW_CHANGE_SUCCESS 0x0080 #define IPMI_ST_FRU_STATE 0x2C #define IPMI_EV_FRU_STATE_NOT_INSTALLED 0x0001 #define IPMI_EV_FRU_STATE_INACTIVE 0x0002 #define IPMI_EV_FRU_STATE_ACT_REQ 0x0004 #define IPMI_EV_FRU_STATE_ACT_INPROGRESS 0x0008 #define IPMI_EV_FRU_STATE_ACTIVE 0x0010 #define IPMI_EV_FRU_STATE_DEACT_REQ 0x0020 #define IPMI_EV_FRU_STATE_DEACT_INPROGRESS 0x0040 #define IPMI_EV_FRU_STATE_COMM_LOST 0x0080 /* * Constants for unit type codes. See Table 43-15. */ #define IPMI_UNITS_UNSPECIFIED 0x00 #define IPMI_UNITS_DEGREES_C 0x01 #define IPMI_UNITS_DEGREES_F 0x02 #define IPMI_UNITS_DEGREES_K 0x03 #define IPMI_UNITS_VOLTS 0x04 #define IPMI_UNITS_AMPS 0x05 #define IPMI_UNITS_WATTS 0x06 #define IPMI_UNITS_JOULES 0x07 #define IPMI_UNITS_COULOMBS 0x08 #define IPMI_UNITS_VA 0x09 #define IPMI_UNITS_NITS 0x0A #define IPMI_UNITS_LUMEN 0x0B #define IPMI_UNITS_LUX 0x0C #define IPMI_UNITS_CANDELA 0x0D #define IPMI_UNITS_KPA 0x0E #define IPMI_UNITS_PSI 0x0F #define IPMI_UNITS_NEWTON 0x10 #define IPMI_UNITS_CFM 0x11 #define IPMI_UNITS_RPM 0x12 #define IPMI_UNITS_HZ 0x13 #define IPMI_UNITS_MICROSEC 0x14 #define IPMI_UNITS_MILLISEC 0x15 #define IPMI_UNITS_SECS 0x16 #define IPMI_UNITS_MIN 0x17 #define IPMI_UNITS_HOUR 0x18 #define IPMI_UNITS_DAY 0x19 #define IPMI_UNITS_WEEK 0x1A #define IPMI_UNITS_MIL 0x1B #define IPMI_UNITS_INCHES 0x1C #define IPMI_UNITS_FEET 0x1D #define IPMI_UNITS_CUB_INCH 0x1E #define IPMI_UNITS_CUB_FEET 0x1F #define IPMI_UNITS_MM 0x20 #define IPMI_UNITS_CM 0x21 #define IPMI_UNITS_METERS 0x22 #define IPMI_UNITS_CUB_CM 0x23 #define IPMI_UNITS_CUB_METER 0x24 #define IPMI_UNITS_LITERS 0x25 #define IPMI_UNITS_FLUID_OUNCE 0x26 #define IPMI_UNITS_RADIANS 0x27 #define IPMI_UNITS_STERADIANS 0x28 #define IPMI_UNITS_REVOLUTIONS 0x29 #define IPMI_UNITS_CYCLES 0x2A #define IPMI_UNITS_GRAVITIES 0x2B #define IPMI_UNITS_OUNCE 0x2C #define IPMI_UNITS_POUND 0x2D #define IPMI_UNITS_FOOT_POUND 0x2E #define IPMI_UNITS_OZ_INCH 0x2F #define IPMI_UNITS_GAUSS 0x30 #define IPMI_UNITS_GILBERTS 0x31 #define IPMI_UNITS_HENRY 0x32 #define IPMI_UNITS_MILHENRY 0x33 #define IPMI_UNITS_FARAD 0x34 #define IPMI_UNITS_MICROFARAD 0x35 #define IPMI_UNITS_OHMS 0x36 #define IPMI_UNITS_SIEMENS 0x37 #define IPMI_UNITS_MOLE 0x38 #define IPMI_UNITS_BECQUEREL 0x39 #define IPMI_UNITS_PPM 0x3A /* 0x3B is reserved */ #define IPMI_UNITS_DECIBELS 0x3C #define IPMI_UNITS_DBA 0x3D #define IPMI_UNITS_DBC 0x3E #define IPMI_UNITS_GRAY 0x3F #define IPMI_UNITS_SIEVERT 0x40 #define IPMI_UNITS_COLOR_TEMP_K 0x41 #define IPMI_UNITS_BIT 0x42 #define IPMI_UNITS_KILOBIT 0x43 #define IPMI_UNITS_MEGABIT 0x44 #define IPMI_UNITS_GIGABIT 0x45 #define IPMI_UNITS_BYTE 0x46 #define IPMI_UNITS_KILOBYTE 0x47 #define IPMI_UNITS_MEGABYTE 0x48 #define IPMI_UNITS_GIGABYTE 0x49 #define IPMI_UNITS_WORD 0x4A #define IPMI_UNITS_DWORD 0x4B #define IPMI_UNITS_QWORD 0x4C #define IPMI_UNITS_MEMLINE 0x4D #define IPMI_UNITS_HIT 0x4E #define IPMI_UNITS_MISS 0x4F #define IPMI_UNITS_RETRY 0x50 #define IPMI_UNITS_RESET 0x51 #define IPMI_UNITS_OVERFLOW 0x52 #define IPMI_UNITS_UNDERRUN 0x53 #define IPMI_UNITS_COLLISION 0x54 #define IPMI_UNITS_PACKETS 0x55 #define IPMI_UNITS_MESSAGES 0x56 #define IPMI_UNITS_CHARACTERS 0x57 #define IPMI_UNITS_ERROR 0x58 #define IPMI_UNITS_CE 0x59 #define IPMI_UNITS_UE 0x5A #define IPMI_UNITS_FATAL_ERROR 0x5B #define IPMI_UNITS_GRAMS 0x5C /* * Event-Only Record. See section 43.3. */ #define IPMI_SDR_TYPE_EVENT_ONLY 0x03 typedef struct ipmi_sdr_event_only { /* RECORD KEY BYTES */ uint8_t is_eo_owner; DECL_BITFIELD3( is_eo_sensor_lun :2, is_eo_fru_lun :2, is_eo_channel :4); uint8_t is_eo_number; /* RECORD BODY BYTES */ uint8_t is_eo_entity_id; DECL_BITFIELD2( is_eo_entity_instance :7, is_eo_entity_logical :1); uint8_t is_eo_sensor_type; uint8_t is_eo_reading_type; DECL_BITFIELD3( is_eo_share_count :4, is_eo_modifier_type :2, is_eo_direction :2); DECL_BITFIELD2( is_eo_modifier_offset :7, is_eo_sharing :1); uint8_t __reserved; uint8_t is_eo_oem; DECL_BITFIELD3( is_eo_idlen :5, __reserved1 :1, is_eo_idtype :2); char is_eo_idstring[1]; } ipmi_sdr_event_only_t; /* * Entity Association Record. See section 43.4. */ #define IPMI_SDR_TYPE_ENTITY_ASSOCIATION 0x08 typedef struct ipmi_sdr_entity_association { /* RECORD KEY BYTES */ uint8_t is_ea_entity_id; uint8_t is_ea_entity_instance; DECL_BITFIELD4( __reserved :5, is_ea_presence :1, is_ea_record_link :1, is_ea_range :1); /* RECORD BODY BYTES */ struct { uint8_t is_ea_sub_id; uint8_t is_ea_sub_instance; } is_ea_sub[4]; } ipmi_sdr_entity_association_t; /* * Device-relative Entity Association Record. See section 43.5. */ #define IPMI_SDR_TYPE_DEVICE_RELATIVE 0x09 typedef struct ipmi_sdr_device_relative { /* RECORD KEY BYTES */ uint8_t is_dr_entity_id; uint8_t is_dr_entity_instance; DECL_BITFIELD2( __reserved1 :1, is_dr_slaveaddr :7); DECL_BITFIELD2( __reserved2 :4, is_dr_channel :4); DECL_BITFIELD4( __reserved :5, is_dr_presence :1, is_dr_record_link :1, is_dr_range :1); /* RECORD BODY BYTES */ struct { DECL_BITFIELD2( __reserved3 :1, is_dr_sub_slaveaddr :7); DECL_BITFIELD2( __reserved4 :4, is_dr_sub_channel :4); uint8_t is_ea_sub_id; uint8_t is_ea_sub_instance; } is_ea_sub[4]; } ipmi_sdr_device_relative_t; /* * Generic Device Locator Record. See section 43.7. */ #define IPMI_SDR_TYPE_GENERIC_LOCATOR 0x10 typedef struct ipmi_sdr_generic_locator { /* RECORD KEY BYTES */ DECL_BITFIELD2( __reserved1 :1, is_gl_accessaddr :7); DECL_BITFIELD2( is_gl_channel_msb :1, is_gl_slaveaddr :7); DECL_BITFIELD3( is_gl_bus :3, is_gl_lun :2, is_gl_channel :3); /* RECORD BODY BYTES */ DECL_BITFIELD2( is_gl_span :3, __reserved2 :5); uint8_t __reserved3; uint8_t is_gl_type; uint8_t is_gl_modifier; uint8_t is_gl_entity; uint8_t is_gl_instance; uint8_t is_gl_oem; DECL_BITFIELD3( is_gl_idlen :5, __reserved4 :1, is_gl_idtype :2); char is_gl_idstring[1]; } ipmi_sdr_generic_locator_t; /* * FRU Device Locator Record. See section 43.8. */ #define IPMI_SDR_TYPE_FRU_LOCATOR 0x11 typedef struct ipmi_sdr_fru_locator { /* RECORD KEY BYTES */ DECL_BITFIELD2( __reserved1 :1, is_fl_accessaddr :7); union { struct { uint8_t _is_fl_devid; } _logical; struct { DECL_BITFIELD2( __reserved :1, _is_fl_slaveaddr :7); } _nonintelligent; } _devid_or_slaveaddr; DECL_BITFIELD4( is_fl_bus :3, is_fl_lun :2, __reserved2 :2, is_fl_logical :1); DECL_BITFIELD2( __reserved3 :4, is_fl_channel :4); /* RECORD BODY BYTES */ uint8_t __reserved4; uint8_t is_fl_type; uint8_t is_fl_modifier; uint8_t is_fl_entity; uint8_t is_fl_instance; uint8_t is_fl_oem; DECL_BITFIELD3( is_fl_idlen :5, __reserved5 :1, is_fl_idtype :2); char is_fl_idstring[1]; } ipmi_sdr_fru_locator_t; #define is_fl_devid _devid_or_slaveaddr._logical._is_fl_devid #define is_fl_slaveaddr _devid_or_slaveaddr._nonintelligent._is_fl_slaveaddr /* * Management Controller Device Locator Record. See section 43.9 */ #define IPMI_SDR_TYPE_MANAGEMENT_LOCATOR 0x12 typedef struct ipmi_sdr_management_locator { /* RECORD KEY BYTES */ DECL_BITFIELD2( __reserved1 :1, is_ml_devaddr :7); DECL_BITFIELD2( is_ml_channel :4, __reserved2 :4); /* RECORD BODY BYTES */ DECL_BITFIELD7( is_ml_init_message :2, is_ml_init_log :1, is_ml_init_controller_log :1, __reserved3 :1, is_ml_static :1, is_ml_acpi_device :1, is_ml_acpi_system :1); DECL_BITFIELD8( is_ml_supp_sensor :1, is_ml_supp_sdr :1, is_ml_supp_sel :1, is_ml_supp_fru :1, is_ml_supp_event_receiver :1, is_ml_supp_event_generator :1, is_ml_supp_bridge :1, is_ml_supp_chassis :1); uint8_t __reserved4; uint16_t __reserved5; uint8_t is_ml_entity_id; uint8_t is_ml_entity_instance; uint8_t is_ml_oem; DECL_BITFIELD3( is_ml_idlen :5, __reserved6 :1, is_ml_idtype :2); char is_ml_idstring[1]; } ipmi_sdr_management_locator_t; #define IPMI_MESSAGE_INIT_ENABLE 0x0 #define IPMI_MESSAGE_INIT_DISABLE 0x1 #define IPMI_MESSAGE_INIT_NONE 0x2 /* * Management Controller Confirmation Record. See section 43.10 */ #define IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION 0x13 typedef struct ipmi_sdr_management_confirmation { /* RECORD KEY BYTES */ DECL_BITFIELD2( __reserved1 :1, is_mc_slaveaddr :7); uint8_t is_mc_deviceid; DECL_BITFIELD2( is_mc_dev_revision :4, is_mc_channel :4); /* RECORD BODY BYTES */ DECL_BITFIELD2( is_mc_major_rev :7, __reserved2 :1); uint8_t is_mc_minor_rev; uint8_t is_mc_impi_ver; uint8_t is_mc_manufacturer[3]; uint16_t is_mc_product; uint8_t is_mc_guid[16]; } ipmi_sdr_management_confirmation_t; /* * BMC Message Channel Info Record. See esction 43.11. */ #define IPMI_SDR_TYPE_BMC_MESSAGE_CHANNEL 0x14 typedef struct ipmi_sdr_bmc_channel { /* RECORD BODY BYTES */ struct { DECL_BITFIELD3( is_bc_protocol :4, is_bc_receive_lun :3, is_bc_transmit :1); } is_bc_channel[8]; uint8_t is_bc_interrupt_type; uint8_t is_bc_buffer_type; uint8_t __reserved; } ipmi_sdr_bmc_channel_t; /* * OEM Record. See ction 43.12. */ #define IPMI_SDR_TYPE_OEM 0xC0 typedef struct ipmi_sdr_oem { uint8_t is_oem_manufacturer[3]; uint8_t is_oem_data[1]; } ipmi_sdr_oem_t; /* * Iterate over the SDR repository. This function does the work of parsing the * name when available, and keeping the repository in a consistent state. */ extern int ipmi_sdr_iter(ipmi_handle_t *, int (*)(ipmi_handle_t *, const char *, ipmi_sdr_t *, void *), void *); /* * Lookup the given sensor type by name or a combination of name and entity * ID/instance. These functions automatically read in and cache the complete * SDR repository. */ extern ipmi_sdr_t *ipmi_sdr_lookup(ipmi_handle_t *, const char *); extern ipmi_sdr_t *ipmi_sdr_lookup_precise(ipmi_handle_t *, const char *, uint8_t, uint8_t); extern ipmi_sdr_fru_locator_t *ipmi_sdr_lookup_fru(ipmi_handle_t *, const char *); extern ipmi_sdr_generic_locator_t *ipmi_sdr_lookup_generic(ipmi_handle_t *, const char *); extern ipmi_sdr_compact_sensor_t *ipmi_sdr_lookup_compact_sensor( ipmi_handle_t *, const char *); extern ipmi_sdr_full_sensor_t *ipmi_sdr_lookup_full_sensor( ipmi_handle_t *, const char *); /* * Entity ID codes. See table 43.13. */ #define IPMI_ET_UNSPECIFIED 0x00 #define IPMI_ET_OTHER 0x01 #define IPMI_ET_UNKNOWN 0x02 #define IPMI_ET_PROCESSOR 0x03 #define IPMI_ET_DISK 0x04 #define IPMI_ET_PERIPHERAL 0x05 #define IPMI_ET_MANAGEMENT_MODULE 0x06 #define IPMI_ET_MOTHERBOARD 0x07 #define IPMI_ET_MEMORY_MODULE 0x08 #define IPMI_ET_PROCESSOR_MODULE 0x09 #define IPMI_ET_PSU 0x0A #define IPMI_ET_CARD 0x0B #define IPMI_ET_FRONT_PANEL 0x0C #define IPMI_ET_BACK_PANEL 0x0D #define IPMI_ET_POWER_BOARD 0x0E #define IPMI_ET_BACKPLANE 0x0F #define IPMI_ET_EXPANSION_BOARD 0x10 #define IPMI_ET_OTHER_BOARD 0x11 #define IPMI_ET_PROCESSOR_BOARD 0x12 #define IPMI_ET_POWER_DOMAIN 0x13 #define IPMI_ET_POWER_CONVERTER 0x14 #define IPMI_ET_POWER_MANAGEMENT 0x15 #define IPMI_ET_BACK_CHASSIS 0x16 #define IPMI_ET_SYSTEM_CHASSIS 0x17 #define IPMI_ET_SUB_CHASSIS 0x18 #define IPMI_ET_OTHER_CHASSIS 0x19 #define IPMI_ET_DISK_BAY 0x1A #define IPMI_ET_PERIPHERAL_BAY 0x1B #define IPMI_ET_DEVICE_BAY 0x1C #define IPMI_ET_FAN 0x1D #define IPMI_ET_COOLING_DOMAIN 0x1E #define IPMI_ET_CABLE 0x1F #define IPMI_ET_MEMORY_DEVICE 0x20 #define IPMI_ET_MANAGEMENT_SOFTWARE 0x21 #define IPMI_ET_SYSTEM_FIRMWARE 0x22 #define IPMI_ET_OS 0x23 #define IPMI_ET_SYSTEM_BUS 0x24 #define IPMI_ET_GROUP 0x25 #define IPMI_ET_REMOTE 0x26 #define IPMI_ET_ENVIRONMENT 0x27 #define IPMI_ET_BATTERY 0x28 #define IPMI_ET_BLADE 0x29 #define IPMI_ET_SWITCH 0x2A #define IPMI_ET_PROCMEM_MODULE 0x2B #define IPMI_ET_IO_MODULE 0x2C #define IPMI_ET_PROCIO_MODULE 0x2D #define IPMI_ET_CONTROLLER_FIRMWARE 0x2E #define IPMI_ET_CHANNEL 0x2F #define IPMI_ET_PCI 0x30 #define IPMI_ET_PCIE 0x31 #define IPMI_ET_SCSI 0x32 #define IPMI_ET_SATA_SAS 0x33 #define IPMI_ET_FSB 0x34 #define IPMI_ET_RTC 0x35 /* * Get Sensor Threshold. See section 35.9 */ #define IPMI_CMD_GET_SENSOR_THRESHOLDS 0x27 typedef struct ipmi_sensor_thresholds { uint8_t ithr_readable_mask; uint8_t ithr_lower_noncrit; uint8_t ithr_lower_crit; uint8_t ithr_lower_nonrec; uint8_t ithr_upper_noncrit; uint8_t ithr_upper_crit; uint8_t ithr_upper_nonrec; } ipmi_sensor_thresholds_t; extern int ipmi_get_sensor_thresholds(ipmi_handle_t *, ipmi_sensor_thresholds_t *, uint8_t); /* * Get Sensor Reading. See section 35.14. */ #define IPMI_CMD_GET_SENSOR_READING 0x2d typedef struct ipmi_sensor_reading { uint8_t isr_reading; DECL_BITFIELD4( __reserved1 :5, isr_state_unavailable :1, isr_scanning_enabled :1, isr_event_enabled :1); uint16_t isr_state; } ipmi_sensor_reading_t; #define IPMI_SENSOR_THRESHOLD_LOWER_NONCRIT 0x0001 #define IPMI_SENSOR_THRESHOLD_LOWER_CRIT 0x0002 #define IPMI_SENSOR_THRESHOLD_LOWER_NONRECOV 0x0004 #define IPMI_SENSOR_THRESHOLD_UPPER_NONCRIT 0x0008 #define IPMI_SENSOR_THRESHOLD_UPPER_CRIT 0x0010 #define IPMI_SENSOR_THRESHOLD_UPPER_NONRECOV 0x0020 extern ipmi_sensor_reading_t *ipmi_get_sensor_reading(ipmi_handle_t *, uint8_t); extern int ipmi_sdr_conv_reading(ipmi_sdr_full_sensor_t *, uint8_t, double *); /* * Set Sensor Reading. See section 35.14. */ #define IPMI_CMD_SET_SENSOR_READING 0x30 #define IPMI_SENSOR_OP_CLEAR 0x3 /* clear '0' bits */ #define IPMI_SENSOR_OP_SET 0x2 /* set '1' bits */ #define IPMI_SENSOR_OP_EXACT 0x1 /* set bits exactly */ typedef struct ipmi_set_sensor_reading { uint8_t iss_id; DECL_BITFIELD5( iss_set_reading :1, __reserved :1, iss_deassrt_op :2, iss_assert_op :2, iss_data_bytes :2); uint8_t iss_sensor_reading; uint16_t iss_assert_state; /* optional */ uint16_t iss_deassert_state; /* optional */ uint8_t iss_event_data1; /* optional */ uint8_t iss_event_data2; /* optional */ uint8_t iss_event_data3; /* optional */ } ipmi_set_sensor_reading_t; extern int ipmi_set_sensor_reading(ipmi_handle_t *, ipmi_set_sensor_reading_t *); /* * These IPMI message id/opcodes are documented in Appendix G in the IPMI spec. * * Payloads for these two commands are described in Sections 34.1 and 34.2 of * the spec, respectively. */ #define IPMI_CMD_GET_FRU_INV_AREA 0x10 #define IPMI_CMD_READ_FRU_DATA 0x11 /* * Structs to hold the FRU Common Header and the FRU Product Info Area, as * described in the IPMI Platform Management FRU Information Storage * Definition (v1.1). */ typedef struct ipmi_fru_hdr { uint8_t ifh_format; uint8_t ifh_int_use_off; uint8_t ifh_chassis_info_off; uint8_t ifh_board_info_off; uint8_t ifh_product_info_off; uint8_t ifh_multi_rec_off; uint8_t ifh_pad; uint8_t ifh_chksum; } ipmi_fru_hdr_t; /* * Because only 6 bits are used to specify the length of each field in the FRU * product and board info areas, the biggest string we would ever need to hold * would be 63 chars plus a NULL. */ #define FRU_INFO_MAXLEN 64 typedef struct ipmi_fru_brd_info { char ifbi_manuf_date[3]; char ifbi_manuf_name[FRU_INFO_MAXLEN]; char ifbi_board_name[FRU_INFO_MAXLEN]; char ifbi_product_serial[FRU_INFO_MAXLEN]; char ifbi_part_number[FRU_INFO_MAXLEN]; } ipmi_fru_brd_info_t; typedef struct ipmi_fru_prod_info { char ifpi_manuf_name[FRU_INFO_MAXLEN]; char ifpi_product_name[FRU_INFO_MAXLEN]; char ifpi_part_number[FRU_INFO_MAXLEN]; char ifpi_product_version[FRU_INFO_MAXLEN]; char ifpi_product_serial[FRU_INFO_MAXLEN]; char ifpi_asset_tag[FRU_INFO_MAXLEN]; } ipmi_fru_prod_info_t; extern int ipmi_fru_read(ipmi_handle_t *, ipmi_sdr_fru_locator_t *, char **); extern int ipmi_fru_parse_board(ipmi_handle_t *, char *, ipmi_fru_brd_info_t *); extern int ipmi_fru_parse_product(ipmi_handle_t *, char *, ipmi_fru_prod_info_t *); /* * Routines to convert from entity and sensors defines into text strings. */ void ipmi_entity_name(uint8_t, char *, size_t); void ipmi_sensor_type_name(uint8_t, char *, size_t); void ipmi_sensor_units_name(uint8_t, char *, size_t); void ipmi_sensor_reading_name(uint8_t, uint8_t, char *, size_t); /* * Entity management. IPMI has a notion of 'entities', but these are not * directly accessible from any commands. Instead, their existence is inferred * from examining the SDR repository. Since this is rather unwieldy, and * iterating over entities is a common operation, libipmi provides an entity * abstraction that hides the implementation details. This handles entity * groupings as well as SDR associations. */ typedef struct ipmi_entity { uint8_t ie_type; uint8_t ie_instance; uint8_t ie_children; boolean_t ie_logical; } ipmi_entity_t; extern int ipmi_entity_iter(ipmi_handle_t *, int (*)(ipmi_handle_t *, ipmi_entity_t *, void *), void *); extern int ipmi_entity_iter_sdr(ipmi_handle_t *, ipmi_entity_t *, int (*)(ipmi_handle_t *, ipmi_entity_t *, const char *, ipmi_sdr_t *, void *), void *); extern int ipmi_entity_iter_children(ipmi_handle_t *, ipmi_entity_t *, int (*)(ipmi_handle_t *, ipmi_entity_t *, void *), void *); extern ipmi_entity_t *ipmi_entity_lookup(ipmi_handle_t *, uint8_t, uint8_t); extern ipmi_entity_t *ipmi_entity_lookup_sdr(ipmi_handle_t *, const char *); extern ipmi_entity_t *ipmi_entity_parent(ipmi_handle_t *, ipmi_entity_t *); extern int ipmi_entity_present(ipmi_handle_t *, ipmi_entity_t *, boolean_t *); extern int ipmi_entity_present_sdr(ipmi_handle_t *, ipmi_sdr_t *, boolean_t *); /* * User management. The raw functions are private to libipmi, and only the * higher level abstraction (ipmi_user_t) is exported to consumers of the * library. */ #define IPMI_USER_PRIV_CALLBACK 0x1 #define IPMI_USER_PRIV_USER 0x2 #define IPMI_USER_PRIV_OPERATOR 0x3 #define IPMI_USER_PRIV_ADMIN 0x4 #define IPMI_USER_PRIV_OEM 0x5 #define IPMI_USER_PRIV_NONE 0xf typedef struct ipmi_user { uint8_t iu_uid; char *iu_name; boolean_t iu_enabled; boolean_t iu_ipmi_msg_enable; boolean_t iu_link_auth_enable; uint8_t iu_priv; } ipmi_user_t; extern int ipmi_user_iter(ipmi_handle_t *, int (*)(ipmi_user_t *, void *), void *); extern ipmi_user_t *ipmi_user_lookup_name(ipmi_handle_t *, const char *); extern ipmi_user_t *ipmi_user_lookup_id(ipmi_handle_t *, uint8_t); extern int ipmi_user_set_password(ipmi_handle_t *, uint8_t, const char *); /* * The remaining functions are private to the implementation of the Sun ILOM * service processor. These function first check the manufacturer from the IPMI * device ID, and will return EIPMI_NOT_SUPPORTED if attempted for non-Sun * devices. */ boolean_t ipmi_is_sun_ilom(ipmi_deviceid_t *); /* * Sun OEM LED requests. */ #define IPMI_SUNOEM_LED_MODE_OFF 0 #define IPMI_SUNOEM_LED_MODE_ON 1 #define IPMI_SUNOEM_LED_MODE_STANDBY 2 #define IPMI_SUNOEM_LED_MODE_SLOW 3 #define IPMI_SUNOEM_LED_MODE_FAST 4 /* * These functions take a SDR record and construct the appropriate form of the * above commands. */ extern int ipmi_sunoem_led_set(ipmi_handle_t *, ipmi_sdr_generic_locator_t *, uint8_t); extern int ipmi_sunoem_led_get(ipmi_handle_t *, ipmi_sdr_generic_locator_t *, uint8_t *); /* * Sun OEM uptime. Note that the underlying command returns the uptime in big * endian form. This wrapper automatically converts to the appropriate native * form. */ #define IPMI_CMD_SUNOEM_UPTIME 0x08 extern int ipmi_sunoem_uptime(ipmi_handle_t *, uint32_t *, uint32_t *); /* * Sun OEM FRU update. The FRU information is managed through a generic * identifier, and then a type-specific data portion. The wrapper function will * automatically fill in the data length field according to which type is * specified. */ #define IPMI_CMD_SUNOEM_FRU_UPDATE 0x16 #define IPMI_SUNOEM_FRU_DIMM 0x00 #define IPMI_SUNOEM_FRU_CPU 0x01 #define IPMI_SUNOEM_FRU_BIOS 0x02 #define IPMI_SUNOEM_FRU_DISK 0x03 typedef struct ipmi_sunoem_fru { uint8_t isf_type; uint8_t isf_id; uint8_t isf_datalen; union { struct { uint8_t isf_data[128]; } dimm; struct { uint32_t isf_thermtrip; uint32_t isf_eax; char isf_product[48]; } cpu; struct { char isf_part[16]; char isf_version[16]; } bios; struct { char isf_manufacturer[16]; char isf_model[28]; char isf_serial[20]; char isf_version[8]; char isf_capacity[16]; } disk; } isf_data; } ipmi_sunoem_fru_t; int ipmi_sunoem_update_fru(ipmi_handle_t *, ipmi_sunoem_fru_t *); /* * See section 28.2 */ #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 /* * flags for ichs_current_pwr_state field */ #define IPMI_CURR_PWR_STATE_ON 0x01 #define IPMI_CURR_PWR_STATE_OVERLOAD 0x02 #define IPMI_CURR_PWR_STATE_INTERLOCK 0x04 #define IPMI_CURR_PWR_STATE_FAULT 0x08 #define IPMI_CURR_PWR_STATE_CNTL_FAULT 0x10 /* * flags for ichs_last_pwr_state field */ #define IPMI_LAST_PWR_STATE_ACFAILED 0x01 #define IPMI_LAST_PWR_STATE_OVERLOAD 0x02 #define IPMI_LAST_PWR_STATE_INTERLOCK 0x04 #define IPMI_LAST_PWR_STATE_FAULT 0x08 #define IPMI_LAST_PWR_STATE_CMD_ON 0x10 /* * flags for the ichs_pwr_restore_policy field */ #define IPMI_PWR_POLICY_REMAIN_OFF 0x0 #define IPMI_PWR_POLICY_RESTORE 0x1 #define IPMI_PWR_POLICY_POWER_ON 0x2 #define IPMI_PWR_POLICY_UNKNOWN 0x3 typedef struct ipmi_chassis_status { DECL_BITFIELD3( ichs_current_pwr_state :5, ichs_pwr_restore_policy :2, __reserved1 :1); DECL_BITFIELD2( ichs_last_pwr_state :5, __reserved2 :3); DECL_BITFIELD7( ichs_intrusion_asserted :1, ichs_front_panel_disabled :1, ichs_drive_fault_asserted :1, ichs_fan_fault_asserted :1, ichs_identify_state :2, ichs_identify_supported :1, __reserved3 :1); } ipmi_chassis_status_t; extern ipmi_chassis_status_t *ipmi_chassis_status(ipmi_handle_t *); /* * See section 28.5 */ #define IPMI_CMD_CHASSIS_IDENTIFY 0x04 int ipmi_chassis_identify(ipmi_handle_t *, boolean_t); #pragma pack() #ifdef __cplusplus } #endif #endif /* _LIBIPMI_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # # # Copyright (c) 2018, Joyent, Inc. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: ipmi_chassis_identify; ipmi_chassis_status; ipmi_close; ipmi_entity_iter; ipmi_entity_iter_children; ipmi_entity_iter_sdr; ipmi_entity_lookup; ipmi_entity_lookup_sdr; ipmi_entity_name; ipmi_entity_parent; ipmi_entity_present; ipmi_entity_present_sdr; ipmi_errmsg; ipmi_errno; ipmi_event_platform_message; ipmi_firmware_version; ipmi_fru_parse_board; ipmi_fru_parse_product; ipmi_fru_read; ipmi_get_channel_info; ipmi_get_deviceid; ipmi_get_sensor_reading; ipmi_get_sensor_thresholds; ipmi_is_sun_ilom; ipmi_lan_get_config; ipmi_lan_set_config; ipmi_open; ipmi_sdr_changed; ipmi_sdr_conv_reading; ipmi_sdr_get; ipmi_sdr_iter; ipmi_sdr_lookup; ipmi_sdr_lookup_compact_sensor; ipmi_sdr_lookup_full_sensor; ipmi_sdr_lookup_fru; ipmi_sdr_lookup_generic; ipmi_sdr_lookup_precise; ipmi_sdr_refresh; ipmi_sel_get_entry; ipmi_sel_get_info; ipmi_sel_get_time; ipmi_sel_get_utc_offset; ipmi_sel_set_time; ipmi_sel_set_utc_offset; ipmi_sensor_reading_name; ipmi_sensor_type_name; ipmi_sensor_units_name; ipmi_send; ipmi_set_sensor_reading; ipmi_sunoem_led_get; ipmi_sunoem_led_set; ipmi_sunoem_update_fru; ipmi_sunoem_uptime; ipmi_user_iter; ipmi_user_lookup_id; ipmi_user_lookup_name; ipmi_user_set_password; local: *; }; #!/bin/ksh93 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # Construct translation tables for defines in libipmi.h to translate to readable # strings. # if [ $# -ne 1 ]; then echo >&2 "USAGE: $0 " exit 1 fi if [ -r $1 ]; then libipmi_h=$1 else echo >&2 "USAGE: $0 " echo >&2 "Make sure libipmi.h exists and is readable" exit 1 fi echo "\ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include " # # Error table. # echo " ipmi_name_trans_t ipmi_errno_table[] = {" pattern=" \(EIPMI_[0-9A-Z_]*\)[^ \/]*\/\* \(.*\) \*\/$" replace=" { \1, \"\2\" }," cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1 echo "\t{ 0, NULL } };" # # Entity table. # echo "\nipmi_name_trans_t ipmi_entity_table[] = {" pattern="#define IPMI_ET_\([A-Z0-9_]*\).*\$" replace=" { IPMI_ET_\1, \"\1\" }," cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1 echo "\t{ 0, NULL } };" # # Sensor types. # echo "\nipmi_name_trans_t ipmi_sensor_type_table[] = {" pattern="#define IPMI_ST_\([A-Z0-9_]*\).*\$" replace=" { IPMI_ST_\1, \"\1\" }," cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1 echo "\t{ 0, NULL } };" # # Reading types. # echo "\nipmi_name_trans_t ipmi_reading_type_table[] = {" pattern="#define IPMI_RT_\([A-Z0-9_]*\).*\$" replace=" { IPMI_RT_\1, \"\1\" }," cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1 echo "\t{ 0, NULL } };" # # Units # echo "\nipmi_name_trans_t ipmi_units_type_table[] = {" pattern="#define IPMI_UNITS_\([A-Z0-9_]*\).*\$" replace=" { IPMI_UNITS_\1, \"\1\" }," cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1 echo "\t{ 0, NULL } };"