xref: /titanic_52/usr/src/lib/libipmi/common/ipmi_misc.c (revision aec67356a48549d11b3a8a0b63410d67e5e90090)
19113a79cSeschrock /*
29113a79cSeschrock  * CDDL HEADER START
39113a79cSeschrock  *
49113a79cSeschrock  * The contents of this file are subject to the terms of the
59113a79cSeschrock  * Common Development and Distribution License (the "License").
69113a79cSeschrock  * You may not use this file except in compliance with the License.
79113a79cSeschrock  *
89113a79cSeschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99113a79cSeschrock  * or http://www.opensolaris.org/os/licensing.
109113a79cSeschrock  * See the License for the specific language governing permissions
119113a79cSeschrock  * and limitations under the License.
129113a79cSeschrock  *
139113a79cSeschrock  * When distributing Covered Code, include this CDDL HEADER in each
149113a79cSeschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159113a79cSeschrock  * If applicable, add the following below this CDDL HEADER, with the
169113a79cSeschrock  * fields enclosed by brackets "[]" replaced with your own identifying
179113a79cSeschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
189113a79cSeschrock  *
199113a79cSeschrock  * CDDL HEADER END
209113a79cSeschrock  */
219113a79cSeschrock /*
22*aec67356SRobert Johnston  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
239113a79cSeschrock  */
249113a79cSeschrock 
259113a79cSeschrock #include <libipmi.h>
262eeaed14Srobj #include <stdio.h>
279113a79cSeschrock #include <string.h>
289113a79cSeschrock 
299113a79cSeschrock #include "ipmi_impl.h"
309113a79cSeschrock 
319113a79cSeschrock ipmi_deviceid_t *
329113a79cSeschrock ipmi_get_deviceid(ipmi_handle_t *ihp)
339113a79cSeschrock {
349113a79cSeschrock 	ipmi_cmd_t cmd, *resp;
35918a0d8aSrobj 	uint16_t id_prod;
369113a79cSeschrock 
372eeaed14Srobj 	if (ihp->ih_deviceid != NULL)
382eeaed14Srobj 		return (ihp->ih_deviceid);
399113a79cSeschrock 
409113a79cSeschrock 	cmd.ic_netfn = IPMI_NETFN_APP;
419113a79cSeschrock 	cmd.ic_lun = 0;
429113a79cSeschrock 	cmd.ic_cmd = IPMI_CMD_GET_DEVICEID;
439113a79cSeschrock 	cmd.ic_data = NULL;
449113a79cSeschrock 	cmd.ic_dlen = 0;
459113a79cSeschrock 
469113a79cSeschrock 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
479113a79cSeschrock 		return (NULL);
489113a79cSeschrock 
499113a79cSeschrock 	if (resp->ic_dlen < sizeof (ipmi_deviceid_t)) {
509113a79cSeschrock 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
519113a79cSeschrock 		return (NULL);
529113a79cSeschrock 	}
539113a79cSeschrock 
542eeaed14Srobj 	/*
552eeaed14Srobj 	 * The devid response data may include additional data beyond the end of
562eeaed14Srobj 	 * the normal structure, so we copy the entire response.
572eeaed14Srobj 	 */
582eeaed14Srobj 	if ((ihp->ih_deviceid = ipmi_alloc(ihp, resp->ic_dlen)) == NULL)
592eeaed14Srobj 		return (NULL);
609113a79cSeschrock 
612eeaed14Srobj 	(void) memcpy(ihp->ih_deviceid, resp->ic_data, resp->ic_dlen);
62918a0d8aSrobj 	id_prod = LE_IN16(&ihp->ih_deviceid->id_product);
63e1a24155Srobj 	(void) memcpy(&ihp->ih_deviceid->id_product, &id_prod,
64918a0d8aSrobj 	    sizeof (id_prod));
652eeaed14Srobj 	ihp->ih_deviceid_len = resp->ic_dlen;
662eeaed14Srobj 
672eeaed14Srobj 	return (ihp->ih_deviceid);
682eeaed14Srobj }
692eeaed14Srobj 
702eeaed14Srobj /*
712eeaed14Srobj  * Returns the firmware revision as a string.  This does the work of converting
722eeaed14Srobj  * the deviceid data into a human readable string (decoding the BCD values).
732eeaed14Srobj  * It also encodes the fact that Sun ILOM includes the additional micro revision
742eeaed14Srobj  * at the end of the deviceid information.
752eeaed14Srobj  */
762eeaed14Srobj const char *
772eeaed14Srobj ipmi_firmware_version(ipmi_handle_t *ihp)
782eeaed14Srobj {
792eeaed14Srobj 	ipmi_deviceid_t *dp;
802eeaed14Srobj 	uint8_t *auxrev;
812eeaed14Srobj 	size_t len;
822eeaed14Srobj 	char rev[128];
832eeaed14Srobj 	int i;
842eeaed14Srobj 
852eeaed14Srobj 	if (ihp->ih_firmware_rev != NULL)
862eeaed14Srobj 		return (ihp->ih_firmware_rev);
872eeaed14Srobj 
882eeaed14Srobj 	if ((dp = ipmi_get_deviceid(ihp)) == NULL)
892eeaed14Srobj 		return (NULL);
902eeaed14Srobj 
912eeaed14Srobj 	/*
922eeaed14Srobj 	 * Start with the major an minor revision numbers
932eeaed14Srobj 	 */
942eeaed14Srobj 	(void) snprintf(rev, sizeof (rev), "%d.%d", dp->id_firm_major,
952eeaed14Srobj 	    ipmi_convert_bcd(dp->id_firm_minor));
962eeaed14Srobj 
972eeaed14Srobj 	if (ipmi_is_sun_ilom(dp) &&
982eeaed14Srobj 	    ihp->ih_deviceid_len >= sizeof (ipmi_deviceid_t) + 4) {
992eeaed14Srobj 		/*
1002eeaed14Srobj 		 * With Sun ILOM we have the micro revision at the end of the
1012eeaed14Srobj 		 * deviceid.  The first two bytes of the aux revision field are
1022eeaed14Srobj 		 * the platform version and release version.
1032eeaed14Srobj 		 */
1042eeaed14Srobj 		auxrev = (uint8_t *)dp + sizeof (ipmi_deviceid_t);
1052eeaed14Srobj 		for (i = 0; i < 2; i++) {
1062eeaed14Srobj 			if (auxrev[i] == 0)
1072eeaed14Srobj 				continue;
1082eeaed14Srobj 
1092eeaed14Srobj 			len = strlen(rev);
1102eeaed14Srobj 			(void) snprintf(rev + len, sizeof (rev) - len, ".%u",
1112eeaed14Srobj 			    auxrev[i]);
1122eeaed14Srobj 		}
1132eeaed14Srobj 	}
1142eeaed14Srobj 
1152eeaed14Srobj 	if ((ihp->ih_firmware_rev = ipmi_strdup(ihp, rev)) == NULL)
1162eeaed14Srobj 		return (NULL);
1172eeaed14Srobj 
1182eeaed14Srobj 	return (ihp->ih_firmware_rev);
1199113a79cSeschrock }
120283bfb4dSEric Schrock 
12181d9f076SRobert Johnston /*
12281d9f076SRobert Johnston  * IPMI Get Channel Authentication Capabilities Command
12381d9f076SRobert Johnston  * See Section 22.13
12481d9f076SRobert Johnston  *
12581d9f076SRobert Johnston  * Caller is responsible for free'ing returned ipmi_channel_auth_caps_t
12681d9f076SRobert Johnston  */
12781d9f076SRobert Johnston ipmi_channel_auth_caps_t *
12881d9f076SRobert Johnston ipmi_get_channel_auth_caps(ipmi_handle_t *ihp, uint8_t channel, uint8_t priv)
12981d9f076SRobert Johnston {
13081d9f076SRobert Johnston 	ipmi_cmd_t cmd, *resp;
13181d9f076SRobert Johnston 	uint8_t msg_data[2];
13281d9f076SRobert Johnston 	ipmi_channel_auth_caps_t *caps;
13381d9f076SRobert Johnston 
13481d9f076SRobert Johnston 	if (channel > 0xF) {
13581d9f076SRobert Johnston 		(void) ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, NULL);
13681d9f076SRobert Johnston 		return (NULL);
13781d9f076SRobert Johnston 	}
13881d9f076SRobert Johnston 
13981d9f076SRobert Johnston 	msg_data[0] = channel;
14081d9f076SRobert Johnston 	msg_data[1] = priv;
14181d9f076SRobert Johnston 
14281d9f076SRobert Johnston 	cmd.ic_netfn = IPMI_NETFN_APP;
14381d9f076SRobert Johnston 	cmd.ic_cmd = IPMI_CMD_GET_CHANNEL_AUTH_CAPS;
14481d9f076SRobert Johnston 	cmd.ic_data = msg_data;
14581d9f076SRobert Johnston 	cmd.ic_dlen = sizeof (msg_data);
14681d9f076SRobert Johnston 	cmd.ic_lun = 0;
14781d9f076SRobert Johnston 
14881d9f076SRobert Johnston 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
14981d9f076SRobert Johnston 		return (NULL);
15081d9f076SRobert Johnston 
15181d9f076SRobert Johnston 	if (resp->ic_dlen < sizeof (ipmi_channel_auth_caps_t)) {
15281d9f076SRobert Johnston 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
15381d9f076SRobert Johnston 		return (NULL);
15481d9f076SRobert Johnston 	}
15581d9f076SRobert Johnston 
15681d9f076SRobert Johnston 	if ((caps = ipmi_alloc(ihp, sizeof (ipmi_channel_auth_caps_t)))
15781d9f076SRobert Johnston 	    == NULL)
15881d9f076SRobert Johnston 		/* ipmi errno set */
15981d9f076SRobert Johnston 		return (NULL);
16081d9f076SRobert Johnston 
16181d9f076SRobert Johnston 	(void) memcpy(caps, resp->ic_data, sizeof (ipmi_channel_auth_caps_t));
16281d9f076SRobert Johnston 
16381d9f076SRobert Johnston 	return (caps);
16481d9f076SRobert Johnston }
16581d9f076SRobert Johnston 
166283bfb4dSEric Schrock ipmi_channel_info_t *
167283bfb4dSEric Schrock ipmi_get_channel_info(ipmi_handle_t *ihp, int number)
168283bfb4dSEric Schrock {
169283bfb4dSEric Schrock 	ipmi_cmd_t cmd, *rsp;
170283bfb4dSEric Schrock 	uint8_t channel;
171283bfb4dSEric Schrock 
172283bfb4dSEric Schrock 	if (number > 0xF) {
173283bfb4dSEric Schrock 		(void) ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, NULL);
174283bfb4dSEric Schrock 		return (NULL);
175283bfb4dSEric Schrock 	}
176283bfb4dSEric Schrock 
177283bfb4dSEric Schrock 	channel = (uint8_t)number;
178283bfb4dSEric Schrock 
179283bfb4dSEric Schrock 	cmd.ic_netfn = IPMI_NETFN_APP;
180283bfb4dSEric Schrock 	cmd.ic_lun = 0;
181283bfb4dSEric Schrock 	cmd.ic_cmd = IPMI_CMD_GET_CHANNEL_INFO;
182283bfb4dSEric Schrock 	cmd.ic_data = &channel;
183283bfb4dSEric Schrock 	cmd.ic_dlen = sizeof (channel);
184283bfb4dSEric Schrock 
185283bfb4dSEric Schrock 	if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
186283bfb4dSEric Schrock 		return (NULL);
187283bfb4dSEric Schrock 
188283bfb4dSEric Schrock 	if (rsp->ic_dlen < sizeof (ipmi_channel_info_t)) {
189283bfb4dSEric Schrock 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
190283bfb4dSEric Schrock 		return (NULL);
191283bfb4dSEric Schrock 	}
192283bfb4dSEric Schrock 
193283bfb4dSEric Schrock 	return (rsp->ic_data);
194283bfb4dSEric Schrock }
195*aec67356SRobert Johnston 
196*aec67356SRobert Johnston /*
197*aec67356SRobert Johnston  * IPMI Chassis Identify Command
198*aec67356SRobert Johnston  * See Section 28.5
199*aec67356SRobert Johnston  */
200*aec67356SRobert Johnston int
201*aec67356SRobert Johnston ipmi_chassis_identify(ipmi_handle_t *ihp, boolean_t enable)
202*aec67356SRobert Johnston {
203*aec67356SRobert Johnston 	ipmi_cmd_t cmd;
204*aec67356SRobert Johnston 	uint8_t msg_data[2];
205*aec67356SRobert Johnston 
206*aec67356SRobert Johnston 	if (enable) {
207*aec67356SRobert Johnston 		msg_data[0] = 0;
208*aec67356SRobert Johnston 		msg_data[1] = 1;
209*aec67356SRobert Johnston 	} else {
210*aec67356SRobert Johnston 		msg_data[0] = 0;
211*aec67356SRobert Johnston 		msg_data[1] = 0;
212*aec67356SRobert Johnston 	}
213*aec67356SRobert Johnston 
214*aec67356SRobert Johnston 	cmd.ic_netfn = IPMI_NETFN_CHASSIS;
215*aec67356SRobert Johnston 	cmd.ic_cmd = IPMI_CMD_CHASSIS_IDENTIFY;
216*aec67356SRobert Johnston 	cmd.ic_data = msg_data;
217*aec67356SRobert Johnston 	cmd.ic_dlen = sizeof (msg_data);
218*aec67356SRobert Johnston 	cmd.ic_lun = 0;
219*aec67356SRobert Johnston 
220*aec67356SRobert Johnston 	if (ipmi_send(ihp, &cmd) == NULL)
221*aec67356SRobert Johnston 		return (-1);
222*aec67356SRobert Johnston 
223*aec67356SRobert Johnston 	return (0);
224*aec67356SRobert Johnston }
225