1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2017, Joyent, Inc. 24 */ 25 #include <libipmi.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 #include "ipmi_impl.h" 30 31 ipmi_deviceid_t * 32 ipmi_get_deviceid(ipmi_handle_t *ihp) 33 { 34 ipmi_cmd_t cmd, *resp; 35 uint16_t id_prod; 36 37 if (ihp->ih_deviceid != NULL) 38 return (ihp->ih_deviceid); 39 40 cmd.ic_netfn = IPMI_NETFN_APP; 41 cmd.ic_lun = 0; 42 cmd.ic_cmd = IPMI_CMD_GET_DEVICEID; 43 cmd.ic_data = NULL; 44 cmd.ic_dlen = 0; 45 46 if ((resp = ipmi_send(ihp, &cmd)) == NULL) 47 return (NULL); 48 49 if (resp->ic_dlen < sizeof (ipmi_deviceid_t)) { 50 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 51 return (NULL); 52 } 53 54 /* 55 * The devid response data may include additional data beyond the end of 56 * the normal structure, so we copy the entire response. 57 */ 58 if ((ihp->ih_deviceid = ipmi_alloc(ihp, resp->ic_dlen)) == NULL) 59 return (NULL); 60 61 (void) memcpy(ihp->ih_deviceid, resp->ic_data, resp->ic_dlen); 62 id_prod = LE_IN16(&ihp->ih_deviceid->id_product); 63 (void) memcpy(&ihp->ih_deviceid->id_product, &id_prod, 64 sizeof (id_prod)); 65 ihp->ih_deviceid_len = resp->ic_dlen; 66 67 return (ihp->ih_deviceid); 68 } 69 70 /* 71 * Returns the firmware revision as a string. This does the work of converting 72 * the deviceid data into a human readable string (decoding the BCD values). 73 * It also encodes the fact that Sun ILOM includes the additional micro revision 74 * at the end of the deviceid information. 75 */ 76 const char * 77 ipmi_firmware_version(ipmi_handle_t *ihp) 78 { 79 ipmi_deviceid_t *dp; 80 uint8_t *auxrev; 81 size_t len; 82 char rev[128]; 83 int i; 84 85 if (ihp->ih_firmware_rev != NULL) 86 return (ihp->ih_firmware_rev); 87 88 if ((dp = ipmi_get_deviceid(ihp)) == NULL) 89 return (NULL); 90 91 /* 92 * Start with the major an minor revision numbers 93 */ 94 (void) snprintf(rev, sizeof (rev), "%d.%d", dp->id_firm_major, 95 ipmi_convert_bcd(dp->id_firm_minor)); 96 97 if (ipmi_is_sun_ilom(dp) && 98 ihp->ih_deviceid_len >= sizeof (ipmi_deviceid_t) + 4) { 99 /* 100 * With Sun ILOM we have the micro revision at the end of the 101 * deviceid. The first two bytes of the aux revision field are 102 * the platform version and release version. 103 */ 104 auxrev = (uint8_t *)dp + sizeof (ipmi_deviceid_t); 105 for (i = 0; i < 2; i++) { 106 if (auxrev[i] == 0) 107 continue; 108 109 len = strlen(rev); 110 (void) snprintf(rev + len, sizeof (rev) - len, ".%u", 111 auxrev[i]); 112 } 113 } 114 115 if ((ihp->ih_firmware_rev = ipmi_strdup(ihp, rev)) == NULL) 116 return (NULL); 117 118 return (ihp->ih_firmware_rev); 119 } 120 121 /* 122 * IPMI Get Channel Authentication Capabilities Command 123 * See Section 22.13 124 * 125 * Caller is responsible for free'ing returned ipmi_channel_auth_caps_t 126 */ 127 ipmi_channel_auth_caps_t * 128 ipmi_get_channel_auth_caps(ipmi_handle_t *ihp, uint8_t channel, uint8_t priv) 129 { 130 ipmi_cmd_t cmd, *resp; 131 uint8_t msg_data[2]; 132 ipmi_channel_auth_caps_t *caps; 133 134 if (channel > 0xF) { 135 (void) ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, NULL); 136 return (NULL); 137 } 138 139 msg_data[0] = channel; 140 msg_data[1] = priv; 141 142 cmd.ic_netfn = IPMI_NETFN_APP; 143 cmd.ic_cmd = IPMI_CMD_GET_CHANNEL_AUTH_CAPS; 144 cmd.ic_data = msg_data; 145 cmd.ic_dlen = sizeof (msg_data); 146 cmd.ic_lun = 0; 147 148 if ((resp = ipmi_send(ihp, &cmd)) == NULL) 149 return (NULL); 150 151 if (resp->ic_dlen < sizeof (ipmi_channel_auth_caps_t)) { 152 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 153 return (NULL); 154 } 155 156 if ((caps = ipmi_alloc(ihp, sizeof (ipmi_channel_auth_caps_t))) 157 == NULL) 158 /* ipmi errno set */ 159 return (NULL); 160 161 (void) memcpy(caps, resp->ic_data, sizeof (ipmi_channel_auth_caps_t)); 162 163 return (caps); 164 } 165 166 ipmi_channel_info_t * 167 ipmi_get_channel_info(ipmi_handle_t *ihp, int number) 168 { 169 ipmi_cmd_t cmd, *rsp; 170 uint8_t channel; 171 172 if (number > 0xF) { 173 (void) ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, NULL); 174 return (NULL); 175 } 176 177 channel = (uint8_t)number; 178 179 cmd.ic_netfn = IPMI_NETFN_APP; 180 cmd.ic_lun = 0; 181 cmd.ic_cmd = IPMI_CMD_GET_CHANNEL_INFO; 182 cmd.ic_data = &channel; 183 cmd.ic_dlen = sizeof (channel); 184 185 if ((rsp = ipmi_send(ihp, &cmd)) == NULL) 186 return (NULL); 187 188 if (rsp->ic_dlen < sizeof (ipmi_channel_info_t)) { 189 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 190 return (NULL); 191 } 192 193 return (rsp->ic_data); 194 } 195 196 /* 197 * IPMI Chassis Identify Command 198 * See Section 28.5 199 */ 200 int 201 ipmi_chassis_identify(ipmi_handle_t *ihp, boolean_t enable) 202 { 203 ipmi_cmd_t cmd; 204 uint8_t msg_data[2]; 205 206 if (enable) { 207 msg_data[0] = 0; 208 msg_data[1] = 1; 209 } else { 210 msg_data[0] = 0; 211 msg_data[1] = 0; 212 } 213 214 cmd.ic_netfn = IPMI_NETFN_CHASSIS; 215 cmd.ic_cmd = IPMI_CMD_CHASSIS_IDENTIFY; 216 cmd.ic_data = msg_data; 217 cmd.ic_dlen = sizeof (msg_data); 218 cmd.ic_lun = 0; 219 220 if (ipmi_send(ihp, &cmd) == NULL) 221 return (-1); 222 223 return (0); 224 } 225 226 /* 227 * caller is responsible for free'ing returned structure 228 */ 229 ipmi_chassis_status_t * 230 ipmi_chassis_status(ipmi_handle_t *ihp) 231 { 232 ipmi_cmd_t cmd, *rsp; 233 ipmi_chassis_status_t *chs; 234 235 cmd.ic_netfn = IPMI_NETFN_CHASSIS; 236 cmd.ic_lun = 0; 237 cmd.ic_cmd = IPMI_CMD_GET_CHASSIS_STATUS; 238 cmd.ic_data = NULL; 239 cmd.ic_dlen = 0; 240 241 if ((rsp = ipmi_send(ihp, &cmd)) == NULL) 242 return (NULL); 243 244 if (rsp->ic_dlen < sizeof (ipmi_chassis_status_t)) { 245 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 246 return (NULL); 247 } 248 249 if ((chs = ipmi_alloc(ihp, sizeof (ipmi_chassis_status_t))) == NULL) { 250 /* ipmi errno set */ 251 return (NULL); 252 } 253 254 (void) memcpy(chs, rsp->ic_data, sizeof (ipmi_chassis_status_t)); 255 return (chs); 256 } 257