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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Read the SDR information on a board and get the device id to 31 * read the FRUID information 32 */ 33 34 #include <stdio.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <errno.h> 39 #include <time.h> 40 #include <poll.h> 41 #include <stropts.h> 42 #include <stdarg.h> 43 #include <syslog.h> 44 #include <smclib.h> 45 #include "fru_access_impl.h" 46 47 #define POLL_TIMEOUT 10000 /* 20 sec */ 48 #define SEQUENCE 10 49 50 #define IPMI_GET_SDR_INFO 0x20 51 #define IPMI_SENSOR_NETFN 0x4 52 #define SDR_INFO_RESPONSE_SZ_MIN 10 53 54 #define NUM_OF_LUN 4 55 #define SUN_FRU "SUN FRU SDR" 56 #define FRU_DEVICE_SDR_TYPE 0x11 57 #define IPMI_SDR_VERSION 0x51 58 #define IPMI_DATA_OFFSET 7 59 #define IPMI_GET_SDR_INFO_CMD 0x20 60 #define SDR_BUFFER_LEN_MAX 100 61 62 typedef struct { 63 uint8_t src; 64 uint8_t dest; 65 uint8_t lun; 66 uint8_t record_id_lsb; 67 uint8_t record_id_msb; 68 int offset; 69 int length; 70 char *buffer; 71 } sdr_info_t; 72 73 static int get_sdr_info(int, int, uint8_t lun); 74 static int get_sdr(sdr_info_t *); 75 static int get_sun_sdr(int, uint8_t, uint8_t, uint8_t); 76 77 /* 78 * bug in smc f/w 79 * 80 * static int lun_mask[4] = { 0x01, 0x02, 0x04, 0x08 }; 81 */ 82 83 /* 84 * routine to read the onboard/remote device SDR information 85 */ 86 void 87 get_fru_data_info(int src, int dest, format_t *fru_format) 88 { 89 int ret; 90 91 src = IPMB_ADDR(src); 92 dest = IPMB_ADDR(dest); 93 94 if (src != dest) { /* ipmi */ 95 int i = 0; 96 for (i = 0; i < NUM_OF_LUN; i++) { /* for each lun */ 97 ret = get_sdr_info(src, dest, i); 98 if (ret > 0) { 99 ret = get_sun_sdr(ret, src, dest, i); 100 if (ret > 0) { 101 fru_format->format |= SUN_FORMAT; 102 fru_format->sun_device_id = ret; 103 fru_format->sun_lun = i; 104 break; 105 } 106 } 107 } 108 } else { /* on board */ 109 ret = get_sdr_info(src, dest, 0); 110 if (ret > 0) { 111 ret = get_sun_sdr(ret, src, dest, 0); 112 if (ret > 0) { 113 fru_format->format |= SUN_FORMAT; 114 fru_format->sun_device_id = ret; 115 fru_format->sun_lun = 0; 116 } 117 } 118 } 119 } 120 121 /* 122 * read the onboard sdr information 123 */ 124 static int 125 get_onboard_sdr(sdr_info_t *sdr) 126 { 127 sc_reqmsg_t req_pkt; 128 sc_rspmsg_t res_pkt; 129 130 SC_MSG_CMD(&req_pkt) = SMC_DEVICE_SDR_GET; 131 SC_MSG_LEN(&req_pkt) = 6; 132 SC_MSG_ID(&req_pkt) = SEQUENCE; 133 134 /* data for request packet */ 135 req_pkt.data[0] = 0x0; 136 req_pkt.data[1] = 0x0; 137 req_pkt.data[2] = sdr->record_id_lsb; 138 req_pkt.data[3] = sdr->record_id_msb; 139 req_pkt.data[4] = sdr->offset; 140 req_pkt.data[5] = sdr->length; 141 142 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt, 143 POLL_TIMEOUT) != SMC_SUCCESS) { 144 return (-1); 145 } 146 147 bzero(sdr->buffer, SDR_BUFFER_LEN_MAX); 148 (void) memcpy(sdr->buffer, res_pkt.data, res_pkt.hdr.len); 149 return (0); 150 } 151 152 /* 153 * get the sdr information 154 */ 155 static int 156 get_sdr_info(int src, int dest, uint8_t lun) 157 { 158 sc_reqmsg_t req_pkt; 159 sc_rspmsg_t res_pkt; 160 161 if (lun >= NUM_OF_LUN) { 162 return (-1); 163 } 164 165 if (src == dest) { /* onboard */ 166 SC_MSG_CMD(&req_pkt) = SMC_DEVICE_SDR_INFO_GET; 167 SC_MSG_LEN(&req_pkt) = 0; 168 SC_MSG_ID(&req_pkt) = SEQUENCE; 169 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt, 170 POLL_TIMEOUT) != SMC_SUCCESS) { 171 return (-1); 172 } 173 return (res_pkt.data[0]); 174 } 175 176 /* ipmb access */ 177 (void) smc_init_ipmi_msg(&req_pkt, IPMI_GET_SDR_INFO_CMD, 178 FRUACCESS_MSG_ID, 0, NULL, DEFAULT_SEQN, dest, 179 SMC_NETFN_SENSOR_REQ, lun); 180 181 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt, 182 POLL_TIMEOUT) != SMC_SUCCESS) { 183 return (-1); 184 } 185 186 /* completion code */ 187 if (res_pkt.data[IPMI_DATA_OFFSET] != 0) { 188 return (-1); 189 } 190 191 /* 192 * Known bug in SMC f/w. take this out for next release 193 * if ((res_pkt.data[IPMI_DATA_OFFSET + 2] & lun_mask[lun]) != 1) { 194 * return (0); 195 * } 196 */ 197 return (res_pkt.data[IPMI_DATA_OFFSET + 1]); 198 } 199 200 static int 201 get_sun_sdr(int num_records, uint8_t src, uint8_t dest, uint8_t lun) 202 { 203 int i, ret; 204 sdr_info_t sdr; 205 char data[SDR_BUFFER_LEN_MAX]; 206 uint8_t next_record_lsb; 207 uint8_t next_record_msb; 208 209 sdr.src = src; 210 sdr.dest = dest; 211 sdr.lun = lun; 212 sdr.buffer = data; 213 214 /* get the first record info */ 215 next_record_lsb = 0x0; 216 next_record_msb = 0x0; 217 sdr.length = 4; 218 sdr.offset = 0x0; 219 220 if (src == dest) { /* onboard */ 221 for (i = 0; i < num_records; i++) { 222 sdr.record_id_lsb = next_record_lsb; 223 sdr.record_id_msb = next_record_msb; 224 225 if ((ret = get_onboard_sdr(&sdr)) < 0) { 226 return (ret); 227 } 228 229 next_record_lsb = data[0]; 230 next_record_msb = data[1]; 231 if (data[4] != IPMI_SDR_VERSION) { 232 return (-1); 233 } 234 235 if (data[5] == FRU_DEVICE_SDR_TYPE) { 236 sdr.offset = 0x10; 237 sdr.length = strlen(SUN_FRU); 238 if ((ret = get_onboard_sdr(&sdr)) < 0) { 239 return (ret); 240 } 241 242 /* first two bytes of response is reserv. id */ 243 if (strncmp(SUN_FRU, &data[2], 244 strlen(SUN_FRU)) == 0) { 245 /* found sun sdr */ 246 sdr.offset = 0x0; 247 sdr.length = 7; 248 if ((ret = get_onboard_sdr(&sdr)) < 0) { 249 return (ret); 250 } 251 return (data[8]); 252 } 253 } 254 } 255 return (-1); 256 } 257 258 /* ipmb access */ 259 /* traverse thru all the records until we find sun sdr */ 260 for (i = 0; i < num_records; i++) { 261 262 sdr.record_id_lsb = next_record_lsb; 263 sdr.record_id_msb = next_record_msb; 264 265 if ((ret = get_sdr(&sdr)) < 0) { 266 return (ret); 267 } 268 269 /* completion code */ 270 if (data[IPMI_DATA_OFFSET] != 0) { 271 return (-1); 272 } 273 next_record_lsb = data[IPMI_DATA_OFFSET + 1]; 274 next_record_msb = data[IPMI_DATA_OFFSET + 2]; 275 276 if (data[IPMI_DATA_OFFSET + 5] != IPMI_SDR_VERSION) { 277 return (-1); 278 } 279 280 if (data[IPMI_DATA_OFFSET + 6] == FRU_DEVICE_SDR_TYPE) { 281 282 sdr.offset = 0x10; 283 sdr.length = strlen(SUN_FRU); 284 if ((ret = get_sdr(&sdr)) < 0) { 285 return (ret); 286 } 287 288 /* completion code */ 289 if (data[IPMI_DATA_OFFSET] != 0) { 290 return (-1); 291 } 292 293 if (strncmp(&data[IPMI_DATA_OFFSET+ 3], 294 SUN_FRU, strlen(SUN_FRU)) == 0) { 295 /* found sun sdr */ 296 sdr.offset = 0x0; 297 sdr.length = 7; 298 if ((ret = get_sdr(&sdr)) < 0) { 299 return (ret); 300 } 301 302 /* completion code */ 303 if (data[IPMI_DATA_OFFSET] != 0) { 304 return (-1); 305 } 306 return (data[IPMI_DATA_OFFSET + 9]); 307 } 308 } 309 } 310 return (-1); 311 } 312 313 static int 314 get_sdr(sdr_info_t *sdr) 315 { 316 sc_reqmsg_t req_pkt; 317 sc_rspmsg_t res_pkt; 318 uint8_t datap[6]; 319 320 if (sdr->lun > 3) { 321 return (-1); 322 } 323 324 /* data for request packet */ 325 datap[0] = 0x0; /* reserved */ 326 datap[1] = 0x0; /* reserved */ 327 datap[2] = sdr->record_id_lsb; 328 datap[3] = sdr->record_id_msb; 329 datap[4] = sdr->offset; 330 datap[5] = sdr->length; 331 332 (void) smc_init_ipmi_msg(&req_pkt, SMC_GET_DEVICE_SDR, 333 FRUACCESS_MSG_ID, 6, datap, DEFAULT_SEQN, 334 sdr->dest, SMC_NETFN_SENSOR_REQ, sdr->lun); 335 336 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt, 337 POLL_TIMEOUT) != SMC_SUCCESS) { 338 return (-1); 339 } 340 bzero(sdr->buffer, SDR_BUFFER_LEN_MAX); 341 (void) memcpy(sdr->buffer, res_pkt.data, res_pkt.hdr.len); 342 return (0); 343 }