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