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 /* 23 * Copyright 2008 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 #include <string.h> 30 #include <strings.h> 31 32 #include <scsi/libses.h> 33 #include <scsi/libses_plugin.h> 34 35 #pragma pack(1) 36 37 typedef struct ses_riverwalk_stringin { 38 uint8_t rws_download_status; 39 uint8_t rws_descriptor_start; 40 uint16_t rws_descriptor_length; 41 char rws_sim0_id[4]; 42 char rws_sim0_pn[15]; 43 char rws_sim0_sn[20]; 44 char rws_sim1_id[4]; 45 char rws_sim1_pn[15]; 46 char rws_sim1_sn[20]; 47 char rws_mid_id[4]; 48 char rws_mid_pn[15]; 49 char rws_mid_sn[20]; 50 char rws_ps0_id[4]; 51 char rws_ps0_pn[15]; 52 char rws_ps0_sn[20]; 53 char rws_ps1_id[4]; 54 char rws_ps1_pn[15]; 55 char rws_ps1_sn[20]; 56 char __reserved1[29]; 57 uint8_t rws_diag_start; 58 uint8_t rws_eid; 59 uint16_t rws_diag_length; 60 uint8_t rws_sim_id; 61 uint8_t rws_numport; 62 uint16_t __reserved2; 63 uint8_t rws_sasaddr[8]; 64 uint8_t rws_sys_sn[8]; 65 char rws_port0[16]; 66 char rws_port1[16]; 67 char rws_port2[16]; 68 } ses_riverwalk_stringin_t; 69 70 #pragma pack() 71 72 /*ARGSUSED*/ 73 static int 74 sun_riverwalk_parse_node(ses_plugin_t *sp, ses_node_t *np) 75 { 76 nvlist_t *props = ses_node_props(np); 77 int nverr; 78 ses_riverwalk_stringin_t *strp; 79 char buf[32]; 80 uint64_t type, index; 81 char *pn, *sn; 82 ses_node_t *encp; 83 nvlist_t *encprops; 84 uint8_t *stringin; 85 uint_t len; 86 87 if (ses_node_type(np) != SES_NODE_ENCLOSURE && 88 ses_node_type(np) != SES_NODE_ELEMENT) 89 return (0); 90 91 /* 92 * Find the containing enclosure node and extract the STRING IN 93 * information. 94 */ 95 for (encp = np; ses_node_type(encp) != SES_NODE_ENCLOSURE; 96 encp = ses_node_parent(encp)) 97 ; 98 99 encprops = ses_node_props(encp); 100 if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_STRING, 101 &stringin, &len) != 0) 102 return (0); 103 104 if (len < sizeof (ses_riverwalk_stringin_t)) 105 return (0); 106 107 strp = (ses_riverwalk_stringin_t *)stringin; 108 109 switch (ses_node_type(np)) { 110 case SES_NODE_ELEMENT: 111 /* 112 * We can get part and serial information for power supplies and 113 * the SIM cards (ESC_ELECTRONICS elements). 114 */ 115 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, 116 &type) == 0); 117 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_CLASS_INDEX, 118 &index) == 0); 119 120 sn = pn = NULL; 121 switch (type) { 122 case SES_ET_POWER_SUPPLY: 123 switch (index) { 124 case 0: 125 if (strncmp(strp->rws_ps0_id, "SPS0", 4) != 0) 126 break; 127 128 pn = strp->rws_ps0_pn; 129 sn = strp->rws_ps0_sn; 130 break; 131 132 case 1: 133 if (strncmp(strp->rws_ps1_id, "SPS1", 4) != 0) 134 break; 135 136 pn = strp->rws_ps1_pn; 137 sn = strp->rws_ps1_sn; 138 break; 139 } 140 break; 141 142 case SES_ET_ESC_ELECTRONICS: 143 switch (index) { 144 case 0: 145 if (strncmp(strp->rws_sim0_id, "SIM0", 4) != 0) 146 break; 147 148 pn = strp->rws_sim0_pn; 149 sn = strp->rws_sim0_sn; 150 break; 151 152 case 1: 153 if (strncmp(strp->rws_sim1_id, "SIM1", 4) != 0) 154 break; 155 156 pn = strp->rws_sim1_pn; 157 sn = strp->rws_sim1_sn; 158 break; 159 } 160 break; 161 162 case SES_ET_COOLING: 163 /* 164 * The J4200 uses identical STRING IN data except that 165 * the PSU part numbers are replaced with fan part 166 * numbers. The power supply part and serial number 167 * information are not available. 168 */ 169 switch (index) { 170 case 0: 171 if (strncmp(strp->rws_ps0_id, "FAN0", 4) != 0) 172 break; 173 174 pn = strp->rws_ps0_pn; 175 sn = strp->rws_ps0_sn; 176 break; 177 178 case 1: 179 if (strncmp(strp->rws_ps1_id, "FAN1", 4) != 0) 180 break; 181 182 pn = strp->rws_ps1_pn; 183 sn = strp->rws_ps1_sn; 184 break; 185 } 186 break; 187 188 } 189 190 if (pn == NULL) 191 return (0); 192 193 if (pn[0] != '\0') { 194 (void) bcopy(pn, buf, sizeof (strp->rws_ps0_pn)); 195 buf[sizeof (strp->rws_ps0_pn)] = '\0'; 196 SES_NV_ADD(string, nverr, props, LIBSES_PROP_PART, 197 buf); 198 } 199 200 if (sn[0] != '\0') { 201 (void) bcopy(sn, buf, sizeof (strp->rws_ps0_sn)); 202 buf[sizeof (strp->rws_ps0_sn)] = '\0'; 203 SES_NV_ADD(string, nverr, props, LIBSES_PROP_SERIAL, 204 sn); 205 } 206 207 break; 208 209 case SES_NODE_ENCLOSURE: 210 /* 211 * The chassis serial number is derived from the MID FRU 212 * descriptor. 213 */ 214 if (strncmp(strp->rws_mid_id, "MID ", 4) == 0 && 215 strp->rws_mid_sn[0] != '\0') { 216 (void) bcopy(strp->rws_mid_sn, buf, 217 sizeof (strp->rws_mid_sn)); 218 buf[sizeof (strp->rws_mid_sn)] = '\0'; 219 SES_NV_ADD(string, nverr, props, LIBSES_EN_PROP_CSN, 220 buf); 221 } 222 223 break; 224 } 225 226 return (0); 227 } 228 229 int 230 _ses_init(ses_plugin_t *sp) 231 { 232 ses_plugin_config_t config = { 233 .spc_node_parse = sun_riverwalk_parse_node 234 }; 235 236 return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION, 237 &config) != 0); 238 } 239