1275c9da8Seschrock /*
2275c9da8Seschrock  * CDDL HEADER START
3275c9da8Seschrock  *
4275c9da8Seschrock  * The contents of this file are subject to the terms of the
5275c9da8Seschrock  * Common Development and Distribution License (the "License").
6275c9da8Seschrock  * You may not use this file except in compliance with the License.
7275c9da8Seschrock  *
8275c9da8Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9275c9da8Seschrock  * or http://www.opensolaris.org/os/licensing.
10275c9da8Seschrock  * See the License for the specific language governing permissions
11275c9da8Seschrock  * and limitations under the License.
12275c9da8Seschrock  *
13275c9da8Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
14275c9da8Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15275c9da8Seschrock  * If applicable, add the following below this CDDL HEADER, with the
16275c9da8Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
17275c9da8Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
18275c9da8Seschrock  *
19275c9da8Seschrock  * CDDL HEADER END
20275c9da8Seschrock  */
21275c9da8Seschrock 
22275c9da8Seschrock /*
23*ac88567aSHyon Kim  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24275c9da8Seschrock  */
25275c9da8Seschrock 
26275c9da8Seschrock #include <stddef.h>
27275c9da8Seschrock #include <string.h>
28275c9da8Seschrock #include <strings.h>
29275c9da8Seschrock #include <libnvpair.h>
30275c9da8Seschrock 
31275c9da8Seschrock #include <scsi/libses.h>
32275c9da8Seschrock #include <scsi/plugins/ses/framework/ses2_impl.h>
33275c9da8Seschrock 
34275c9da8Seschrock static int
enc_parse_sd(ses2_elem_status_impl_t * esip,nvlist_t * nvl)35275c9da8Seschrock enc_parse_sd(ses2_elem_status_impl_t *esip, nvlist_t *nvl)
36275c9da8Seschrock {
37275c9da8Seschrock 	ses2_enclosure_status_impl_t *sdp;
38275c9da8Seschrock 	int nverr;
39275c9da8Seschrock 
40275c9da8Seschrock 	sdp = (ses2_enclosure_status_impl_t *)esip;
41275c9da8Seschrock 
42275c9da8Seschrock 	SES_NV_ADD(uint64, nverr, nvl, SES_PROP_STATUS_CODE,
43275c9da8Seschrock 	    sdp->sesi_common.sesi_status_code);
44275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_SWAP,
45275c9da8Seschrock 	    sdp->sesi_common.sesi_swap);
46275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED,
47275c9da8Seschrock 	    sdp->sesi_common.sesi_disabled);
48275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_PRDFAIL,
49275c9da8Seschrock 	    sdp->sesi_common.sesi_prdfail);
50275c9da8Seschrock 
51275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sdp->sesi_ident);
52275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN,
53275c9da8Seschrock 	    sdp->sesi_warning_indication);
54275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL,
55275c9da8Seschrock 	    sdp->sesi_failure_indication);
56275c9da8Seschrock 	SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DELAY,
57275c9da8Seschrock 	    sdp->sesi_power_delay);
58275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_REQ,
59275c9da8Seschrock 	    sdp->sesi_warning_requested);
60275c9da8Seschrock 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL_REQ,
61275c9da8Seschrock 	    sdp->sesi_warning_requested);
62275c9da8Seschrock 	SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DURATION,
63275c9da8Seschrock 	    sdp->sesi_power_duration);
64275c9da8Seschrock 
65275c9da8Seschrock 	return (0);
66275c9da8Seschrock }
67275c9da8Seschrock 
68275c9da8Seschrock static int
enc_parse_help(ses_plugin_t * sp,ses_node_t * np)69275c9da8Seschrock enc_parse_help(ses_plugin_t *sp, ses_node_t *np)
70275c9da8Seschrock {
71275c9da8Seschrock 	ses_snap_t *snap = ses_node_snapshot(np);
72275c9da8Seschrock 	ses2_help_page_impl_t *hpip;
73275c9da8Seschrock 	ses2_subhelp_page_impl_t *shpip;
74275c9da8Seschrock 	ses2_subhelp_text_impl_t *tip;
75275c9da8Seschrock 	nvlist_t *nvl = ses_node_props(np);
76275c9da8Seschrock 	uint64_t eid;
77*ac88567aSHyon Kim 	size_t len, textlen;
78275c9da8Seschrock 	off_t pos;
79275c9da8Seschrock 	int nverr;
80275c9da8Seschrock 
81275c9da8Seschrock 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
82275c9da8Seschrock 		return (0);
83275c9da8Seschrock 
84275c9da8Seschrock 	if ((shpip = ses_plugin_page_lookup(sp, snap,
85275c9da8Seschrock 	    SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT, np, &len)) != NULL) {
86275c9da8Seschrock 		pos = 0;
87275c9da8Seschrock 		for (tip = (ses2_subhelp_text_impl_t *)shpip->sspi_data;
88275c9da8Seschrock 		    pos < SCSI_READ16(&shpip->sspi_page_length);
89275c9da8Seschrock 		    pos += SES2_SUBHELP_LEN(tip),
90275c9da8Seschrock 		    tip = (ses2_subhelp_text_impl_t *)((uint8_t *)tip + pos)) {
91275c9da8Seschrock 			if (!SES_WITHIN_PAGE_STRUCT(tip, shpip, len))
92275c9da8Seschrock 				break;
93275c9da8Seschrock 
94275c9da8Seschrock 			if (tip->ssti_subenclosure_identifier != eid)
95275c9da8Seschrock 				continue;
96275c9da8Seschrock 
97*ac88567aSHyon Kim 			textlen = SCSI_READ16(
98*ac88567aSHyon Kim 			    &tip->ssti_subenclosure_help_text_length);
99*ac88567aSHyon Kim 
100275c9da8Seschrock 			if (!SES_WITHIN_PAGE(tip->ssti_subenclosure_help_text,
101*ac88567aSHyon Kim 			    textlen, shpip, len))
102275c9da8Seschrock 				break;
103275c9da8Seschrock 
104275c9da8Seschrock 			SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP,
105*ac88567aSHyon Kim 			    tip->ssti_subenclosure_help_text, textlen);
106275c9da8Seschrock 			return (0);
107275c9da8Seschrock 		}
108275c9da8Seschrock 	}
109275c9da8Seschrock 
110275c9da8Seschrock 	if (eid == 0 && (hpip = ses_plugin_page_lookup(sp, snap,
111275c9da8Seschrock 	    SES2_DIAGPAGE_HELP_TEXT, np, &len)) != NULL) {
112275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(hpip, hpip, len))
113275c9da8Seschrock 			return (0);
114275c9da8Seschrock 
115275c9da8Seschrock 		if (!SES_WITHIN_PAGE(hpip->shpi_help_text,
116275c9da8Seschrock 		    SCSI_READ16(&hpip->shpi_page_length), hpip, len))
117275c9da8Seschrock 			return (0);
118275c9da8Seschrock 
119275c9da8Seschrock 		SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP,
120275c9da8Seschrock 		    hpip->shpi_help_text, SCSI_READ16(&hpip->shpi_page_length));
121275c9da8Seschrock 	}
122275c9da8Seschrock 
123275c9da8Seschrock 	return (0);
124275c9da8Seschrock }
125275c9da8Seschrock 
126275c9da8Seschrock static int
enc_parse_string_in(ses_plugin_t * sp,ses_node_t * np)127275c9da8Seschrock enc_parse_string_in(ses_plugin_t *sp, ses_node_t *np)
128275c9da8Seschrock {
129275c9da8Seschrock 	ses_snap_t *snap = ses_node_snapshot(np);
130275c9da8Seschrock 	ses2_string_in_page_impl_t *sip;
131275c9da8Seschrock 	ses2_substring_in_page_impl_t *ssip;
132275c9da8Seschrock 	ses2_substring_in_data_impl_t *dip;
133275c9da8Seschrock 	nvlist_t *nvl = ses_node_props(np);
134275c9da8Seschrock 	uint64_t eid;
135275c9da8Seschrock 	off_t pos;
136275c9da8Seschrock 	size_t len, textlen;
137275c9da8Seschrock 	int nverr;
138275c9da8Seschrock 
139275c9da8Seschrock 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
140275c9da8Seschrock 		return (0);
141275c9da8Seschrock 
142275c9da8Seschrock 	if ((ssip = ses_plugin_page_lookup(sp, snap,
143275c9da8Seschrock 	    SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, np, &len)) != NULL) {
144275c9da8Seschrock 		pos = 0;
145275c9da8Seschrock 		for (dip = (ses2_substring_in_data_impl_t *)ssip->ssipi_data;
146275c9da8Seschrock 		    pos < SCSI_READ16(&ssip->ssipi_page_length);
147275c9da8Seschrock 		    pos += SES2_SUBSTR_LEN(dip),
148275c9da8Seschrock 		    dip = (ses2_substring_in_data_impl_t *)
149275c9da8Seschrock 		    ((uint8_t *)dip + pos)) {
150275c9da8Seschrock 			if (!SES_WITHIN_PAGE_STRUCT(dip, ssip, len))
151275c9da8Seschrock 				break;
152275c9da8Seschrock 
153275c9da8Seschrock 			if (dip->ssidi_subenclosure_identifier != eid)
154275c9da8Seschrock 				continue;
155275c9da8Seschrock 
156*ac88567aSHyon Kim 			textlen =
157*ac88567aSHyon Kim 			    SCSI_READ16(&dip->ssidi_substring_data_length);
158*ac88567aSHyon Kim 
159*ac88567aSHyon Kim 			if (!SES_WITHIN_PAGE(dip->ssidi_data, textlen,
160*ac88567aSHyon Kim 			    ssip, len))
161275c9da8Seschrock 				break;
162275c9da8Seschrock 
163275c9da8Seschrock 			SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_STRING,
164*ac88567aSHyon Kim 			    (char *)dip->ssidi_data, textlen);
165275c9da8Seschrock 			return (0);
166275c9da8Seschrock 		}
167275c9da8Seschrock 	}
168275c9da8Seschrock 
169275c9da8Seschrock 	if (eid == 0 && (sip = ses_plugin_page_lookup(sp, snap,
170275c9da8Seschrock 	    SES2_DIAGPAGE_STRING_IO, np, &len)) != NULL) {
171275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(sip, sip, len))
172275c9da8Seschrock 			return (0);
173275c9da8Seschrock 
174275c9da8Seschrock 		textlen = SCSI_READ16(&sip->ssipi_page_length);
175275c9da8Seschrock 
176275c9da8Seschrock 		if (!SES_WITHIN_PAGE(sip->ssipi_data, textlen, sip, len))
177275c9da8Seschrock 			return (0);
178275c9da8Seschrock 
179275c9da8Seschrock 		SES_NV_ADD(byte_array, nverr, nvl, SES_EN_PROP_STRING,
180275c9da8Seschrock 		    sip->ssipi_data, textlen);
181275c9da8Seschrock 	}
182275c9da8Seschrock 
183275c9da8Seschrock 	return (0);
184275c9da8Seschrock }
185275c9da8Seschrock 
186275c9da8Seschrock static int
enc_parse_descr(ses_plugin_t * sp,ses_node_t * np)187275c9da8Seschrock enc_parse_descr(ses_plugin_t *sp, ses_node_t *np)
188275c9da8Seschrock {
189275c9da8Seschrock 	char *desc;
190275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
191275c9da8Seschrock 	int nverr;
192275c9da8Seschrock 	size_t len;
193275c9da8Seschrock 
194275c9da8Seschrock 	if ((desc = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
195275c9da8Seschrock 	    SES2_DIAGPAGE_ELEMENT_DESC, np, &len)) == NULL)
196275c9da8Seschrock 		return (0);
197275c9da8Seschrock 
198275c9da8Seschrock 	SES_NV_ADD(fixed_string, nverr, props, SES_PROP_DESCRIPTION,
199275c9da8Seschrock 	    desc, len);
200275c9da8Seschrock 
201275c9da8Seschrock 	return (0);
202275c9da8Seschrock }
203275c9da8Seschrock 
204275c9da8Seschrock static int
enc_parse_dlucode(ses_plugin_t * sp,ses_node_t * np)205275c9da8Seschrock enc_parse_dlucode(ses_plugin_t *sp, ses_node_t *np)
206275c9da8Seschrock {
207275c9da8Seschrock 	ses_snap_t *snap = ses_node_snapshot(np);
208275c9da8Seschrock 	ses2_ucode_status_page_impl_t *upip;
209275c9da8Seschrock 	ses2_ucode_status_descr_impl_t *dip;
210275c9da8Seschrock 	nvlist_t *nvl = ses_node_props(np);
211275c9da8Seschrock 	int nverr, i;
212275c9da8Seschrock 	size_t len;
213275c9da8Seschrock 	uint64_t eid;
214275c9da8Seschrock 
215275c9da8Seschrock 	if ((upip = ses_plugin_page_lookup(sp, snap,
216275c9da8Seschrock 	    SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, np, &len)) == NULL)
217275c9da8Seschrock 		return (0);
218275c9da8Seschrock 
219275c9da8Seschrock 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
220275c9da8Seschrock 		return (0);
221275c9da8Seschrock 
222275c9da8Seschrock 	if (!SES_WITHIN_PAGE_STRUCT(upip, upip, len))
223275c9da8Seschrock 		return (0);
224275c9da8Seschrock 
225275c9da8Seschrock 	/*
226275c9da8Seschrock 	 * The number of subenclosures excludes the primary subenclosure, which
227275c9da8Seschrock 	 * is always part of the response.
228275c9da8Seschrock 	 */
229275c9da8Seschrock 	for (dip = &upip->suspi_descriptors[0], i = 0;
230275c9da8Seschrock 	    i <= upip->suspi_n_subenclosures;
231275c9da8Seschrock 	    i++, dip++) {
232275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(dip, upip, len))
233275c9da8Seschrock 			break;
234275c9da8Seschrock 
235275c9da8Seschrock 		if (dip->susdi_subenclosure_identifier != eid)
236275c9da8Seschrock 			continue;
237275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE,
238275c9da8Seschrock 		    dip->susdi_subenclosure_dl_status);
239275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_A,
240275c9da8Seschrock 		    dip->susdi_subenclosure_dl_addl_status);
241275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_SZ,
242275c9da8Seschrock 		    SCSI_READ32(&dip->susdi_subenclosure_dl_max_size));
243275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_BUF,
244275c9da8Seschrock 		    dip->susdi_subenclosure_dl_buffer_id);
245275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_OFF,
246275c9da8Seschrock 		    dip->susdi_subenclosure_dl_buffer_offset);
247275c9da8Seschrock 		break;
248275c9da8Seschrock 	}
249275c9da8Seschrock 
250275c9da8Seschrock 	return (0);
251275c9da8Seschrock }
252275c9da8Seschrock 
253275c9da8Seschrock static int
enc_parse_subnick(ses_plugin_t * sp,ses_node_t * np)254275c9da8Seschrock enc_parse_subnick(ses_plugin_t *sp, ses_node_t *np)
255275c9da8Seschrock {
256275c9da8Seschrock 	ses_snap_t *snap = ses_node_snapshot(np);
257275c9da8Seschrock 	ses2_subnick_status_page_impl_t *spip;
258275c9da8Seschrock 	ses2_subnick_descr_impl_t *dip;
259275c9da8Seschrock 	nvlist_t *nvl = ses_node_props(np);
260275c9da8Seschrock 	int nverr, i;
261275c9da8Seschrock 	size_t len;
262275c9da8Seschrock 	uint64_t eid;
263275c9da8Seschrock 
264275c9da8Seschrock 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
265275c9da8Seschrock 		return (0);
266275c9da8Seschrock 
267275c9da8Seschrock 	if ((spip = ses_plugin_page_lookup(sp, snap,
268275c9da8Seschrock 	    SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
269275c9da8Seschrock 	    np, &len)) == NULL)
270275c9da8Seschrock 		return (0);
271275c9da8Seschrock 
272275c9da8Seschrock 	if (!SES_WITHIN_PAGE_STRUCT(spip, spip, len))
273275c9da8Seschrock 		return (0);
274275c9da8Seschrock 
275275c9da8Seschrock 	for (dip = &spip->sspci_subnicks[0], i = 0;
27651ece835Seschrock 	    i <= spip->sspci_n_subenclosures;
277275c9da8Seschrock 	    i++, dip++) {
278275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(dip, spip, len))
279275c9da8Seschrock 			break;
280275c9da8Seschrock 
281275c9da8Seschrock 		if (dip->ssdi_subenclosure_identifier != eid)
282275c9da8Seschrock 			continue;
283275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_STATUS,
284275c9da8Seschrock 		    dip->ssdi_subenclosure_nick_status);
285275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_ADDL_STATUS,
286275c9da8Seschrock 		    dip->ssdi_subenclosure_nick_addl_status);
287275c9da8Seschrock 		SES_NV_ADD_FS(nverr, nvl, SES_EN_PROP_NICK,
288275c9da8Seschrock 		    dip->ssdi_subenclosure_nickname);
289275c9da8Seschrock 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_LANG,
290275c9da8Seschrock 		    dip->ssdi_subenclosure_nick_lang_code);
291275c9da8Seschrock 		break;
292275c9da8Seschrock 	}
293275c9da8Seschrock 
294275c9da8Seschrock 	return (0);
295275c9da8Seschrock }
296275c9da8Seschrock 
297275c9da8Seschrock int
ses2_fill_enclosure_node(ses_plugin_t * sp,ses_node_t * np)298275c9da8Seschrock ses2_fill_enclosure_node(ses_plugin_t *sp, ses_node_t *np)
299275c9da8Seschrock {
300275c9da8Seschrock 	ses_snap_t *snap = ses_node_snapshot(np);
301275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
302275c9da8Seschrock 	ses2_elem_status_impl_t *esip;
303275c9da8Seschrock 	int err;
304275c9da8Seschrock 	size_t len;
305275c9da8Seschrock 
306275c9da8Seschrock 	if ((esip = ses_plugin_page_lookup(sp, snap,
307275c9da8Seschrock 	    SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, np, &len)) != NULL) {
308275c9da8Seschrock 		if ((err = enc_parse_sd(esip, props)) != 0)
309275c9da8Seschrock 			return (err);
310275c9da8Seschrock 	}
311275c9da8Seschrock 
312275c9da8Seschrock 	if ((err = enc_parse_help(sp, np)) != 0)
313275c9da8Seschrock 		return (err);
314275c9da8Seschrock 
315275c9da8Seschrock 	if ((err = enc_parse_string_in(sp, np)) != 0)
316275c9da8Seschrock 		return (err);
317275c9da8Seschrock 
318275c9da8Seschrock 	if ((err = enc_parse_descr(sp, np)) != 0)
319275c9da8Seschrock 		return (err);
320275c9da8Seschrock 
321275c9da8Seschrock 	if ((err = enc_parse_dlucode(sp, np)) != 0)
322275c9da8Seschrock 		return (err);
323275c9da8Seschrock 
324275c9da8Seschrock 	if ((err = enc_parse_subnick(sp, np)) != 0)
325275c9da8Seschrock 		return (err);
326275c9da8Seschrock 
327275c9da8Seschrock 	return (0);
328275c9da8Seschrock }
329