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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
25  * Use is subject to license terms.
26  */
27 /*
28  * Copyright 2019 RackTop Systems.
29  */
30 
31 #include <sys/types.h>
32 #include <stddef.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <libnvpair.h>
36 
37 #include <scsi/libses.h>
38 #include "ses2_impl.h"
39 
40 static int
41 elem_parse_device(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
42 {
43 	ses2_device_status_impl_t *dip = (ses2_device_status_impl_t *)esip;
44 	int nverr;
45 
46 	SES_NV_ADD(uint64, nverr, nvl, SES_DEV_PROP_SLOT_ADDR,
47 	    dip->sdsi_slot_addr);
48 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT,
49 	    dip->sdsi_report);
50 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
51 	    dip->sdsi_ident);
52 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_RMV, dip->sdsi_rmv);
53 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_READY_TO_INSERT,
54 	    dip->sdsi_ready_to_insert);
55 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_B,
56 	    dip->sdsi_enclosure_bypassed_b);
57 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_A,
58 	    dip->sdsi_enclosure_bypassed_a);
59 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DO_NOT_REMOVE,
60 	    dip->sdsi_do_not_remove);
61 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_A,
62 	    dip->sdsi_app_client_bypassed_a);
63 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_B,
64 	    dip->sdsi_device_bypassed_b);
65 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_A,
66 	    dip->sdsi_device_bypassed_a);
67 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_B,
68 	    dip->sdsi_bypassed_b);
69 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_A,
70 	    dip->sdsi_bypassed_a);
71 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF,
72 	    dip->sdsi_device_off);
73 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_RQSTD,
74 	    dip->sdsi_fault_reqstd);
75 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_SENSED,
76 	    dip->sdsi_fault_sensed);
77 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_B,
78 	    dip->sdsi_app_client_bypassed_b);
79 
80 	return (0);
81 }
82 
83 static int
84 elem_parse_psu(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
85 {
86 	ses2_psu_status_impl_t *pip = (ses2_psu_status_impl_t *)esip;
87 	int nverr;
88 
89 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
90 	    pip->spsi_ident);
91 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_OVER_CURRENT,
92 	    pip->spsi_dc_over_current);
93 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_UNDER_VOLTAGE,
94 	    pip->spsi_dc_under_voltage);
95 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_OVER_VOLTAGE,
96 	    pip->spsi_dc_over_voltage);
97 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_DC_FAIL,
98 	    pip->spsi_dc_fail);
99 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_AC_FAIL,
100 	    pip->spsi_ac_fail);
101 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_TEMP_WARN,
102 	    pip->spsi_temp_warn);
103 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PSU_PROP_OVERTEMP_FAIL,
104 	    pip->spsi_overtmp_fail);
105 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF, pip->spsi_off);
106 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REQUESTED_ON,
107 	    pip->spsi_rqsted_on);
108 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, pip->spsi_fail);
109 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_HOT_SWAP,
110 	    pip->spsi_hot_swap);
111 
112 	return (0);
113 }
114 
115 static int
116 elem_parse_cooling(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
117 {
118 	ses2_cooling_status_impl_t *cip = (ses2_cooling_status_impl_t *)esip;
119 	int nverr;
120 
121 	SES_NV_ADD(uint64, nverr, nvl, SES_COOLING_PROP_FAN_SPEED,
122 	    SES2_ES_COOLING_ST_FAN_SPEED(cip));
123 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
124 	    cip->scsi_ident);
125 	SES_NV_ADD(uint64, nverr, nvl, SES_COOLING_PROP_SPEED_CODE,
126 	    cip->scsi_actual_speed_code);
127 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF, cip->scsi_off);
128 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REQUESTED_ON,
129 	    cip->scsi_requested_on);
130 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail);
131 
132 	return (0);
133 }
134 
135 static int
136 elem_parse_temp(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
137 {
138 	ses2_temp_status_impl_t *tip = (ses2_temp_status_impl_t *)esip;
139 	int nverr;
140 
141 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, tip->stsi_ident);
142 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, tip->stsi_fail);
143 	SES_NV_ADD(int64, nverr, nvl, SES_TEMP_PROP_TEMP,
144 	    SES2_ES_TEMP_ST_TEMPERATURE(tip));
145 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_UNDER,
146 	    tip->stsi_ut_warn);
147 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_CRIT_UNDER,
148 	    tip->stsi_ut_fail);
149 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_OVER,
150 	    tip->stsi_ot_warn);
151 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_CRIT_OVER,
152 	    tip->stsi_ot_fail);
153 
154 	return (0);
155 }
156 
157 static int
158 elem_parse_lock(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
159 {
160 	ses2_lock_status_impl_t *lip = (ses2_lock_status_impl_t *)esip;
161 	int nverr;
162 
163 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL,
164 	    lip->slsi_fail);
165 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
166 	    lip->slsi_ident);
167 	SES_NV_ADD(boolean_value, nverr, nvl, SES_LOCK_PROP_UNLOCKED,
168 	    lip->slsi_unlocked);
169 
170 	return (0);
171 }
172 
173 static int
174 elem_parse_alarm(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
175 {
176 	ses2_alarm_status_impl_t *aip = (ses2_alarm_status_impl_t *)esip;
177 	int nverr;
178 
179 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, aip->sasi_fail);
180 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
181 	    aip->sasi_ident);
182 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_UNRECOV,
183 	    aip->sasi_unrecov);
184 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_CRIT,
185 	    aip->sasi_crit);
186 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_NONCRIT,
187 	    aip->sasi_noncrit);
188 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_INFO,
189 	    aip->sasi_info);
190 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_REMIND,
191 	    aip->sasi_remind);
192 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_MUTED,
193 	    aip->sasi_muted);
194 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ALARM_PROP_RQST_MUTE,
195 	    aip->sasi_rqst_mute);
196 
197 	return (0);
198 }
199 
200 static int
201 elem_parse_esc(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
202 {
203 	ses2_controller_status_impl_t *cip =
204 	    (ses2_controller_status_impl_t *)esip;
205 	int nverr;
206 
207 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail);
208 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, cip->scsi_ident);
209 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT,
210 	    cip->scsi_report);
211 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_HOT_SWAP,
212 	    cip->scsi_hot_swap);
213 
214 	return (0);
215 }
216 
217 static int
218 elem_parse_scc(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
219 {
220 	ses2_scc_status_impl_t *sip = (ses2_scc_status_impl_t *)esip;
221 	int nverr;
222 
223 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, sip->sss_fail);
224 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sip->sss_ident);
225 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT,
226 	    sip->sss_report);
227 
228 	return (0);
229 }
230 
231 static int
232 elem_parse_cache(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
233 {
234 	ses2_nvcache_status_impl_t *np = (ses2_nvcache_status_impl_t *)esip;
235 	int nverr;
236 
237 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, np->snsi_fail);
238 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
239 	    np->snsi_ident);
240 	SES_NV_ADD(uint64, nverr, nvl, SES_CACHE_PROP_SIZE,
241 	    SES2_NVCACHE_SIZE(np));
242 
243 	return (0);
244 }
245 
246 static int
247 elem_parse_ups(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
248 {
249 	ses2_ups_status_impl_t *uip = (ses2_ups_status_impl_t *)esip;
250 	int nverr;
251 
252 	SES_NV_ADD(uint64, nverr, nvl, SES_UPS_PROP_TIMELEFT,
253 	    uip->susi_battery_status);
254 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_INTF_FAIL,
255 	    uip->susi_intf_fail);
256 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_WARN,
257 	    uip->susi_warn);
258 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_UPS_FAIL,
259 	    uip->susi_ups_fail);
260 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_DC_FAIL,
261 	    uip->susi_dc_fail);
262 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_FAIL,
263 	    uip->susi_ac_fail);
264 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_QUAL,
265 	    uip->susi_ac_qual);
266 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_HI,
267 	    uip->susi_ac_hi);
268 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_AC_LO,
269 	    uip->susi_ac_lo);
270 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_BPF, uip->susi_bpf);
271 	SES_NV_ADD(boolean_value, nverr, nvl, SES_UPS_PROP_BATT_FAIL,
272 	    uip->susi_batt_fail);
273 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, uip->susi_fail);
274 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, uip->susi_ident);
275 
276 	return (0);
277 }
278 
279 static int
280 elem_parse_display(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
281 {
282 	ses2_display_status_impl_t *dip = (ses2_display_status_impl_t *)esip;
283 	int nverr;
284 
285 	SES_NV_ADD(uint64, nverr, nvl, SES_DPY_PROP_MODE,
286 	    dip->sdsi_display_mode_status);
287 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, dip->sdsi_fail);
288 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, dip->sdsi_ident);
289 	SES_NV_ADD(uint16, nverr, nvl, SES_DPY_PROP_CHAR,
290 	    dip->sdsi_display_character_status);
291 
292 	return (0);
293 }
294 
295 static int
296 elem_parse_keypad(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
297 {
298 	ses2_keypad_status_impl_t *kip = (ses2_keypad_status_impl_t *)esip;
299 	int nverr;
300 
301 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, kip->sksi_fail);
302 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, kip->sksi_ident);
303 
304 	return (0);
305 }
306 
307 static int
308 elem_parse_px(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
309 {
310 	ses2_port_status_impl_t *pip = (ses2_port_status_impl_t *)esip;
311 	int nverr;
312 
313 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, pip->spsi_fail);
314 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, pip->spsi_ident);
315 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT,
316 	    pip->spsi_report);
317 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PX_PROP_XMIT_FAIL,
318 	    pip->spsi_xmit_fail);
319 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PX_PROP_LOL, pip->spsi_lol);
320 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED,
321 	    pip->spsi_disabled);
322 
323 	return (0);
324 }
325 
326 static int
327 elem_parse_lang(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
328 {
329 	ses2_lang_status_impl_t *lip = (ses2_lang_status_impl_t *)esip;
330 	int nverr;
331 
332 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
333 	    lip->slsi_ident);
334 	SES_NV_ADD(uint64, nverr, nvl, SES_LANG_PROP_LANGCODE,
335 	    SCSI_READ16(&lip->slsi_language_code));
336 
337 	return (0);
338 }
339 
340 static int
341 elem_parse_comm(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
342 {
343 	ses2_comm_status_impl_t *cip = (ses2_comm_status_impl_t *)esip;
344 	int nverr;
345 
346 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail);
347 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
348 	    cip->scsi_ident);
349 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED,
350 	    cip->scsi_disabled);
351 
352 	return (0);
353 }
354 
355 static int
356 elem_parse_voltage(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
357 {
358 	ses2_voltage_status_impl_t *vip = (ses2_voltage_status_impl_t *)esip;
359 	int nverr;
360 
361 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_CRIT_UNDER,
362 	    vip->svsi_crit_under);
363 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_CRIT_OVER,
364 	    vip->svsi_crit_over);
365 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_UNDER,
366 	    vip->svsi_warn_under);
367 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_OVER,
368 	    vip->svsi_warn_over);
369 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, vip->svsi_fail);
370 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, vip->svsi_ident);
371 	SES_NV_ADD(int64, nverr, nvl, SES_VS_PROP_VOLTAGE_MV,
372 	    SCSI_READ16(&vip->svsi_voltage));
373 
374 	return (0);
375 }
376 
377 static int
378 elem_parse_current(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
379 {
380 	ses2_current_status_impl_t *cip = (ses2_current_status_impl_t *)esip;
381 	int nverr;
382 
383 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_CRIT_OVER,
384 	    cip->scsi_crit_over);
385 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_WARN_OVER,
386 	    cip->scsi_warn_over);
387 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, cip->scsi_fail);
388 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, cip->scsi_ident);
389 	SES_NV_ADD(int64, nverr, nvl, SES_CS_PROP_CURRENT_MA,
390 	    SCSI_READ16(&cip->scsi_current));
391 
392 	return (0);
393 }
394 
395 static int
396 elem_parse_itp(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
397 {
398 	ses2_itp_status_impl_t *iip = (ses2_itp_status_impl_t *)esip;
399 	int nverr;
400 
401 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, iip->sisi_fail);
402 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT,
403 	    iip->sisi_ident);
404 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT,
405 	    iip->sisi_report);
406 	SES_NV_ADD(boolean_value, nverr, nvl, SES_ITP_PROP_ENABLED,
407 	    iip->sisi_enabled);
408 
409 	return (0);
410 }
411 
412 static int
413 elem_parse_sse(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
414 {
415 	ses2_ss_status_impl_t *sip = (ses2_ss_status_impl_t *)esip;
416 	int nverr;
417 
418 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, sip->sss_fail);
419 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sip->sss_ident);
420 	SES_NV_ADD(uint64, nverr, nvl, SES_SS_PROP_SHORT_STATUS,
421 	    sip->sss_short_status);
422 
423 	return (0);
424 }
425 
426 static int
427 elem_parse_arraydev(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
428 {
429 	ses2_array_device_status_impl_t *aip =
430 	    (ses2_array_device_status_impl_t *)esip;
431 	int nverr;
432 
433 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_RR_ABORT,
434 	    aip->sadsi_rr_abort);
435 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_REBUILD,
436 	    aip->sadsi_rebuild);
437 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_IN_FAILED_ARRAY,
438 	    aip->sadsi_in_failed_array);
439 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_IN_CRIT_ARRAY,
440 	    aip->sadsi_in_crit_array);
441 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_CONS_CHK,
442 	    aip->sadsi_cons_chk);
443 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_HOT_SPARE,
444 	    aip->sadsi_hot_spare);
445 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_RSVD_DEVICE,
446 	    aip->sadsi_rsvd_device);
447 	SES_NV_ADD(boolean_value, nverr, nvl, SES_AD_PROP_OK, aip->sadsi_ok);
448 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_REPORT,
449 	    aip->sadsi_report);
450 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, aip->sadsi_ident);
451 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_RMV, aip->sadsi_rmv);
452 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_READY_TO_INSERT,
453 	    aip->sadsi_ready_to_insert);
454 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_B,
455 	    aip->sadsi_enclosure_bypassed_b);
456 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_ENC_BYP_A,
457 	    aip->sadsi_enclosure_bypassed_a);
458 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DO_NOT_REMOVE,
459 	    aip->sadsi_do_not_remove);
460 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_A,
461 	    aip->sadsi_app_client_bypassed_a);
462 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_B,
463 	    aip->sadsi_device_bypassed_b);
464 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_DEV_BYP_A,
465 	    aip->sadsi_device_bypassed_a);
466 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_B,
467 	    aip->sadsi_bypassed_b);
468 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_BYP_A,
469 	    aip->sadsi_bypassed_a);
470 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_OFF,
471 	    aip->sadsi_device_off);
472 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_RQSTD,
473 	    aip->sadsi_fault_reqstd);
474 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_FAULT_SENSED,
475 	    aip->sadsi_fault_sensed);
476 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_APP_BYP_B,
477 	    aip->sadsi_app_client_bypassed_b);
478 
479 	return (0);
480 }
481 
482 static int
483 elem_parse_expander(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
484 {
485 	ses2_expander_status_impl_t *eip = (ses2_expander_status_impl_t *)esip;
486 	int nverr;
487 
488 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, eip->sesi_fail);
489 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, eip->sesi_ident);
490 
491 	return (0);
492 }
493 
494 static int
495 elem_parse_sasconn(const ses2_elem_status_impl_t *esip, nvlist_t *nvl)
496 {
497 	ses2_sasconn_status_impl_t *sip = (ses2_sasconn_status_impl_t *)esip;
498 	int nverr;
499 
500 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_FAIL, sip->sss_fail);
501 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_IDENT, sip->sss_ident);
502 	SES_NV_ADD(uint64, nverr, nvl, SES_SC_PROP_CONNECTOR_TYPE,
503 	    sip->sss_connector_type);
504 	SES_NV_ADD(uint64, nverr, nvl, SES_SC_PROP_PHYSICAL_LINK,
505 	    sip->sss_connector_physical_link);
506 
507 	return (0);
508 }
509 
510 static const struct status_parser {
511 	ses2_element_type_t type;
512 	int (*func)(const ses2_elem_status_impl_t *, nvlist_t *);
513 } status_parsers[] = {
514 	{ SES_ET_DEVICE, elem_parse_device },
515 	{ SES_ET_POWER_SUPPLY, elem_parse_psu },
516 	{ SES_ET_COOLING, elem_parse_cooling },
517 	{ SES_ET_TEMPERATURE_SENSOR, elem_parse_temp },
518 	{ SES_ET_DOOR_LOCK, elem_parse_lock },
519 	{ SES_ET_AUDIBLE_ALARM, elem_parse_alarm },
520 	{ SES_ET_ESC_ELECTRONICS, elem_parse_esc },
521 	{ SES_ET_SCC_ELECTRONICS, elem_parse_scc },
522 	{ SES_ET_NONVOLATILE_CACHE, elem_parse_cache },
523 	{ SES_ET_UPS, elem_parse_ups },
524 	{ SES_ET_DISPLAY, elem_parse_display },
525 	{ SES_ET_KEY_PAD_ENTRY, elem_parse_keypad },
526 	{ SES_ET_SCSI_PORT_XCVR, elem_parse_px },
527 	{ SES_ET_LANGUAGE, elem_parse_lang },
528 	{ SES_ET_COMMUNICATION_PORT, elem_parse_comm },
529 	{ SES_ET_VOLTAGE_SENSOR, elem_parse_voltage },
530 	{ SES_ET_CURRENT_SENSOR, elem_parse_current },
531 	{ SES_ET_SCSI_TARGET_PORT, elem_parse_itp },
532 	{ SES_ET_SCSI_INITIATOR_PORT, elem_parse_itp },
533 	{ SES_ET_SIMPLE_SUBENCLOSURE, elem_parse_sse },
534 	{ SES_ET_ARRAY_DEVICE, elem_parse_arraydev },
535 	{ SES_ET_SAS_EXPANDER, elem_parse_expander },
536 	{ SES_ET_SAS_CONNECTOR, elem_parse_sasconn },
537 	{ (ses2_element_type_t)-1, NULL }
538 };
539 
540 static int
541 elem_parse_sd(ses_plugin_t *spp, ses_node_t *np)
542 {
543 	ses2_elem_status_impl_t *esip;
544 	const struct status_parser *sp;
545 	nvlist_t *nvl = ses_node_props(np);
546 	size_t len;
547 	int nverr;
548 	uint64_t type;
549 
550 	if ((esip = ses_plugin_page_lookup(spp,
551 	    ses_node_snapshot(np), SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
552 	    np, &len)) == NULL)
553 		return (0);
554 
555 	VERIFY(nvlist_lookup_uint64(nvl, SES_PROP_ELEMENT_TYPE,
556 	    &type) == 0);
557 
558 	SES_NV_ADD(uint64, nverr, nvl, SES_PROP_STATUS_CODE,
559 	    esip->sesi_common.sesi_status_code);
560 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_SWAP,
561 	    esip->sesi_common.sesi_swap);
562 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_DISABLED,
563 	    esip->sesi_common.sesi_disabled);
564 	SES_NV_ADD(boolean_value, nverr, nvl, SES_PROP_PRDFAIL,
565 	    esip->sesi_common.sesi_prdfail);
566 
567 	for (sp = &status_parsers[0]; sp->type != (ses2_element_type_t)-1; sp++)
568 		if (sp->type == type && sp->func != NULL)
569 			return (sp->func(esip, nvl));
570 
571 	return (0);
572 }
573 
574 static int
575 elem_parse_descr(ses_plugin_t *sp, ses_node_t *np)
576 {
577 	char *desc;
578 	size_t len;
579 	nvlist_t *props = ses_node_props(np);
580 	int nverr;
581 
582 	if ((desc = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
583 	    SES2_DIAGPAGE_ELEMENT_DESC, np, &len)) == NULL)
584 		return (0);
585 
586 	SES_NV_ADD(fixed_string, nverr, props, SES_PROP_DESCRIPTION,
587 	    desc, len);
588 
589 	return (0);
590 }
591 
592 static int
593 elem_parse_aes_fc(const ses2_aes_descr_fc_eip_impl_t *fp,
594     nvlist_t *nvl, size_t len)
595 {
596 	int nverr, i;
597 	nvlist_t **nva;
598 	int nports;
599 
600 	if (len < offsetof(ses2_aes_descr_fc_eip_impl_t,
601 	    sadfi_ports))
602 		return (0);
603 
604 	SES_NV_ADD(uint64, nverr, nvl, SES_PROP_BAY_NUMBER,
605 	    fp->sadfi_bay_number);
606 	SES_NV_ADD(uint64, nverr, nvl, SES_FC_PROP_NODE_NAME,
607 	    SCSI_READ64(&fp->sadfi_node_name));
608 
609 	nports = MIN(fp->sadfi_n_ports,
610 	    (len - offsetof(ses2_aes_descr_fc_eip_impl_t,
611 	    sadfi_ports)) / sizeof (ses2_aes_port_descr_impl_t));
612 
613 	if (nports == 0)
614 		return (0);
615 
616 	nva = ses_zalloc(nports * sizeof (nvlist_t *));
617 	if (nva == NULL)
618 		return (-1);
619 
620 	for (i = 0; i < nports; i++) {
621 		if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0)
622 			goto fail;
623 		if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_LOOP_POS,
624 		    fp->sadfi_ports[i].sapdi_port_loop_position)) != 0)
625 			goto fail;
626 		if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_REQ_HARDADDR,
627 		    fp->sadfi_ports[i].sapdi_port_requested_hard_address)) != 0)
628 			goto fail;
629 		nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_N_PORT_ID,
630 		    SCSI_READ24(fp->sadfi_ports[i].sapdi_n_port_identifier));
631 		if (nverr != 0)
632 			goto fail;
633 		if ((nverr = nvlist_add_uint64(nva[i], SES_FC_PROP_N_PORT_NAME,
634 		    SCSI_READ64(&fp->sadfi_ports[i].sapdi_n_port_name))) != 0)
635 			goto fail;
636 	}
637 
638 	if ((nverr = nvlist_add_nvlist_array(nvl, SES_FC_PROP_PORTS,
639 	    nva, nports)) != 0)
640 		goto fail;
641 
642 	for (i = 0; i < nports && nva[i] != NULL; i++)
643 		nvlist_free(nva[i]);
644 	ses_free(nva);
645 	return (0);
646 
647 fail:
648 	for (i = 0; i < nports && nva[i] != NULL; i++)
649 		nvlist_free(nva[i]);
650 	ses_free(nva);
651 	return (ses_set_nverrno(nverr, NULL));
652 }
653 
654 static int
655 elem_parse_aes_device(const ses2_aes_descr_eip_impl_t *dep, nvlist_t *nvl,
656     size_t len)
657 {
658 	ses2_aes_descr_fc_eip_impl_t *fp;
659 	ses2_aes_descr_sas0_eip_impl_t *s0ep;
660 	ses2_aes_descr_sas0_impl_t *s0p;
661 	ses2_aes_descr_impl_t *dip;
662 	nvlist_t **nva;
663 	int nverr, i;
664 	size_t nphy;
665 
666 	if (dep->sadei_eip) {
667 		s0ep = (ses2_aes_descr_sas0_eip_impl_t *)
668 		    dep->sadei_protocol_specific;
669 		s0p = (ses2_aes_descr_sas0_impl_t *)
670 		    dep->sadei_protocol_specific;
671 	} else {
672 		dip = (ses2_aes_descr_impl_t *)dep;
673 		s0ep = NULL;
674 		s0p = (ses2_aes_descr_sas0_impl_t *)
675 		    dip->sadei_protocol_specific;
676 	}
677 
678 	if (dep->sadei_invalid)
679 		return (0);
680 
681 	if (dep->sadei_protocol_identifier == SPC4_PROTO_FIBRE_CHANNEL) {
682 		fp = (ses2_aes_descr_fc_eip_impl_t *)
683 		    dep->sadei_protocol_specific;
684 
685 		if (!SES_WITHIN_PAGE_STRUCT(fp, dep, len))
686 			return (0);
687 
688 		return (elem_parse_aes_fc(fp, nvl, len -
689 		    offsetof(ses2_aes_descr_eip_impl_t,
690 		    sadei_protocol_specific)));
691 	} else if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS) {
692 		return (0);
693 	}
694 
695 	if (s0p->sadsi_descriptor_type != SES2_AESD_SAS_DEVICE)
696 		return (0);
697 
698 	SES_NV_ADD(boolean_value, nverr, nvl, SES_DEV_PROP_SAS_NOT_ALL_PHYS,
699 	    s0p->sadsi_not_all_phys);
700 	if (s0ep != NULL) {
701 		SES_NV_ADD(uint64, nverr, nvl, SES_PROP_BAY_NUMBER,
702 		    s0ep->sadsi_bay_number);
703 		nphy = MIN(s0ep->sadsi_n_phy_descriptors,
704 		    (len - offsetof(ses2_aes_descr_sas0_eip_impl_t,
705 		    sadsi_phys)) / sizeof (ses2_aes_phy0_descr_impl_t));
706 	} else {
707 		nphy = MIN(s0p->sadsi_n_phy_descriptors,
708 		    (len - offsetof(ses2_aes_descr_sas0_impl_t,
709 		    sadsi_phys)) / sizeof (ses2_aes_phy0_descr_impl_t));
710 	}
711 
712 	if (nphy == 0)
713 		return (0);
714 
715 	nva = ses_zalloc(nphy * sizeof (nvlist_t *));
716 	if (nva == NULL)
717 		return (-1);
718 
719 	for (i = 0; i < nphy; i++) {
720 		ses2_aes_phy0_descr_impl_t *pp;
721 		pp = s0ep != NULL ? &s0ep->sadsi_phys[i] : &s0p->sadsi_phys[i];
722 		if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0)
723 			goto fail;
724 		if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_DEVICE_TYPE,
725 		    pp->sapdi_device_type)) != 0)
726 			goto fail;
727 		if ((nverr = nvlist_add_boolean_value(nva[i],
728 		    SES_SAS_PROP_SMPI_PORT, pp->sapdi_smp_initiator_port)) != 0)
729 			goto fail;
730 		if ((nverr = nvlist_add_boolean_value(nva[i],
731 		    SES_SAS_PROP_STPI_PORT, pp->sapdi_stp_initiator_port)) != 0)
732 			goto fail;
733 		if ((nverr = nvlist_add_boolean_value(nva[i],
734 		    SES_SAS_PROP_SSPI_PORT, pp->sapdi_ssp_initiator_port)) != 0)
735 			goto fail;
736 		if ((nverr = nvlist_add_boolean_value(nva[i],
737 		    SES_SAS_PROP_SATA_DEVICE, pp->sapdi_sata_device)) != 0)
738 			goto fail;
739 		if ((nverr = nvlist_add_boolean_value(nva[i],
740 		    SES_SAS_PROP_SMPT_PORT, pp->sapdi_smp_target_port)) != 0)
741 			goto fail;
742 		if ((nverr = nvlist_add_boolean_value(nva[i],
743 		    SES_SAS_PROP_STPT_PORT, pp->sapdi_stp_target_port)) != 0)
744 			goto fail;
745 		if ((nverr = nvlist_add_boolean_value(nva[i],
746 		    SES_SAS_PROP_SSPT_PORT, pp->sapdi_ssp_target_port)) != 0)
747 			goto fail;
748 		nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ATT_ADDR,
749 		    SCSI_READ64(&pp->sapdi_attached_sas_address));
750 		if (nverr != 0)
751 			goto fail;
752 		nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ADDR,
753 		    SCSI_READ64(&pp->sapdi_sas_address));
754 		if (nverr != 0)
755 			goto fail;
756 		if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_PHY_ID,
757 		    pp->sapdi_phy_identifier)) != 0)
758 			goto fail;
759 	}
760 
761 	if ((nverr = nvlist_add_nvlist_array(nvl, SES_SAS_PROP_PHYS,
762 	    nva, nphy)) != 0)
763 		goto fail;
764 
765 	for (i = 0; i < nphy && nva[i] != NULL; i++)
766 		nvlist_free(nva[i]);
767 	ses_free(nva);
768 	return (0);
769 
770 fail:
771 	for (i = 0; i < nphy && nva[i] != NULL; i++)
772 		nvlist_free(nva[i]);
773 	ses_free(nva);
774 	return (ses_set_nverrno(nverr, NULL));
775 }
776 
777 static int
778 elem_parse_aes_expander(const ses2_aes_descr_eip_impl_t *dep, nvlist_t *nvl,
779     size_t len)
780 {
781 	ses2_aes_descr_exp_impl_t *sep;
782 	nvlist_t **nva;
783 	int nverr, i;
784 	size_t nphy;
785 
786 	if (dep->sadei_invalid)
787 		return (0);
788 
789 	/*
790 	 * This should never happen; no current SAS expander can have any
791 	 * other kind of ports.  But maybe someday - one could envision a
792 	 * SAS expander with iSCSI target ports, for example.
793 	 */
794 	if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS)
795 		return (0);
796 
797 	sep = (ses2_aes_descr_exp_impl_t *)dep->sadei_protocol_specific;
798 	if (sep->sadei_descriptor_type != SES2_AESD_SAS_OTHER)
799 		return (0);
800 
801 	SES_NV_ADD(uint64, nverr, nvl, SES_EXP_PROP_SAS_ADDR,
802 	    SCSI_READ64(&sep->sadei_sas_address));
803 
804 	nphy = MIN(sep->sadei_n_exp_phy_descriptors,
805 	    (len - offsetof(ses2_aes_descr_exp_impl_t,
806 	    sadei_phys)) / sizeof (ses2_aes_exp_phy_descr_impl_t));
807 
808 	if (nphy == 0)
809 		return (0);
810 
811 	nva = ses_zalloc(nphy * sizeof (nvlist_t *));
812 	if (nva == NULL)
813 		return (-1);
814 
815 	for (i = 0; i < nphy; i++) {
816 		if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0)
817 			goto fail;
818 		if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_CE_IDX,
819 		    sep->sadei_phys[i].saepdi_connector_element_index)) != 0)
820 			goto fail;
821 		if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_OE_IDX,
822 		    sep->sadei_phys[i].saepdi_other_element_index)) != 0)
823 			goto fail;
824 	}
825 
826 	if ((nverr = nvlist_add_nvlist_array(nvl, SES_SAS_PROP_PHYS,
827 	    nva, nphy)) != 0)
828 		goto fail;
829 
830 	for (i = 0; i < nphy && nva[i] != NULL; i++)
831 		nvlist_free(nva[i]);
832 	ses_free(nva);
833 	return (0);
834 
835 fail:
836 	for (i = 0; i < nphy && nva[i] != NULL; i++)
837 		nvlist_free(nva[i]);
838 	ses_free(nva);
839 	return (ses_set_nverrno(nverr, NULL));
840 }
841 
842 static int
843 elem_parse_aes_misc(const ses2_aes_descr_eip_impl_t *dep, nvlist_t *nvl,
844     size_t len)
845 {
846 	ses2_aes_descr_fc_eip_impl_t *fp;
847 	ses2_aes_descr_sas1_impl_t *s1p;
848 	nvlist_t **nva;
849 	int nverr, i;
850 	size_t nphy;
851 
852 	if (dep->sadei_invalid)
853 		return (0);
854 
855 	if (dep->sadei_protocol_identifier == SPC4_PROTO_FIBRE_CHANNEL) {
856 		fp = (ses2_aes_descr_fc_eip_impl_t *)
857 		    dep->sadei_protocol_specific;
858 
859 		if (!SES_WITHIN_PAGE_STRUCT(fp, dep, len))
860 			return (0);
861 
862 		return (elem_parse_aes_fc(fp, nvl, len -
863 		    offsetof(ses2_aes_descr_eip_impl_t,
864 		    sadei_protocol_specific)));
865 	} else if (dep->sadei_protocol_identifier != SPC4_PROTO_SAS) {
866 		return (0);
867 	}
868 
869 	s1p = (ses2_aes_descr_sas1_impl_t *)dep->sadei_protocol_specific;
870 	if (s1p->sadsi_descriptor_type == SES2_AESD_SAS_DEVICE)
871 		return (0);
872 
873 	nphy = MIN(s1p->sadsi_n_phy_descriptors,
874 	    (len - offsetof(ses2_aes_descr_sas1_impl_t,
875 	    sadsi_phys)) / sizeof (ses2_aes_phy1_descr_impl_t));
876 
877 	if (nphy == 0)
878 		return (0);
879 
880 	nva = ses_zalloc(nphy * sizeof (nvlist_t *));
881 	if (nva == NULL)
882 		return (-1);
883 
884 	for (i = 0; i < nphy; i++) {
885 		if ((nverr = nvlist_alloc(&nva[i], NV_UNIQUE_NAME, 0)) != 0)
886 			goto fail;
887 		if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_CE_IDX,
888 		    s1p->sadsi_phys[i].sapdi_connector_element_index)) != 0)
889 			goto fail;
890 		if ((nverr = nvlist_add_uint64(nva[i], SES_PROP_OE_IDX,
891 		    s1p->sadsi_phys[i].sapdi_other_element_index)) != 0)
892 			goto fail;
893 		if ((nverr = nvlist_add_uint64(nva[i], SES_SAS_PROP_ADDR,
894 		    SCSI_READ64(&s1p->sadsi_phys[i].sapdi_sas_address))) != 0)
895 			goto fail;
896 	}
897 
898 	if ((nverr = nvlist_add_nvlist_array(nvl, SES_SAS_PROP_PHYS,
899 	    nva, nphy)) != 0)
900 		goto fail;
901 
902 	for (i = 0; i < nphy && nva[i] != NULL; i++)
903 		nvlist_free(nva[i]);
904 
905 	ses_free(nva);
906 	return (0);
907 
908 fail:
909 	for (i = 0; i < nphy && nva[i] != NULL; i++)
910 		nvlist_free(nva[i]);
911 	ses_free(nva);
912 	return (nverr);
913 }
914 
915 static const struct aes_parser {
916 	ses2_element_type_t type;
917 	int (*func)(const ses2_aes_descr_eip_impl_t *, nvlist_t *, size_t);
918 } aes_parsers[] = {
919 	{ SES_ET_DEVICE, elem_parse_aes_device },
920 	{ SES_ET_SCSI_TARGET_PORT, elem_parse_aes_misc },
921 	{ SES_ET_SCSI_INITIATOR_PORT, elem_parse_aes_misc },
922 	{ SES_ET_ESC_ELECTRONICS, elem_parse_aes_misc },
923 	{ SES_ET_ARRAY_DEVICE, elem_parse_aes_device },
924 	{ SES_ET_SAS_EXPANDER, elem_parse_aes_expander },
925 	{ (ses2_element_type_t)-1, NULL }
926 };
927 
928 static int
929 elem_parse_aes(ses_plugin_t *sp, ses_node_t *np)
930 {
931 	ses2_aes_descr_eip_impl_t *dep;
932 	nvlist_t *props = ses_node_props(np);
933 	const struct aes_parser *app;
934 	uint64_t type;
935 	size_t len;
936 
937 	if (ses_node_type(np) == SES_NODE_AGGREGATE)
938 		return (0);
939 
940 	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE,
941 	    &type) == 0);
942 
943 	for (app = &aes_parsers[0]; app->func != NULL; app++)
944 		if (app->type == type)
945 			break;
946 	if (app->func == NULL)
947 		return (0);
948 
949 	if ((dep = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
950 	    SES2_DIAGPAGE_ADDL_ELEM_STATUS, np, &len)) == NULL)
951 		return (0);
952 
953 	return (app->func(dep, props, len));
954 }
955 
956 static int
957 elem_parse_threshold(ses_plugin_t *sp, ses_node_t *np)
958 {
959 	ses_snap_t *snap = ses_node_snapshot(np);
960 	ses2_threshold_impl_t *tp;
961 	nvlist_t *nvl = ses_node_props(np);
962 	int nverr;
963 	uint64_t type;
964 	size_t len;
965 
966 	VERIFY(nvlist_lookup_uint64(nvl, SES_PROP_ELEMENT_TYPE,
967 	    &type) == 0);
968 
969 	if ((tp = ses_plugin_page_lookup(sp, snap,
970 	    SES2_DIAGPAGE_THRESHOLD_IO, np, &len)) == NULL)
971 		return (0);
972 
973 	switch (type) {
974 	case SES_ET_TEMPERATURE_SENSOR:
975 		SES_NV_ADD(int64, nverr, nvl, SES_PROP_THRESH_CRIT_HI,
976 		    (int)tp->sti_high_crit + SES2_ES_TEMP_OFFSET);
977 		SES_NV_ADD(int64, nverr, nvl, SES_PROP_THRESH_WARN_HI,
978 		    (int)tp->sti_high_warn + SES2_ES_TEMP_OFFSET);
979 		SES_NV_ADD(int64, nverr, nvl, SES_PROP_THRESH_CRIT_LO,
980 		    (int)tp->sti_low_crit + SES2_ES_TEMP_OFFSET);
981 		SES_NV_ADD(int64, nverr, nvl, SES_PROP_THRESH_WARN_LO,
982 		    (int)tp->sti_low_warn + SES2_ES_TEMP_OFFSET);
983 		return (0);
984 
985 	case SES_ET_UPS:
986 	case SES_ET_CURRENT_SENSOR:
987 	case SES_ET_VOLTAGE_SENSOR:
988 		SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_CRIT_HI,
989 		    tp->sti_high_crit);
990 		SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_WARN_HI,
991 		    tp->sti_high_warn);
992 		SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_CRIT_LO,
993 		    tp->sti_low_crit);
994 		SES_NV_ADD(uint64, nverr, nvl, SES_PROP_THRESH_WARN_LO,
995 		    tp->sti_low_warn);
996 		return (0);
997 	default:
998 		return (0);
999 	}
1000 }
1001 
1002 int
1003 ses2_fill_element_node(ses_plugin_t *sp, ses_node_t *np)
1004 {
1005 	int err;
1006 
1007 	if ((err = elem_parse_sd(sp, np)) != 0)
1008 		return (err);
1009 
1010 	if ((err = elem_parse_descr(sp, np)) != 0)
1011 		return (err);
1012 
1013 	if ((err = elem_parse_aes(sp, np)) != 0)
1014 		return (err);
1015 
1016 	if ((err = elem_parse_threshold(sp, np)) != 0)
1017 		return (err);
1018 
1019 	return (0);
1020 }
1021