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