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 <strings.h>
28
29 #include <scsi/libses.h>
30 #include <scsi/libses_plugin.h>
31 #include <scsi/plugins/ses/framework/ses2.h>
32
33 #include "ses2_impl.h"
34
35 static int
ses2_ctl_common_setdef(ses_node_t * np,ses2_diag_page_t page,void * data)36 ses2_ctl_common_setdef(ses_node_t *np, ses2_diag_page_t page, void *data)
37 {
38 ses2_cmn_elem_ctl_impl_t *eip = data;
39 nvlist_t *props = ses_node_props(np);
40
41 if (page != SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS)
42 return (0);
43
44 SES_NV_CTLBOOL_INVERT(props, SES_PROP_SWAP, eip->seci_rst_swap);
45 SES_NV_CTLBOOL(props, SES_PROP_DISABLED, eip->seci_disable);
46 SES_NV_CTLBOOL(props, SES_PROP_PRDFAIL, eip->seci_prdfail);
47
48 eip->seci_select = 1;
49
50 return (0);
51 }
52
53 /*ARGSUSED*/
54 static void *
ses2_aes_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)55 ses2_aes_index(ses_plugin_t *sp, ses_node_t *np, void *data, size_t pagelen,
56 size_t *len)
57 {
58 ses2_aes_page_impl_t *apip = data;
59 uint64_t index, type;
60 nvlist_t *props = ses_node_props(np);
61 ses2_aes_descr_eip_impl_t *dep;
62 size_t desclen;
63 int i, pos;
64
65 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_ONLY_INDEX,
66 &index) == 0);
67 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE,
68 &type) == 0);
69
70 if (pagelen < offsetof(ses2_aes_page_impl_t, sapi_data))
71 return (0);
72
73 for (dep = (ses2_aes_descr_eip_impl_t *)apip->sapi_data, pos = 0, i = 0;
74 pos < SCSI_READ16(&apip->sapi_page_length);
75 dep = (ses2_aes_descr_eip_impl_t *)(apip->sapi_data + pos), i++) {
76 if (!SES_WITHIN_PAGE_STRUCT(dep, data, pagelen))
77 break;
78
79 desclen = dep->sadei_length +
80 offsetof(ses2_aes_descr_eip_impl_t, sadei_length) +
81 sizeof (dep->sadei_length);
82
83 if (!SES_WITHIN_PAGE(dep, desclen, data, pagelen))
84 break;
85
86 pos += desclen;
87 if (!dep->sadei_eip &&
88 type != SES_ET_DEVICE &&
89 type != SES_ET_ARRAY_DEVICE) {
90 /*
91 * We can't really do anything with this, because
92 * while the standard requires that these descriptors
93 * be in the same order as those in the status page,
94 * some element types may optionally include AES
95 * data. This means we cannot know which element
96 * this descriptor refers to unless EIP is 1. Sadly,
97 * the standard only says that this "should" be true.
98 * It's impossible to guess what use this is supposed
99 * to have otherwise. See 6.1.13.1.
100 */
101 continue;
102 } else if (dep->sadei_eip &&
103 dep->sadei_element_index != index) {
104 /*
105 * The element index field from AES descriptor is
106 * element only index which doesn't include the OVERALL
107 * STATUS fields so we should compare with
108 * SES_PROP_ELEMENT_ONLY_INDEX not
109 * SES_PROP_ELEMENT_INDEX.
110 */
111 continue;
112 } else if (dep->sadei_eip || i == index) {
113 *len = desclen;
114 return (dep);
115 }
116 }
117
118 return (NULL);
119 }
120
121 /*ARGSUSED*/
122 static void *
ses2_threshold_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)123 ses2_threshold_index(ses_plugin_t *sp, ses_node_t *np, void *data,
124 size_t pagelen, size_t *len)
125 {
126 uint64_t index;
127 nvlist_t *props = ses_node_props(np);
128 ses2_threshold_in_page_impl_t *tpip = data;
129 ses2_threshold_impl_t *tp;
130
131 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
132 &index) == 0);
133
134 *len = sizeof (ses2_threshold_impl_t);
135 tp = &tpip->stipi_thresholds[index];
136
137 if (!SES_WITHIN_PAGE_STRUCT(tp, data, pagelen))
138 return (NULL);
139
140 return (&tpip->stipi_thresholds[index]);
141 }
142
143 /*ARGSUSED*/
144 static void *
ses2_element_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)145 ses2_element_index(ses_plugin_t *sp, ses_node_t *np, void *data,
146 size_t pagelen, size_t *len)
147 {
148 uint64_t index;
149 nvlist_t *props = ses_node_props(np);
150 ses2_elem_desc_page_impl_t *edip = data;
151 ses2_elem_descriptor_impl_t *dp;
152 int i;
153 uint16_t dlen;
154
155 if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, &index) != 0)
156 return (NULL);
157
158 if (!SES_WITHIN_PAGE(data, sizeof (*dp), data, pagelen))
159 return (NULL);
160
161 /*
162 * This variable-length list of variable-length strings format sucks
163 * for performance; we ALWAYS have to walk the whole bloody thing to
164 * find a particular node's entry.
165 */
166 for (i = 0, dp = (ses2_elem_descriptor_impl_t *)edip->sedpi_data;
167 i < index; i++) {
168
169 if (!SES_WITHIN_PAGE_STRUCT(dp, data, pagelen))
170 return (NULL);
171
172 dlen = SCSI_READ16(&dp->sedi_descriptor_length);
173
174 dp = (ses2_elem_descriptor_impl_t *)
175 ((uint8_t *)dp->sedi_descriptor + dlen);
176 }
177
178 if (!SES_WITHIN_PAGE_STRUCT(dp, data, pagelen))
179 return (NULL);
180
181 *len = SCSI_READ16(&dp->sedi_descriptor_length);
182
183 if (!SES_WITHIN_PAGE(dp,
184 *len + offsetof(ses2_elem_descriptor_impl_t, sedi_descriptor),
185 data, pagelen))
186 return (NULL);
187
188 return (dp->sedi_descriptor);
189 }
190
191 /*ARGSUSED*/
192 static void *
ses2_status_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)193 ses2_status_index(ses_plugin_t *sp, ses_node_t *np, void *data,
194 size_t pagelen, size_t *len)
195 {
196 uint64_t index;
197 nvlist_t *props = ses_node_props(np);
198 ses2_status_page_impl_t *spip = data;
199
200 if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
201 &index) != 0)
202 return (NULL);
203
204 if ((index + 1) * sizeof (ses2_elem_status_impl_t) +
205 offsetof(ses2_status_page_impl_t, sspi_data) > pagelen)
206 return (NULL);
207
208 *len = sizeof (ses2_elem_status_impl_t);
209 return ((ses2_elem_status_impl_t *)spip->sspi_data + index);
210 }
211
212 /*ARGSUSED*/
213 static size_t
ses2_ctl_len(uint_t nelem,int page,size_t datalen)214 ses2_ctl_len(uint_t nelem, int page, size_t datalen)
215 {
216 ASSERT(page == SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS);
217
218 return (nelem * sizeof (ses2_elem_ctl_impl_t) +
219 offsetof(ses2_control_page_impl_t, scpi_data[0]));
220 }
221
222 /*ARGSUSED*/
223 static void *
ses2_ctl_fill(ses_plugin_t * sp,void * pagedata,size_t pagelen,ses_node_t * np)224 ses2_ctl_fill(ses_plugin_t *sp, void *pagedata, size_t pagelen,
225 ses_node_t *np)
226 {
227 uint64_t index;
228 nvlist_t *props = ses_node_props(np);
229 ses2_control_page_impl_t *pip = pagedata;
230 void *data;
231 ses2_diag_page_t page = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS;
232
233 if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
234 &index) != 0) {
235 (void) ses_error(ESES_BAD_RESPONSE, "missing element index "
236 "for enclosure node");
237 return (NULL);
238 }
239
240 data = &pip->scpi_data[index];
241
242 if (ses2_ctl_common_setdef(np, page, data) != 0 ||
243 ses2_element_setdef(np, page, data) != 0 ||
244 ses2_enclosure_setdef(np, page, data) != 0)
245 return (NULL);
246
247 return (data);
248 }
249
250 /*ARGSUSED*/
251 static size_t
ses2_stringout_len(uint_t nelem,int page,size_t datalen)252 ses2_stringout_len(uint_t nelem, int page, size_t datalen)
253 {
254 ASSERT(page == SES2_DIAGPAGE_STRING_IO);
255
256 return (datalen + offsetof(ses2_string_out_page_impl_t, ssopi_data[0]));
257 }
258
259 /*ARGSUSED*/
260 static size_t
ses2_threshout_len(uint_t nelem,int page,size_t datalen)261 ses2_threshout_len(uint_t nelem, int page, size_t datalen)
262 {
263 ASSERT(page == SES2_DIAGPAGE_THRESHOLD_IO);
264
265 return (nelem * sizeof (ses2_threshold_impl_t) +
266 offsetof(ses2_threshold_out_page_impl_t, stopi_thresholds[0]));
267 }
268
269 /*ARGSUSED*/
270 static void *
ses2_threshout_ctl_fill(ses_plugin_t * sp,void * pagedata,size_t pagelen,ses_node_t * np)271 ses2_threshout_ctl_fill(ses_plugin_t *sp, void *pagedata, size_t pagelen,
272 ses_node_t *np)
273 {
274 uint64_t index;
275 nvlist_t *props = ses_node_props(np);
276 ses2_threshold_out_page_impl_t *pip = pagedata;
277 ses2_diag_page_t page = SES2_DIAGPAGE_THRESHOLD_IO;
278 void *data;
279
280 VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
281 &index) == 0);
282
283 data = &pip[index];
284
285 if (ses2_ctl_common_setdef(np, page, data) != 0 ||
286 ses2_element_setdef(np, page, data) != 0 ||
287 ses2_enclosure_setdef(np, page, data) != 0)
288 return (NULL);
289
290 return (data);
291 }
292
293 /*ARGSUSED*/
294 static size_t
ses2_substrout_len(uint_t nelem,int page,size_t datalen)295 ses2_substrout_len(uint_t nelem, int page, size_t datalen)
296 {
297 ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO);
298
299 return (datalen +
300 offsetof(ses2_substring_out_page_impl_t, ssopi_data[0]));
301 }
302
303 /*ARGSUSED*/
304 static size_t
ses2_ucodeout_len(uint_t nelem,int page,size_t datalen)305 ses2_ucodeout_len(uint_t nelem, int page, size_t datalen)
306 {
307 size_t len;
308
309 ASSERT(page == SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS);
310
311 len = datalen +
312 offsetof(ses2_ucode_ctl_page_impl_t, sucpi_ucode_data[0]);
313
314 return (P2ROUNDUP(len, 4));
315 }
316
317 /*ARGSUSED*/
318 static void *
ses2_ucodeout_ctl_fill(ses_plugin_t * sp,void * data,size_t pagelen,ses_node_t * np)319 ses2_ucodeout_ctl_fill(ses_plugin_t *sp, void *data, size_t pagelen,
320 ses_node_t *np)
321 {
322 ses_snap_t *snap = ses_node_snapshot(np);
323 nvlist_t *props = ses_node_props(np);
324 ses2_ucode_ctl_page_impl_t *uip = data;
325 uint64_t eid;
326
327 if (ses_node_type(np) != SES_NODE_ENCLOSURE) {
328 (void) ses_error(ESES_BAD_TYPE,
329 "microcode download page only valid for enclosure "
330 "nodes");
331 return (NULL);
332 }
333
334 VERIFY(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &eid) == 0);
335
336 SCSI_WRITE32(&uip->sucpi_generation_code,
337 ses_snap_generation(snap));
338 uip->sucpi_subenclosure_identifier = eid;
339
340 return (data);
341 }
342
343 /*ARGSUSED*/
344 static size_t
ses2_subnickout_len(uint_t nelem,int page,size_t datalen)345 ses2_subnickout_len(uint_t nelem, int page, size_t datalen)
346 {
347 ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS);
348
349 return (sizeof (ses2_subnick_ctl_page_impl_t));
350 }
351
352 ses_pagedesc_t ses2_pages[] = {
353 {
354 .spd_pagenum = SES2_DIAGPAGE_SUPPORTED_PAGES,
355 .spd_req = SES_REQ_MANDATORY_ALL,
356 .spd_gcoff = -1
357 },
358 {
359 .spd_pagenum = SES2_DIAGPAGE_CONFIG,
360 .spd_req = SES_REQ_MANDATORY_STANDARD,
361 .spd_gcoff = offsetof(ses2_config_page_impl_t, scpi_generation_code)
362 },
363 {
364 .spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
365 .spd_req = SES_REQ_MANDATORY_STANDARD,
366 .spd_index = ses2_status_index,
367 .spd_gcoff = offsetof(ses2_status_page_impl_t, sspi_generation_code)
368 },
369 {
370 .spd_pagenum = SES2_DIAGPAGE_HELP_TEXT,
371 .spd_req = SES_REQ_OPTIONAL_STANDARD,
372 .spd_gcoff = -1
373 },
374 {
375 .spd_pagenum = SES2_DIAGPAGE_STRING_IO,
376 .spd_req = SES_REQ_OPTIONAL_STANDARD,
377 .spd_gcoff = -1
378 },
379 {
380 .spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO,
381 .spd_index = ses2_threshold_index,
382 .spd_req = SES_REQ_OPTIONAL_STANDARD,
383 .spd_gcoff =
384 offsetof(ses2_threshold_in_page_impl_t, stipi_generation_code)
385 },
386 {
387 .spd_pagenum = SES2_DIAGPAGE_ELEMENT_DESC,
388 .spd_index = ses2_element_index,
389 .spd_req = SES_REQ_OPTIONAL_STANDARD,
390 .spd_gcoff = offsetof(ses2_elem_desc_page_impl_t, sedpi_generation_code)
391 },
392 {
393 .spd_pagenum = SES2_DIAGPAGE_ADDL_ELEM_STATUS,
394 .spd_index = ses2_aes_index,
395 .spd_req = SES_REQ_OPTIONAL_STANDARD,
396 .spd_gcoff = offsetof(ses2_aes_page_impl_t, sapi_generation_code)
397 },
398 {
399 .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT,
400 .spd_req = SES_REQ_OPTIONAL_STANDARD,
401 .spd_gcoff = offsetof(ses2_subhelp_page_impl_t, sspi_generation_code)
402 },
403 {
404 .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO,
405 .spd_req = SES_REQ_OPTIONAL_STANDARD,
406 .spd_gcoff =
407 offsetof(ses2_substring_in_page_impl_t, ssipi_generation_code)
408 },
409 {
410 .spd_pagenum = SES2_DIAGPAGE_SUPPORTED_SES_PAGES,
411 .spd_req = SES_REQ_OPTIONAL_STANDARD,
412 .spd_gcoff = -1
413 },
414 {
415 .spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS,
416 .spd_req = SES_REQ_OPTIONAL_STANDARD,
417 .spd_gcoff =
418 offsetof(ses2_ucode_status_page_impl_t, suspi_generation_code)
419 },
420 {
421 .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
422 .spd_req = SES_REQ_OPTIONAL_STANDARD,
423 .spd_gcoff =
424 offsetof(ses2_subnick_status_page_impl_t, sspci_generation_code)
425 },
426 /* Control pages */
427 {
428 .spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
429 .spd_ctl_len = ses2_ctl_len,
430 .spd_ctl_fill = ses2_ctl_fill,
431 .spd_req = SES_REQ_MANDATORY_STANDARD,
432 .spd_gcoff = offsetof(ses2_control_page_impl_t, scpi_generation_code)
433 },
434 {
435 .spd_pagenum = SES2_DIAGPAGE_STRING_IO,
436 .spd_ctl_len = ses2_stringout_len,
437 .spd_req = SES_REQ_OPTIONAL_STANDARD,
438 .spd_gcoff = -1
439 },
440 {
441 .spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO,
442 .spd_ctl_len = ses2_threshout_len,
443 .spd_ctl_fill = ses2_threshout_ctl_fill,
444 .spd_req = SES_REQ_OPTIONAL_STANDARD,
445 .spd_gcoff =
446 offsetof(ses2_threshold_out_page_impl_t, stopi_generation_code)
447 },
448 {
449 .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO,
450 .spd_ctl_len = ses2_substrout_len,
451 .spd_req = SES_REQ_OPTIONAL_STANDARD,
452 .spd_gcoff =
453 offsetof(ses2_substring_out_page_impl_t, ssopi_generation_code)
454 },
455 {
456 .spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS,
457 .spd_ctl_len = ses2_ucodeout_len,
458 .spd_ctl_fill = ses2_ucodeout_ctl_fill,
459 .spd_req = SES_REQ_OPTIONAL_STANDARD,
460 .spd_gcoff =
461 offsetof(ses2_ucode_ctl_page_impl_t, sucpi_generation_code)
462 },
463 {
464 .spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
465 .spd_ctl_len = ses2_subnickout_len,
466 .spd_req = SES_REQ_OPTIONAL_STANDARD,
467 .spd_gcoff =
468 offsetof(ses2_subnick_ctl_page_impl_t, sspci_generation_code)
469 },
470 {
471 .spd_pagenum = -1,
472 .spd_gcoff = -1
473 }
474 };
475