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
sun_riverwalk_parse_node(ses_plugin_t * sp,ses_node_t * np)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
_ses_init(ses_plugin_t * sp)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