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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <stddef.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <libnvpair.h>
30 
31 #include <scsi/libses.h>
32 #include <scsi/plugins/ses/framework/ses2_impl.h>
33 
34 static int
enc_parse_sd(ses2_elem_status_impl_t * esip,nvlist_t * nvl)35 enc_parse_sd(ses2_elem_status_impl_t *esip, nvlist_t *nvl)
36 {
37 	ses2_enclosure_status_impl_t *sdp;
38 	int nverr;
39 
40 	sdp = (ses2_enclosure_status_impl_t *)esip;
41 
42 	SES_NV_ADD(uint64, nverr, nvl, SES_PROP_STATUS_CODE,
43 	    sdp->sesi_common.sesi_status_code);
44 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_SWAP,
45 	    sdp->sesi_common.sesi_swap);
46 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED,
47 	    sdp->sesi_common.sesi_disabled);
48 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_PRDFAIL,
49 	    sdp->sesi_common.sesi_prdfail);
50 
51 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sdp->sesi_ident);
52 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN,
53 	    sdp->sesi_warning_indication);
54 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL,
55 	    sdp->sesi_failure_indication);
56 	SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DELAY,
57 	    sdp->sesi_power_delay);
58 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_REQ,
59 	    sdp->sesi_warning_requested);
60 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL_REQ,
61 	    sdp->sesi_warning_requested);
62 	SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_POWER_DURATION,
63 	    sdp->sesi_power_duration);
64 
65 	return (0);
66 }
67 
68 static int
enc_parse_help(ses_plugin_t * sp,ses_node_t * np)69 enc_parse_help(ses_plugin_t *sp, ses_node_t *np)
70 {
71 	ses_snap_t *snap = ses_node_snapshot(np);
72 	ses2_help_page_impl_t *hpip;
73 	ses2_subhelp_page_impl_t *shpip;
74 	ses2_subhelp_text_impl_t *tip;
75 	nvlist_t *nvl = ses_node_props(np);
76 	uint64_t eid;
77 	size_t len, textlen;
78 	off_t pos;
79 	int nverr;
80 
81 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
82 		return (0);
83 
84 	if ((shpip = ses_plugin_page_lookup(sp, snap,
85 	    SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT, np, &len)) != NULL) {
86 		pos = 0;
87 		for (tip = (ses2_subhelp_text_impl_t *)shpip->sspi_data;
88 		    pos < SCSI_READ16(&shpip->sspi_page_length);
89 		    pos += SES2_SUBHELP_LEN(tip),
90 		    tip = (ses2_subhelp_text_impl_t *)((uint8_t *)tip + pos)) {
91 			if (!SES_WITHIN_PAGE_STRUCT(tip, shpip, len))
92 				break;
93 
94 			if (tip->ssti_subenclosure_identifier != eid)
95 				continue;
96 
97 			textlen = SCSI_READ16(
98 			    &tip->ssti_subenclosure_help_text_length);
99 
100 			if (!SES_WITHIN_PAGE(tip->ssti_subenclosure_help_text,
101 			    textlen, shpip, len))
102 				break;
103 
104 			SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP,
105 			    tip->ssti_subenclosure_help_text, textlen);
106 			return (0);
107 		}
108 	}
109 
110 	if (eid == 0 && (hpip = ses_plugin_page_lookup(sp, snap,
111 	    SES2_DIAGPAGE_HELP_TEXT, np, &len)) != NULL) {
112 		if (!SES_WITHIN_PAGE_STRUCT(hpip, hpip, len))
113 			return (0);
114 
115 		if (!SES_WITHIN_PAGE(hpip->shpi_help_text,
116 		    SCSI_READ16(&hpip->shpi_page_length), hpip, len))
117 			return (0);
118 
119 		SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_HELP,
120 		    hpip->shpi_help_text, SCSI_READ16(&hpip->shpi_page_length));
121 	}
122 
123 	return (0);
124 }
125 
126 static int
enc_parse_string_in(ses_plugin_t * sp,ses_node_t * np)127 enc_parse_string_in(ses_plugin_t *sp, ses_node_t *np)
128 {
129 	ses_snap_t *snap = ses_node_snapshot(np);
130 	ses2_string_in_page_impl_t *sip;
131 	ses2_substring_in_page_impl_t *ssip;
132 	ses2_substring_in_data_impl_t *dip;
133 	nvlist_t *nvl = ses_node_props(np);
134 	uint64_t eid;
135 	off_t pos;
136 	size_t len, textlen;
137 	int nverr;
138 
139 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
140 		return (0);
141 
142 	if ((ssip = ses_plugin_page_lookup(sp, snap,
143 	    SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO, np, &len)) != NULL) {
144 		pos = 0;
145 		for (dip = (ses2_substring_in_data_impl_t *)ssip->ssipi_data;
146 		    pos < SCSI_READ16(&ssip->ssipi_page_length);
147 		    pos += SES2_SUBSTR_LEN(dip),
148 		    dip = (ses2_substring_in_data_impl_t *)
149 		    ((uint8_t *)dip + pos)) {
150 			if (!SES_WITHIN_PAGE_STRUCT(dip, ssip, len))
151 				break;
152 
153 			if (dip->ssidi_subenclosure_identifier != eid)
154 				continue;
155 
156 			textlen =
157 			    SCSI_READ16(&dip->ssidi_substring_data_length);
158 
159 			if (!SES_WITHIN_PAGE(dip->ssidi_data, textlen,
160 			    ssip, len))
161 				break;
162 
163 			SES_NV_ADD(fixed_string, nverr, nvl, SES_EN_PROP_STRING,
164 			    (char *)dip->ssidi_data, textlen);
165 			return (0);
166 		}
167 	}
168 
169 	if (eid == 0 && (sip = ses_plugin_page_lookup(sp, snap,
170 	    SES2_DIAGPAGE_STRING_IO, np, &len)) != NULL) {
171 		if (!SES_WITHIN_PAGE_STRUCT(sip, sip, len))
172 			return (0);
173 
174 		textlen = SCSI_READ16(&sip->ssipi_page_length);
175 
176 		if (!SES_WITHIN_PAGE(sip->ssipi_data, textlen, sip, len))
177 			return (0);
178 
179 		SES_NV_ADD(byte_array, nverr, nvl, SES_EN_PROP_STRING,
180 		    sip->ssipi_data, textlen);
181 	}
182 
183 	return (0);
184 }
185 
186 static int
enc_parse_descr(ses_plugin_t * sp,ses_node_t * np)187 enc_parse_descr(ses_plugin_t *sp, ses_node_t *np)
188 {
189 	char *desc;
190 	nvlist_t *props = ses_node_props(np);
191 	int nverr;
192 	size_t len;
193 
194 	if ((desc = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
195 	    SES2_DIAGPAGE_ELEMENT_DESC, np, &len)) == NULL)
196 		return (0);
197 
198 	SES_NV_ADD(fixed_string, nverr, props, SES_PROP_DESCRIPTION,
199 	    desc, len);
200 
201 	return (0);
202 }
203 
204 static int
enc_parse_dlucode(ses_plugin_t * sp,ses_node_t * np)205 enc_parse_dlucode(ses_plugin_t *sp, ses_node_t *np)
206 {
207 	ses_snap_t *snap = ses_node_snapshot(np);
208 	ses2_ucode_status_page_impl_t *upip;
209 	ses2_ucode_status_descr_impl_t *dip;
210 	nvlist_t *nvl = ses_node_props(np);
211 	int nverr, i;
212 	size_t len;
213 	uint64_t eid;
214 
215 	if ((upip = ses_plugin_page_lookup(sp, snap,
216 	    SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS, np, &len)) == NULL)
217 		return (0);
218 
219 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
220 		return (0);
221 
222 	if (!SES_WITHIN_PAGE_STRUCT(upip, upip, len))
223 		return (0);
224 
225 	/*
226 	 * The number of subenclosures excludes the primary subenclosure, which
227 	 * is always part of the response.
228 	 */
229 	for (dip = &upip->suspi_descriptors[0], i = 0;
230 	    i <= upip->suspi_n_subenclosures;
231 	    i++, dip++) {
232 		if (!SES_WITHIN_PAGE_STRUCT(dip, upip, len))
233 			break;
234 
235 		if (dip->susdi_subenclosure_identifier != eid)
236 			continue;
237 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE,
238 		    dip->susdi_subenclosure_dl_status);
239 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_A,
240 		    dip->susdi_subenclosure_dl_addl_status);
241 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_SZ,
242 		    SCSI_READ32(&dip->susdi_subenclosure_dl_max_size));
243 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_BUF,
244 		    dip->susdi_subenclosure_dl_buffer_id);
245 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_UCODE_OFF,
246 		    dip->susdi_subenclosure_dl_buffer_offset);
247 		break;
248 	}
249 
250 	return (0);
251 }
252 
253 static int
enc_parse_subnick(ses_plugin_t * sp,ses_node_t * np)254 enc_parse_subnick(ses_plugin_t *sp, ses_node_t *np)
255 {
256 	ses_snap_t *snap = ses_node_snapshot(np);
257 	ses2_subnick_status_page_impl_t *spip;
258 	ses2_subnick_descr_impl_t *dip;
259 	nvlist_t *nvl = ses_node_props(np);
260 	int nverr, i;
261 	size_t len;
262 	uint64_t eid;
263 
264 	if (nvlist_lookup_uint64(nvl, SES_EN_PROP_EID, &eid) != 0)
265 		return (0);
266 
267 	if ((spip = ses_plugin_page_lookup(sp, snap,
268 	    SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
269 	    np, &len)) == NULL)
270 		return (0);
271 
272 	if (!SES_WITHIN_PAGE_STRUCT(spip, spip, len))
273 		return (0);
274 
275 	for (dip = &spip->sspci_subnicks[0], i = 0;
276 	    i <= spip->sspci_n_subenclosures;
277 	    i++, dip++) {
278 		if (!SES_WITHIN_PAGE_STRUCT(dip, spip, len))
279 			break;
280 
281 		if (dip->ssdi_subenclosure_identifier != eid)
282 			continue;
283 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_STATUS,
284 		    dip->ssdi_subenclosure_nick_status);
285 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_ADDL_STATUS,
286 		    dip->ssdi_subenclosure_nick_addl_status);
287 		SES_NV_ADD_FS(nverr, nvl, SES_EN_PROP_NICK,
288 		    dip->ssdi_subenclosure_nickname);
289 		SES_NV_ADD(uint64, nverr, nvl, SES_EN_PROP_NICK_LANG,
290 		    dip->ssdi_subenclosure_nick_lang_code);
291 		break;
292 	}
293 
294 	return (0);
295 }
296 
297 int
ses2_fill_enclosure_node(ses_plugin_t * sp,ses_node_t * np)298 ses2_fill_enclosure_node(ses_plugin_t *sp, ses_node_t *np)
299 {
300 	ses_snap_t *snap = ses_node_snapshot(np);
301 	nvlist_t *props = ses_node_props(np);
302 	ses2_elem_status_impl_t *esip;
303 	int err;
304 	size_t len;
305 
306 	if ((esip = ses_plugin_page_lookup(sp, snap,
307 	    SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS, np, &len)) != NULL) {
308 		if ((err = enc_parse_sd(esip, props)) != 0)
309 			return (err);
310 	}
311 
312 	if ((err = enc_parse_help(sp, np)) != 0)
313 		return (err);
314 
315 	if ((err = enc_parse_string_in(sp, np)) != 0)
316 		return (err);
317 
318 	if ((err = enc_parse_descr(sp, np)) != 0)
319 		return (err);
320 
321 	if ((err = enc_parse_dlucode(sp, np)) != 0)
322 		return (err);
323 
324 	if ((err = enc_parse_subnick(sp, np)) != 0)
325 		return (err);
326 
327 	return (0);
328 }
329