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