1*6433Seschrock /*
2*6433Seschrock  * CDDL HEADER START
3*6433Seschrock  *
4*6433Seschrock  * The contents of this file are subject to the terms of the
5*6433Seschrock  * Common Development and Distribution License (the "License").
6*6433Seschrock  * You may not use this file except in compliance with the License.
7*6433Seschrock  *
8*6433Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6433Seschrock  * or http://www.opensolaris.org/os/licensing.
10*6433Seschrock  * See the License for the specific language governing permissions
11*6433Seschrock  * and limitations under the License.
12*6433Seschrock  *
13*6433Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
14*6433Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6433Seschrock  * If applicable, add the following below this CDDL HEADER, with the
16*6433Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
17*6433Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6433Seschrock  *
19*6433Seschrock  * CDDL HEADER END
20*6433Seschrock  */
21*6433Seschrock 
22*6433Seschrock /*
23*6433Seschrock  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*6433Seschrock  * Use is subject to license terms.
25*6433Seschrock  */
26*6433Seschrock 
27*6433Seschrock #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*6433Seschrock 
29*6433Seschrock #include <string.h>
30*6433Seschrock #include <strings.h>
31*6433Seschrock 
32*6433Seschrock #include <scsi/libses.h>
33*6433Seschrock #include <scsi/libses_plugin.h>
34*6433Seschrock 
35*6433Seschrock #pragma pack(1)
36*6433Seschrock 
37*6433Seschrock typedef struct ses_riverwalk_stringin {
38*6433Seschrock 	uint8_t		rws_download_status;
39*6433Seschrock 	uint8_t		rws_descriptor_start;
40*6433Seschrock 	uint16_t	rws_descriptor_length;
41*6433Seschrock 	char		rws_sim0_id[4];
42*6433Seschrock 	char		rws_sim0_pn[15];
43*6433Seschrock 	char		rws_sim0_sn[20];
44*6433Seschrock 	char		rws_sim1_id[4];
45*6433Seschrock 	char		rws_sim1_pn[15];
46*6433Seschrock 	char		rws_sim1_sn[20];
47*6433Seschrock 	char		rws_mid_id[4];
48*6433Seschrock 	char		rws_mid_pn[15];
49*6433Seschrock 	char		rws_mid_sn[20];
50*6433Seschrock 	char		rws_ps0_id[4];
51*6433Seschrock 	char		rws_ps0_pn[15];
52*6433Seschrock 	char		rws_ps0_sn[20];
53*6433Seschrock 	char		rws_ps1_id[4];
54*6433Seschrock 	char		rws_ps1_pn[15];
55*6433Seschrock 	char		rws_ps1_sn[20];
56*6433Seschrock 	char		__reserved1[29];
57*6433Seschrock 	uint8_t		rws_diag_start;
58*6433Seschrock 	uint8_t		rws_eid;
59*6433Seschrock 	uint16_t	rws_diag_length;
60*6433Seschrock 	uint8_t		rws_sim_id;
61*6433Seschrock 	uint8_t		rws_numport;
62*6433Seschrock 	uint16_t	__reserved2;
63*6433Seschrock 	uint8_t		rws_sasaddr[8];
64*6433Seschrock 	uint8_t		rws_sys_sn[8];
65*6433Seschrock 	char		rws_port0[16];
66*6433Seschrock 	char		rws_port1[16];
67*6433Seschrock 	char		rws_port2[16];
68*6433Seschrock } ses_riverwalk_stringin_t;
69*6433Seschrock 
70*6433Seschrock #pragma pack()
71*6433Seschrock 
72*6433Seschrock /*ARGSUSED*/
73*6433Seschrock static int
sun_riverwalk_parse_node(ses_plugin_t * sp,ses_node_t * np)74*6433Seschrock sun_riverwalk_parse_node(ses_plugin_t *sp, ses_node_t *np)
75*6433Seschrock {
76*6433Seschrock 	nvlist_t *props = ses_node_props(np);
77*6433Seschrock 	int nverr;
78*6433Seschrock 	ses_riverwalk_stringin_t *strp;
79*6433Seschrock 	char buf[32];
80*6433Seschrock 	uint64_t type, index;
81*6433Seschrock 	char *pn, *sn;
82*6433Seschrock 	ses_node_t *encp;
83*6433Seschrock 	nvlist_t *encprops;
84*6433Seschrock 	uint8_t *stringin;
85*6433Seschrock 	uint_t len;
86*6433Seschrock 
87*6433Seschrock 	if (ses_node_type(np) != SES_NODE_ENCLOSURE &&
88*6433Seschrock 	    ses_node_type(np) != SES_NODE_ELEMENT)
89*6433Seschrock 		return (0);
90*6433Seschrock 
91*6433Seschrock 	/*
92*6433Seschrock 	 * Find the containing enclosure node and extract the STRING IN
93*6433Seschrock 	 * information.
94*6433Seschrock 	 */
95*6433Seschrock 	for (encp = np; ses_node_type(encp) != SES_NODE_ENCLOSURE;
96*6433Seschrock 	    encp = ses_node_parent(encp))
97*6433Seschrock 		;
98*6433Seschrock 
99*6433Seschrock 	encprops = ses_node_props(encp);
100*6433Seschrock 	if (nvlist_lookup_byte_array(encprops, SES_EN_PROP_STRING,
101*6433Seschrock 	    &stringin, &len) != 0)
102*6433Seschrock 		return (0);
103*6433Seschrock 
104*6433Seschrock 	if (len < sizeof (ses_riverwalk_stringin_t))
105*6433Seschrock 		return (0);
106*6433Seschrock 
107*6433Seschrock 	strp = (ses_riverwalk_stringin_t *)stringin;
108*6433Seschrock 
109*6433Seschrock 	switch (ses_node_type(np)) {
110*6433Seschrock 	case SES_NODE_ELEMENT:
111*6433Seschrock 		/*
112*6433Seschrock 		 * We can get part and serial information for power supplies and
113*6433Seschrock 		 * the SIM cards (ESC_ELECTRONICS elements).
114*6433Seschrock 		 */
115*6433Seschrock 		VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE,
116*6433Seschrock 		    &type) == 0);
117*6433Seschrock 		VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_CLASS_INDEX,
118*6433Seschrock 		    &index) == 0);
119*6433Seschrock 
120*6433Seschrock 		sn = pn = NULL;
121*6433Seschrock 		switch (type) {
122*6433Seschrock 		case SES_ET_POWER_SUPPLY:
123*6433Seschrock 			switch (index) {
124*6433Seschrock 			case 0:
125*6433Seschrock 				if (strncmp(strp->rws_ps0_id, "SPS0", 4) != 0)
126*6433Seschrock 					break;
127*6433Seschrock 
128*6433Seschrock 				pn = strp->rws_ps0_pn;
129*6433Seschrock 				sn = strp->rws_ps0_sn;
130*6433Seschrock 				break;
131*6433Seschrock 
132*6433Seschrock 			case 1:
133*6433Seschrock 				if (strncmp(strp->rws_ps1_id, "SPS1", 4) != 0)
134*6433Seschrock 					break;
135*6433Seschrock 
136*6433Seschrock 				pn = strp->rws_ps1_pn;
137*6433Seschrock 				sn = strp->rws_ps1_sn;
138*6433Seschrock 				break;
139*6433Seschrock 			}
140*6433Seschrock 			break;
141*6433Seschrock 
142*6433Seschrock 		case SES_ET_ESC_ELECTRONICS:
143*6433Seschrock 			switch (index) {
144*6433Seschrock 			case 0:
145*6433Seschrock 				if (strncmp(strp->rws_sim0_id, "SIM0", 4) != 0)
146*6433Seschrock 					break;
147*6433Seschrock 
148*6433Seschrock 				pn = strp->rws_sim0_pn;
149*6433Seschrock 				sn = strp->rws_sim0_sn;
150*6433Seschrock 				break;
151*6433Seschrock 
152*6433Seschrock 			case 1:
153*6433Seschrock 				if (strncmp(strp->rws_sim1_id, "SIM1", 4) != 0)
154*6433Seschrock 					break;
155*6433Seschrock 
156*6433Seschrock 				pn = strp->rws_sim1_pn;
157*6433Seschrock 				sn = strp->rws_sim1_sn;
158*6433Seschrock 				break;
159*6433Seschrock 			}
160*6433Seschrock 			break;
161*6433Seschrock 
162*6433Seschrock 		case SES_ET_COOLING:
163*6433Seschrock 			/*
164*6433Seschrock 			 * The J4200 uses identical STRING IN data except that
165*6433Seschrock 			 * the PSU part numbers are replaced with fan part
166*6433Seschrock 			 * numbers.  The power supply part and serial number
167*6433Seschrock 			 * information are not available.
168*6433Seschrock 			 */
169*6433Seschrock 			switch (index) {
170*6433Seschrock 			case 0:
171*6433Seschrock 				if (strncmp(strp->rws_ps0_id, "FAN0", 4) != 0)
172*6433Seschrock 					break;
173*6433Seschrock 
174*6433Seschrock 				pn = strp->rws_ps0_pn;
175*6433Seschrock 				sn = strp->rws_ps0_sn;
176*6433Seschrock 				break;
177*6433Seschrock 
178*6433Seschrock 			case 1:
179*6433Seschrock 				if (strncmp(strp->rws_ps1_id, "FAN1", 4) != 0)
180*6433Seschrock 					break;
181*6433Seschrock 
182*6433Seschrock 				pn = strp->rws_ps1_pn;
183*6433Seschrock 				sn = strp->rws_ps1_sn;
184*6433Seschrock 				break;
185*6433Seschrock 			}
186*6433Seschrock 			break;
187*6433Seschrock 
188*6433Seschrock 		}
189*6433Seschrock 
190*6433Seschrock 		if (pn == NULL)
191*6433Seschrock 			return (0);
192*6433Seschrock 
193*6433Seschrock 		if (pn[0] != '\0') {
194*6433Seschrock 			(void) bcopy(pn, buf, sizeof (strp->rws_ps0_pn));
195*6433Seschrock 			buf[sizeof (strp->rws_ps0_pn)] = '\0';
196*6433Seschrock 			SES_NV_ADD(string, nverr, props, LIBSES_PROP_PART,
197*6433Seschrock 			    buf);
198*6433Seschrock 		}
199*6433Seschrock 
200*6433Seschrock 		if (sn[0] != '\0') {
201*6433Seschrock 			(void) bcopy(sn, buf, sizeof (strp->rws_ps0_sn));
202*6433Seschrock 			buf[sizeof (strp->rws_ps0_sn)] = '\0';
203*6433Seschrock 			SES_NV_ADD(string, nverr, props, LIBSES_PROP_SERIAL,
204*6433Seschrock 			    sn);
205*6433Seschrock 		}
206*6433Seschrock 
207*6433Seschrock 		break;
208*6433Seschrock 
209*6433Seschrock 	case SES_NODE_ENCLOSURE:
210*6433Seschrock 		/*
211*6433Seschrock 		 * The chassis serial number is derived from the MID FRU
212*6433Seschrock 		 * descriptor.
213*6433Seschrock 		 */
214*6433Seschrock 		if (strncmp(strp->rws_mid_id, "MID ", 4) == 0 &&
215*6433Seschrock 		    strp->rws_mid_sn[0] != '\0') {
216*6433Seschrock 			(void) bcopy(strp->rws_mid_sn, buf,
217*6433Seschrock 			    sizeof (strp->rws_mid_sn));
218*6433Seschrock 			buf[sizeof (strp->rws_mid_sn)] = '\0';
219*6433Seschrock 			SES_NV_ADD(string, nverr, props, LIBSES_EN_PROP_CSN,
220*6433Seschrock 			    buf);
221*6433Seschrock 		}
222*6433Seschrock 
223*6433Seschrock 		break;
224*6433Seschrock 	}
225*6433Seschrock 
226*6433Seschrock 	return (0);
227*6433Seschrock }
228*6433Seschrock 
229*6433Seschrock int
_ses_init(ses_plugin_t * sp)230*6433Seschrock _ses_init(ses_plugin_t *sp)
231*6433Seschrock {
232*6433Seschrock 	ses_plugin_config_t config = {
233*6433Seschrock 		.spc_node_parse = sun_riverwalk_parse_node
234*6433Seschrock 	};
235*6433Seschrock 
236*6433Seschrock 	return (ses_plugin_register(sp, LIBSES_PLUGIN_VERSION,
237*6433Seschrock 	    &config) != 0);
238*6433Seschrock }
239