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 /*
23ac88567aSHyon Kim  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24275c9da8Seschrock  */
25a8be79faSAlexander Stetsenko /*
26a8be79faSAlexander Stetsenko  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
27*3fa8bc2dSGarrett D'Amore  * Copyright 2019 RackTop Systems
28a8be79faSAlexander Stetsenko  */
29275c9da8Seschrock 
30275c9da8Seschrock #include <stddef.h>
31275c9da8Seschrock #include <strings.h>
32275c9da8Seschrock 
33275c9da8Seschrock #include <scsi/libses.h>
34275c9da8Seschrock #include <scsi/libses_plugin.h>
35275c9da8Seschrock #include <scsi/plugins/ses/framework/ses2.h>
36275c9da8Seschrock 
37275c9da8Seschrock #include "ses2_impl.h"
38275c9da8Seschrock 
39275c9da8Seschrock static int
ses2_ctl_common_setdef(ses_node_t * np,ses2_diag_page_t page,void * data)40275c9da8Seschrock ses2_ctl_common_setdef(ses_node_t *np, ses2_diag_page_t page, void *data)
41275c9da8Seschrock {
42275c9da8Seschrock 	ses2_cmn_elem_ctl_impl_t *eip = data;
43275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
44275c9da8Seschrock 
45275c9da8Seschrock 	if (page != SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS)
46275c9da8Seschrock 		return (0);
47275c9da8Seschrock 
48275c9da8Seschrock 	SES_NV_CTLBOOL_INVERT(props, SES_PROP_SWAP, eip->seci_rst_swap);
49275c9da8Seschrock 	SES_NV_CTLBOOL(props, SES_PROP_DISABLED, eip->seci_disable);
50275c9da8Seschrock 	SES_NV_CTLBOOL(props, SES_PROP_PRDFAIL, eip->seci_prdfail);
51275c9da8Seschrock 
52275c9da8Seschrock 	eip->seci_select = 1;
53275c9da8Seschrock 
54275c9da8Seschrock 	return (0);
55275c9da8Seschrock }
56275c9da8Seschrock 
57275c9da8Seschrock /*ARGSUSED*/
58275c9da8Seschrock static void *
ses2_aes_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)59275c9da8Seschrock ses2_aes_index(ses_plugin_t *sp, ses_node_t *np, void *data, size_t pagelen,
60275c9da8Seschrock     size_t *len)
61275c9da8Seschrock {
62275c9da8Seschrock 	ses2_aes_page_impl_t *apip = data;
63*3fa8bc2dSGarrett D'Amore 	uint64_t index, eindex, oindex, type;
64275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
65275c9da8Seschrock 	ses2_aes_descr_eip_impl_t *dep;
66275c9da8Seschrock 	size_t desclen;
67275c9da8Seschrock 	int i, pos;
68275c9da8Seschrock 
69ed0f0083SHyon Kim 	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_ONLY_INDEX,
70*3fa8bc2dSGarrett D'Amore 	    &eindex) == 0);
71*3fa8bc2dSGarrett D'Amore 	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
72*3fa8bc2dSGarrett D'Amore 	    &oindex) == 0);
73275c9da8Seschrock 	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE,
74275c9da8Seschrock 	    &type) == 0);
75275c9da8Seschrock 
76275c9da8Seschrock 	if (pagelen < offsetof(ses2_aes_page_impl_t, sapi_data))
77275c9da8Seschrock 		return (0);
78275c9da8Seschrock 
79275c9da8Seschrock 	for (dep = (ses2_aes_descr_eip_impl_t *)apip->sapi_data, pos = 0, i = 0;
80275c9da8Seschrock 	    pos < SCSI_READ16(&apip->sapi_page_length);
81275c9da8Seschrock 	    dep = (ses2_aes_descr_eip_impl_t *)(apip->sapi_data + pos), i++) {
82275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(dep, data, pagelen))
83275c9da8Seschrock 			break;
84275c9da8Seschrock 
85275c9da8Seschrock 		desclen = dep->sadei_length +
86275c9da8Seschrock 		    offsetof(ses2_aes_descr_eip_impl_t, sadei_length) +
87275c9da8Seschrock 		    sizeof (dep->sadei_length);
88275c9da8Seschrock 
89275c9da8Seschrock 		if (!SES_WITHIN_PAGE(dep, desclen, data, pagelen))
90275c9da8Seschrock 			break;
91275c9da8Seschrock 
92*3fa8bc2dSGarrett D'Amore 		if (dep->sadei_eip) {
93*3fa8bc2dSGarrett D'Amore 			/*
94*3fa8bc2dSGarrett D'Amore 			 * The following switch table deals with the cases
95*3fa8bc2dSGarrett D'Amore 			 * for the EIIOE (element index includes overall
96*3fa8bc2dSGarrett D'Amore 			 * elements).  The treatment for this includes handling
97*3fa8bc2dSGarrett D'Amore 			 * connector and other element indices, but we don't
98*3fa8bc2dSGarrett D'Amore 			 * actually care about or use them, so for now we
99*3fa8bc2dSGarrett D'Amore 			 * really only care about the ELEMENT INDEX field.
100*3fa8bc2dSGarrett D'Amore 			 */
101*3fa8bc2dSGarrett D'Amore 			switch (dep->sadei_eiioe) {
102*3fa8bc2dSGarrett D'Amore 			case 1:
103*3fa8bc2dSGarrett D'Amore 				/*
104*3fa8bc2dSGarrett D'Amore 				 * Use the overall index.  We expect most
105*3fa8bc2dSGarrett D'Amore 				 * modern implementations to use this case.
106*3fa8bc2dSGarrett D'Amore 				 */
107*3fa8bc2dSGarrett D'Amore 				index = oindex;
108*3fa8bc2dSGarrett D'Amore 				break;
109*3fa8bc2dSGarrett D'Amore 			case 0:
110*3fa8bc2dSGarrett D'Amore 			case 2:
111*3fa8bc2dSGarrett D'Amore 			case 3:
112*3fa8bc2dSGarrett D'Amore 				/*
113*3fa8bc2dSGarrett D'Amore 				 * Use the element only index - excluding
114*3fa8bc2dSGarrett D'Amore 				 * the overall elements.
115*3fa8bc2dSGarrett D'Amore 				 */
116*3fa8bc2dSGarrett D'Amore 				index = eindex;
117*3fa8bc2dSGarrett D'Amore 				break;
118*3fa8bc2dSGarrett D'Amore 			}
119*3fa8bc2dSGarrett D'Amore 		}
120275c9da8Seschrock 		pos += desclen;
121275c9da8Seschrock 		if (!dep->sadei_eip &&
122275c9da8Seschrock 		    type != SES_ET_DEVICE &&
123275c9da8Seschrock 		    type != SES_ET_ARRAY_DEVICE) {
124275c9da8Seschrock 			/*
125275c9da8Seschrock 			 * We can't really do anything with this, because
126275c9da8Seschrock 			 * while the standard requires that these descriptors
127275c9da8Seschrock 			 * be in the same order as those in the status page,
128275c9da8Seschrock 			 * some element types may optionally include AES
129275c9da8Seschrock 			 * data.  This means we cannot know which element
130275c9da8Seschrock 			 * this descriptor refers to unless EIP is 1.  Sadly,
131275c9da8Seschrock 			 * the standard only says that this "should" be true.
132275c9da8Seschrock 			 * It's impossible to guess what use this is supposed
133275c9da8Seschrock 			 * to have otherwise.  See 6.1.13.1.
134275c9da8Seschrock 			 */
135275c9da8Seschrock 			continue;
136*3fa8bc2dSGarrett D'Amore 		} else if (dep->sadei_eip) {
137*3fa8bc2dSGarrett D'Amore 			if (dep->sadei_element_index == index) {
138*3fa8bc2dSGarrett D'Amore 				*len = desclen;
139*3fa8bc2dSGarrett D'Amore 				return (dep);
140*3fa8bc2dSGarrett D'Amore 			}
141ed0f0083SHyon Kim 			/*
142ed0f0083SHyon Kim 			 * The element index field from AES descriptor is
143ed0f0083SHyon Kim 			 * element only index which doesn't include the OVERALL
144ed0f0083SHyon Kim 			 * STATUS fields so we should compare with
145ed0f0083SHyon Kim 			 * SES_PROP_ELEMENT_ONLY_INDEX not
146ed0f0083SHyon Kim 			 * SES_PROP_ELEMENT_INDEX.
147ed0f0083SHyon Kim 			 */
148275c9da8Seschrock 			continue;
149*3fa8bc2dSGarrett D'Amore 		} else if (i == eindex) {
150275c9da8Seschrock 			*len = desclen;
151275c9da8Seschrock 			return (dep);
152275c9da8Seschrock 		}
153275c9da8Seschrock 	}
154275c9da8Seschrock 
155275c9da8Seschrock 	return (NULL);
156275c9da8Seschrock }
157275c9da8Seschrock 
158275c9da8Seschrock /*ARGSUSED*/
159275c9da8Seschrock static void *
ses2_threshold_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)160275c9da8Seschrock ses2_threshold_index(ses_plugin_t *sp, ses_node_t *np, void *data,
161275c9da8Seschrock     size_t pagelen, size_t *len)
162275c9da8Seschrock {
163275c9da8Seschrock 	uint64_t index;
164275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
165275c9da8Seschrock 	ses2_threshold_in_page_impl_t *tpip = data;
166275c9da8Seschrock 	ses2_threshold_impl_t *tp;
167275c9da8Seschrock 
168275c9da8Seschrock 	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
169275c9da8Seschrock 	    &index) == 0);
170275c9da8Seschrock 
171275c9da8Seschrock 	*len = sizeof (ses2_threshold_impl_t);
172275c9da8Seschrock 	tp = &tpip->stipi_thresholds[index];
173275c9da8Seschrock 
174275c9da8Seschrock 	if (!SES_WITHIN_PAGE_STRUCT(tp, data, pagelen))
175275c9da8Seschrock 		return (NULL);
176275c9da8Seschrock 
177275c9da8Seschrock 	return (&tpip->stipi_thresholds[index]);
178275c9da8Seschrock }
179275c9da8Seschrock 
180275c9da8Seschrock /*ARGSUSED*/
181275c9da8Seschrock static void *
ses2_element_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)182275c9da8Seschrock ses2_element_index(ses_plugin_t *sp, ses_node_t *np, void *data,
183275c9da8Seschrock     size_t pagelen, size_t *len)
184275c9da8Seschrock {
185275c9da8Seschrock 	uint64_t index;
186275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
187275c9da8Seschrock 	ses2_elem_desc_page_impl_t *edip = data;
188275c9da8Seschrock 	ses2_elem_descriptor_impl_t *dp;
189275c9da8Seschrock 	int i;
190275c9da8Seschrock 	uint16_t dlen;
191275c9da8Seschrock 
192275c9da8Seschrock 	if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX, &index) != 0)
193275c9da8Seschrock 		return (NULL);
194275c9da8Seschrock 
195275c9da8Seschrock 	if (!SES_WITHIN_PAGE(data, sizeof (*dp), data, pagelen))
196275c9da8Seschrock 		return (NULL);
197275c9da8Seschrock 
198275c9da8Seschrock 	/*
199275c9da8Seschrock 	 * This variable-length list of variable-length strings format sucks
200275c9da8Seschrock 	 * for performance; we ALWAYS have to walk the whole bloody thing to
201275c9da8Seschrock 	 * find a particular node's entry.
202275c9da8Seschrock 	 */
203275c9da8Seschrock 	for (i = 0, dp = (ses2_elem_descriptor_impl_t *)edip->sedpi_data;
204275c9da8Seschrock 	    i < index; i++) {
205275c9da8Seschrock 
206275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(dp, data, pagelen))
207275c9da8Seschrock 			return (NULL);
208275c9da8Seschrock 
209275c9da8Seschrock 		dlen = SCSI_READ16(&dp->sedi_descriptor_length);
210275c9da8Seschrock 
211275c9da8Seschrock 		dp = (ses2_elem_descriptor_impl_t *)
212275c9da8Seschrock 		    ((uint8_t *)dp->sedi_descriptor + dlen);
213275c9da8Seschrock 	}
214275c9da8Seschrock 
215275c9da8Seschrock 	if (!SES_WITHIN_PAGE_STRUCT(dp, data, pagelen))
216275c9da8Seschrock 		return (NULL);
217275c9da8Seschrock 
218275c9da8Seschrock 	*len = SCSI_READ16(&dp->sedi_descriptor_length);
219275c9da8Seschrock 
220275c9da8Seschrock 	if (!SES_WITHIN_PAGE(dp,
221275c9da8Seschrock 	    *len + offsetof(ses2_elem_descriptor_impl_t, sedi_descriptor),
222275c9da8Seschrock 	    data, pagelen))
223275c9da8Seschrock 		return (NULL);
224275c9da8Seschrock 
225275c9da8Seschrock 	return (dp->sedi_descriptor);
226275c9da8Seschrock }
227275c9da8Seschrock 
228275c9da8Seschrock /*ARGSUSED*/
229275c9da8Seschrock static void *
ses2_status_index(ses_plugin_t * sp,ses_node_t * np,void * data,size_t pagelen,size_t * len)230275c9da8Seschrock ses2_status_index(ses_plugin_t *sp, ses_node_t *np, void *data,
231275c9da8Seschrock     size_t pagelen, size_t *len)
232275c9da8Seschrock {
233275c9da8Seschrock 	uint64_t index;
234275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
235275c9da8Seschrock 	ses2_status_page_impl_t *spip = data;
236275c9da8Seschrock 
237275c9da8Seschrock 	if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
238275c9da8Seschrock 	    &index) != 0)
239275c9da8Seschrock 		return (NULL);
240275c9da8Seschrock 
241275c9da8Seschrock 	if ((index + 1) * sizeof (ses2_elem_status_impl_t) +
242275c9da8Seschrock 	    offsetof(ses2_status_page_impl_t, sspi_data) > pagelen)
243275c9da8Seschrock 		return (NULL);
244275c9da8Seschrock 
245275c9da8Seschrock 	*len = sizeof (ses2_elem_status_impl_t);
246275c9da8Seschrock 	return ((ses2_elem_status_impl_t *)spip->sspi_data + index);
247275c9da8Seschrock }
248275c9da8Seschrock 
249275c9da8Seschrock /*ARGSUSED*/
250275c9da8Seschrock static size_t
ses2_ctl_len(uint_t nelem,int page,size_t datalen)251275c9da8Seschrock ses2_ctl_len(uint_t nelem, int page, size_t datalen)
252275c9da8Seschrock {
253275c9da8Seschrock 	ASSERT(page == SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS);
254275c9da8Seschrock 
255275c9da8Seschrock 	return (nelem * sizeof (ses2_elem_ctl_impl_t) +
256275c9da8Seschrock 	    offsetof(ses2_control_page_impl_t, scpi_data[0]));
257275c9da8Seschrock }
258275c9da8Seschrock 
259275c9da8Seschrock /*ARGSUSED*/
260275c9da8Seschrock static void *
ses2_ctl_fill(ses_plugin_t * sp,void * pagedata,size_t pagelen,ses_node_t * np)261275c9da8Seschrock ses2_ctl_fill(ses_plugin_t *sp, void *pagedata, size_t pagelen,
262275c9da8Seschrock     ses_node_t *np)
263275c9da8Seschrock {
264275c9da8Seschrock 	uint64_t index;
265275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
266275c9da8Seschrock 	ses2_control_page_impl_t *pip = pagedata;
267a8be79faSAlexander Stetsenko 	ses2_elem_ctl_impl_t *eip;
268275c9da8Seschrock 	void *data;
269275c9da8Seschrock 	ses2_diag_page_t page = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS;
270275c9da8Seschrock 
271275c9da8Seschrock 	if (nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
272275c9da8Seschrock 	    &index) != 0) {
273275c9da8Seschrock 		(void) ses_error(ESES_BAD_RESPONSE, "missing element index "
274275c9da8Seschrock 		    "for enclosure node");
275275c9da8Seschrock 		return (NULL);
276275c9da8Seschrock 	}
277275c9da8Seschrock 
278a8be79faSAlexander Stetsenko 	data = eip = &pip->scpi_data[index];
279a8be79faSAlexander Stetsenko 	/*
280a8be79faSAlexander Stetsenko 	 * if control element was already modified "select" field is non-zero,
281a8be79faSAlexander Stetsenko 	 * so skip setting default values to avoid fields overriding
282a8be79faSAlexander Stetsenko 	 */
283a8be79faSAlexander Stetsenko 	if (eip->seci_common.seci_select)
284a8be79faSAlexander Stetsenko 		return (data);
285275c9da8Seschrock 
286275c9da8Seschrock 	if (ses2_ctl_common_setdef(np, page, data) != 0 ||
287275c9da8Seschrock 	    ses2_element_setdef(np, page, data) != 0 ||
288275c9da8Seschrock 	    ses2_enclosure_setdef(np, page, data) != 0)
289275c9da8Seschrock 		return (NULL);
290275c9da8Seschrock 
291275c9da8Seschrock 	return (data);
292275c9da8Seschrock }
293275c9da8Seschrock 
294275c9da8Seschrock /*ARGSUSED*/
295275c9da8Seschrock static size_t
ses2_stringout_len(uint_t nelem,int page,size_t datalen)296275c9da8Seschrock ses2_stringout_len(uint_t nelem, int page, size_t datalen)
297275c9da8Seschrock {
298275c9da8Seschrock 	ASSERT(page == SES2_DIAGPAGE_STRING_IO);
299275c9da8Seschrock 
300275c9da8Seschrock 	return (datalen + offsetof(ses2_string_out_page_impl_t, ssopi_data[0]));
301275c9da8Seschrock }
302275c9da8Seschrock 
303275c9da8Seschrock /*ARGSUSED*/
304275c9da8Seschrock static size_t
ses2_threshout_len(uint_t nelem,int page,size_t datalen)305275c9da8Seschrock ses2_threshout_len(uint_t nelem, int page, size_t datalen)
306275c9da8Seschrock {
307275c9da8Seschrock 	ASSERT(page == SES2_DIAGPAGE_THRESHOLD_IO);
308275c9da8Seschrock 
309275c9da8Seschrock 	return (nelem * sizeof (ses2_threshold_impl_t) +
310275c9da8Seschrock 	    offsetof(ses2_threshold_out_page_impl_t, stopi_thresholds[0]));
311275c9da8Seschrock }
312275c9da8Seschrock 
313275c9da8Seschrock /*ARGSUSED*/
314275c9da8Seschrock static void *
ses2_threshout_ctl_fill(ses_plugin_t * sp,void * pagedata,size_t pagelen,ses_node_t * np)315275c9da8Seschrock ses2_threshout_ctl_fill(ses_plugin_t *sp, void *pagedata, size_t pagelen,
316275c9da8Seschrock     ses_node_t *np)
317275c9da8Seschrock {
318275c9da8Seschrock 	uint64_t index;
319275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
320275c9da8Seschrock 	ses2_threshold_out_page_impl_t *pip = pagedata;
321a8be79faSAlexander Stetsenko 	ses2_threshold_impl_t *tip;
322275c9da8Seschrock 	ses2_diag_page_t page = SES2_DIAGPAGE_THRESHOLD_IO;
323275c9da8Seschrock 	void *data;
324275c9da8Seschrock 
325275c9da8Seschrock 	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_INDEX,
326275c9da8Seschrock 	    &index) == 0);
327275c9da8Seschrock 
328a8be79faSAlexander Stetsenko 	data = tip = &pip->stopi_thresholds[index];
329275c9da8Seschrock 
330a8be79faSAlexander Stetsenko 	/* check if threshold is dirty, so no need to set default values */
331a8be79faSAlexander Stetsenko 	if ((tip->sti_high_crit | tip->sti_low_crit | tip->sti_high_warn |
332a8be79faSAlexander Stetsenko 	    tip->sti_low_warn) != 0)
333a8be79faSAlexander Stetsenko 		return (data);
334a8be79faSAlexander Stetsenko 
335a8be79faSAlexander Stetsenko 	if (ses2_element_setdef(np, page, data) != 0)
336275c9da8Seschrock 		return (NULL);
337275c9da8Seschrock 
338275c9da8Seschrock 	return (data);
339275c9da8Seschrock }
340275c9da8Seschrock 
341275c9da8Seschrock /*ARGSUSED*/
342275c9da8Seschrock static size_t
ses2_substrout_len(uint_t nelem,int page,size_t datalen)343275c9da8Seschrock ses2_substrout_len(uint_t nelem, int page, size_t datalen)
344275c9da8Seschrock {
345275c9da8Seschrock 	ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO);
346275c9da8Seschrock 
347275c9da8Seschrock 	return (datalen +
348275c9da8Seschrock 	    offsetof(ses2_substring_out_page_impl_t, ssopi_data[0]));
349275c9da8Seschrock }
350275c9da8Seschrock 
351275c9da8Seschrock /*ARGSUSED*/
352275c9da8Seschrock static size_t
ses2_ucodeout_len(uint_t nelem,int page,size_t datalen)353275c9da8Seschrock ses2_ucodeout_len(uint_t nelem, int page, size_t datalen)
354275c9da8Seschrock {
355275c9da8Seschrock 	size_t len;
356275c9da8Seschrock 
357275c9da8Seschrock 	ASSERT(page == SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS);
358275c9da8Seschrock 
359275c9da8Seschrock 	len = datalen +
360275c9da8Seschrock 	    offsetof(ses2_ucode_ctl_page_impl_t, sucpi_ucode_data[0]);
361275c9da8Seschrock 
362275c9da8Seschrock 	return (P2ROUNDUP(len, 4));
363275c9da8Seschrock }
364275c9da8Seschrock 
365275c9da8Seschrock /*ARGSUSED*/
366275c9da8Seschrock static void *
ses2_ucodeout_ctl_fill(ses_plugin_t * sp,void * data,size_t pagelen,ses_node_t * np)367275c9da8Seschrock ses2_ucodeout_ctl_fill(ses_plugin_t *sp, void *data, size_t pagelen,
368275c9da8Seschrock     ses_node_t *np)
369275c9da8Seschrock {
370275c9da8Seschrock 	ses_snap_t *snap = ses_node_snapshot(np);
371275c9da8Seschrock 	nvlist_t *props = ses_node_props(np);
372275c9da8Seschrock 	ses2_ucode_ctl_page_impl_t *uip = data;
373275c9da8Seschrock 	uint64_t eid;
374275c9da8Seschrock 
375275c9da8Seschrock 	if (ses_node_type(np) != SES_NODE_ENCLOSURE) {
376275c9da8Seschrock 		(void) ses_error(ESES_BAD_TYPE,
377275c9da8Seschrock 		    "microcode download page only valid for enclosure "
378275c9da8Seschrock 		    "nodes");
379275c9da8Seschrock 		return (NULL);
380275c9da8Seschrock 	}
381275c9da8Seschrock 
382275c9da8Seschrock 	VERIFY(nvlist_lookup_uint64(props, SES_EN_PROP_EID, &eid) == 0);
383275c9da8Seschrock 
384275c9da8Seschrock 	SCSI_WRITE32(&uip->sucpi_generation_code,
385275c9da8Seschrock 	    ses_snap_generation(snap));
386275c9da8Seschrock 	uip->sucpi_subenclosure_identifier = eid;
387275c9da8Seschrock 
388275c9da8Seschrock 	return (data);
389275c9da8Seschrock }
390275c9da8Seschrock 
391275c9da8Seschrock /*ARGSUSED*/
392275c9da8Seschrock static size_t
ses2_subnickout_len(uint_t nelem,int page,size_t datalen)393275c9da8Seschrock ses2_subnickout_len(uint_t nelem, int page, size_t datalen)
394275c9da8Seschrock {
395275c9da8Seschrock 	ASSERT(page == SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS);
396275c9da8Seschrock 
397275c9da8Seschrock 	return (sizeof (ses2_subnick_ctl_page_impl_t));
398275c9da8Seschrock }
399275c9da8Seschrock 
400275c9da8Seschrock ses_pagedesc_t ses2_pages[] = {
401275c9da8Seschrock {
402275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_SUPPORTED_PAGES,
403ac88567aSHyon Kim 	.spd_req = SES_REQ_MANDATORY_ALL,
404275c9da8Seschrock 	.spd_gcoff = -1
405275c9da8Seschrock },
406275c9da8Seschrock {
407275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_CONFIG,
408ac88567aSHyon Kim 	.spd_req = SES_REQ_MANDATORY_STANDARD,
409275c9da8Seschrock 	.spd_gcoff = offsetof(ses2_config_page_impl_t, scpi_generation_code)
410275c9da8Seschrock },
411275c9da8Seschrock {
412275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
413ac88567aSHyon Kim 	.spd_req = SES_REQ_MANDATORY_STANDARD,
414275c9da8Seschrock 	.spd_index = ses2_status_index,
415275c9da8Seschrock 	.spd_gcoff = offsetof(ses2_status_page_impl_t, sspi_generation_code)
416275c9da8Seschrock },
417275c9da8Seschrock {
418275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_HELP_TEXT,
419ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
420275c9da8Seschrock 	.spd_gcoff = -1
421275c9da8Seschrock },
422275c9da8Seschrock {
423275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_STRING_IO,
424ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
425275c9da8Seschrock 	.spd_gcoff = -1
426275c9da8Seschrock },
427275c9da8Seschrock {
428275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO,
429275c9da8Seschrock 	.spd_index = ses2_threshold_index,
430ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
431275c9da8Seschrock 	.spd_gcoff =
432275c9da8Seschrock 	    offsetof(ses2_threshold_in_page_impl_t, stipi_generation_code)
433275c9da8Seschrock },
434275c9da8Seschrock {
435275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_ELEMENT_DESC,
436275c9da8Seschrock 	.spd_index = ses2_element_index,
437ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
438275c9da8Seschrock 	.spd_gcoff = offsetof(ses2_elem_desc_page_impl_t, sedpi_generation_code)
439275c9da8Seschrock },
440275c9da8Seschrock {
441275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_ADDL_ELEM_STATUS,
442275c9da8Seschrock 	.spd_index = ses2_aes_index,
443ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
444275c9da8Seschrock 	.spd_gcoff = offsetof(ses2_aes_page_impl_t, sapi_generation_code)
445275c9da8Seschrock },
446275c9da8Seschrock {
447275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_HELP_TEXT,
448ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
449275c9da8Seschrock 	.spd_gcoff = offsetof(ses2_subhelp_page_impl_t, sspi_generation_code)
450275c9da8Seschrock },
451275c9da8Seschrock {
452275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO,
453ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
454275c9da8Seschrock 	.spd_gcoff =
455275c9da8Seschrock 	    offsetof(ses2_substring_in_page_impl_t, ssipi_generation_code)
456275c9da8Seschrock },
457275c9da8Seschrock {
458275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_SUPPORTED_SES_PAGES,
459ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
460275c9da8Seschrock 	.spd_gcoff = -1
461275c9da8Seschrock },
462275c9da8Seschrock {
463275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS,
464ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
465275c9da8Seschrock 	.spd_gcoff =
466275c9da8Seschrock 	    offsetof(ses2_ucode_status_page_impl_t, suspi_generation_code)
467275c9da8Seschrock },
468275c9da8Seschrock {
469275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
470ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
471275c9da8Seschrock 	.spd_gcoff =
472275c9da8Seschrock 	    offsetof(ses2_subnick_status_page_impl_t, sspci_generation_code)
473275c9da8Seschrock },
474275c9da8Seschrock /* Control pages */
475275c9da8Seschrock {
476275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
477275c9da8Seschrock 	.spd_ctl_len = ses2_ctl_len,
478275c9da8Seschrock 	.spd_ctl_fill = ses2_ctl_fill,
479ac88567aSHyon Kim 	.spd_req = SES_REQ_MANDATORY_STANDARD,
480275c9da8Seschrock 	.spd_gcoff = offsetof(ses2_control_page_impl_t, scpi_generation_code)
481275c9da8Seschrock },
482275c9da8Seschrock {
483275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_STRING_IO,
484275c9da8Seschrock 	.spd_ctl_len = ses2_stringout_len,
485ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
486275c9da8Seschrock 	.spd_gcoff = -1
487275c9da8Seschrock },
488275c9da8Seschrock {
489275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_THRESHOLD_IO,
490275c9da8Seschrock 	.spd_ctl_len = ses2_threshout_len,
491275c9da8Seschrock 	.spd_ctl_fill = ses2_threshout_ctl_fill,
492ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
493275c9da8Seschrock 	.spd_gcoff =
494275c9da8Seschrock 	    offsetof(ses2_threshold_out_page_impl_t, stopi_generation_code)
495275c9da8Seschrock },
496275c9da8Seschrock {
497275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_STRING_IO,
498275c9da8Seschrock 	.spd_ctl_len = ses2_substrout_len,
499ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
500275c9da8Seschrock 	.spd_gcoff =
501275c9da8Seschrock 	    offsetof(ses2_substring_out_page_impl_t, ssopi_generation_code)
502275c9da8Seschrock },
503275c9da8Seschrock {
504275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_DL_MICROCODE_CTL_STATUS,
505275c9da8Seschrock 	.spd_ctl_len = ses2_ucodeout_len,
506275c9da8Seschrock 	.spd_ctl_fill = ses2_ucodeout_ctl_fill,
507ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
508275c9da8Seschrock 	.spd_gcoff =
509275c9da8Seschrock 	    offsetof(ses2_ucode_ctl_page_impl_t, sucpi_generation_code)
510275c9da8Seschrock },
511275c9da8Seschrock {
512275c9da8Seschrock 	.spd_pagenum = SES2_DIAGPAGE_SUBENCLOSURE_NICKNAME_CTL_STATUS,
513275c9da8Seschrock 	.spd_ctl_len = ses2_subnickout_len,
514ac88567aSHyon Kim 	.spd_req = SES_REQ_OPTIONAL_STANDARD,
515275c9da8Seschrock 	.spd_gcoff =
516275c9da8Seschrock 	    offsetof(ses2_subnick_ctl_page_impl_t, sspci_generation_code)
517275c9da8Seschrock },
518275c9da8Seschrock {
519275c9da8Seschrock 	.spd_pagenum = -1,
520275c9da8Seschrock 	.spd_gcoff = -1
521275c9da8Seschrock }
522275c9da8Seschrock };
523