view usr/src/lib/scsi/plugins/ses/ses2/common/ses2_element_ctl.c @ 13586:a42b5426edb4

1914 libses cannot set more than one properties at once 1984 libses uses threshold diag page wrong way Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Eric Schrock <eric.schrock@delphix.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Richard Lowe <richlowe@richlowe.net>
author Alexander Stetsenko <ams@nexenta.com>
date Wed, 01 Feb 2012 20:59:19 +0400
parents 40d5384cc8b2
children
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
/*
 * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
 */

#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <libnvpair.h>

#include <scsi/libses.h>
#include "ses2_impl.h"

static int
elem_setprop_device(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_device_ctl_impl_t *dip;
	const char *name;
	boolean_t v;

	if ((dip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_IDENT) == 0)
		dip->sdci_rqst_ident = v;
	else if (strcmp(name, SES_PROP_RMV) == 0)
		dip->sdci_rqst_remove = v;
	else if (strcmp(name, SES_DEV_PROP_READY_TO_INSERT) == 0)
		dip->sdci_rqst_insert = v;
	else if (strcmp(name, SES_DEV_PROP_REQ_MISSING) == 0)
		dip->sdci_rqst_missing = v;
	else if (strcmp(name, SES_DEV_PROP_DO_NOT_REMOVE) == 0)
		dip->sdci_do_not_remove = v;
	else if (strcmp(name, SES_DEV_PROP_REQ_ACTIVE) == 0)
		dip->sdci_rqst_active = v;
	else if (strcmp(name, SES_DEV_PROP_BYP_B) == 0)
		dip->sdci_enable_byp_b = v;
	else if (strcmp(name, SES_DEV_PROP_BYP_A) == 0)
		dip->sdci_enable_byp_a = v;
	else if (strcmp(name, SES_PROP_OFF) == 0)
		dip->sdci_device_off = v;
	else if (strcmp(name, SES_DEV_PROP_FAULT_RQSTD) == 0)
		dip->sdci_rqst_fault = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_psu(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_psu_ctl_impl_t *pip;
	const char *name;
	boolean_t v;

	if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_IDENT) == 0)
		pip->spci_rqst_ident = v;
	else if (strcmp(name, SES_PROP_REQUESTED_ON) == 0)
		pip->spci_rqst_on = v;
	else if (strcmp(name, SES_PROP_FAIL) == 0)
		pip->spci_rqst_fail = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_cooling(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_cooling_ctl_impl_t *cip;
	const char *name;
	boolean_t v1;
	uint64_t v64;

	if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);

	if (strcmp(name, SES_COOLING_PROP_SPEED_CODE) == 0) {
		(void) nvpair_value_uint64(nvp, &v64);
		cip->scci_requested_speed_code = v64;
		return (0);
	}

	(void) nvpair_value_boolean_value(nvp, &v1);

	if (strcmp(name, SES_PROP_IDENT) == 0)
		cip->scci_rqst_ident = v1;
	else if (strcmp(name, SES_PROP_REQUESTED_ON) == 0)
		cip->scci_rqst_on = v1;
	else if (strcmp(name, SES_PROP_FAIL) == 0)
		cip->scci_rqst_fail = v1;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_temp(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_temp_ctl_impl_t *tip;
	const char *name;
	boolean_t v;

	if ((tip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		tip->stci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		tip->stci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_lock(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_lock_ctl_impl_t *lip;
	const char *name;
	boolean_t v;

	if ((lip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		lip->slci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		lip->slci_rqst_ident = v;
	else if (strcmp(name, SES_LOCK_PROP_UNLOCKED) == 0)
		lip->slci_unlock = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_alarm(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_alarm_ctl_impl_t *aip;
	const char *name;
	boolean_t v;

	if ((aip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		aip->saci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		aip->saci_rqst_ident = v;
	else if (strcmp(name, SES_ALARM_PROP_UNRECOV) == 0)
		aip->saci_unrecov = v;
	else if (strcmp(name, SES_ALARM_PROP_CRIT) == 0)
		aip->saci_crit = v;
	else if (strcmp(name, SES_ALARM_PROP_NONCRIT) == 0)
		aip->saci_noncrit = v;
	else if (strcmp(name, SES_ALARM_PROP_INFO) == 0)
		aip->saci_info = v;
	else if (strcmp(name, SES_ALARM_PROP_REMIND) == 0)
		aip->saci_set_remind = v;
	else if (strcmp(name, SES_ALARM_PROP_MUTED) == 0)
		aip->saci_set_mute = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_esc(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_controller_ctl_impl_t *cip;
	const char *name;
	boolean_t v;

	if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		cip->scci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		cip->scci_rqst_ident = v;
	else if (strcmp(name, SES_ESC_PROP_SELECT) == 0)
		cip->scci_select_element = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_scc(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_scc_ctl_impl_t *sip;
	const char *name;
	boolean_t v;

	if ((sip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		sip->ssci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		sip->ssci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_ups(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_ups_ctl_impl_t *uip;
	const char *name;
	boolean_t v;

	if ((uip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		uip->suci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		uip->suci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_cache(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_nvcache_ctl_impl_t *cip;
	const char *name;
	boolean_t v;

	if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		cip->snci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		cip->snci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_keypad(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_keypad_ctl_impl_t *kip;
	const char *name;
	boolean_t v;

	if ((kip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		kip->skci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		kip->skci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_display(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_display_ctl_impl_t *dip;
	const char *name;
	boolean_t v1;
	uint16_t v16;
	uint64_t v64;

	if ((dip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);


	name = nvpair_name(nvp);

	if (strcmp(name, SES_DPY_PROP_MODE) == 0) {
		(void) nvpair_value_uint64(nvp, &v64);
		dip->sdci_display_mode = v64;
		return (0);
	} else if (strcmp(name, SES_DPY_PROP_CHAR) == 0) {
		(void) nvpair_value_uint16(nvp, &v16);
		SCSI_WRITE16(&dip->sdci_display_character, v16);
		return (0);
	}

	(void) nvpair_value_boolean_value(nvp, &v1);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		dip->sdci_rqst_fail = v1;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		dip->sdci_rqst_ident = v1;
	else
		ses_panic("Bad property %s", name);
	return (0);
}

static int
elem_setprop_px(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_port_ctl_impl_t *pip;
	const char *name;
	boolean_t v;

	if ((pip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);

	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		pip->spci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		pip->spci_rqst_ident = v;
	else if (strcmp(name, SES_PROP_DISABLED) == 0)
		pip->spci_disable = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_lang(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_lang_ctl_impl_t *lip;
	const char *name;
	boolean_t v1;
	uint64_t v64;

	if ((lip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);

	if (strcmp(name, SES_LANG_PROP_LANGCODE) == 0) {
		(void) nvpair_value_uint64(nvp, &v64);
		SCSI_WRITE16(&lip->slci_language_code, v64);
		return (0);
	}

	(void) nvpair_value_boolean_value(nvp, &v1);

	if (strcmp(name, SES_PROP_IDENT) == 0)
		lip->slci_rqst_ident = v1;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_comm(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_comm_ctl_impl_t *cip;
	const char *name;
	boolean_t v;

	if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		cip->scci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		cip->scci_rqst_ident = v;
	else if (strcmp(name, SES_PROP_DISABLED) == 0)
		cip->scci_disable = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_voltage(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_voltage_ctl_impl_t *vip;
	const char *name;
	boolean_t v;

	if ((vip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		vip->svci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		vip->svci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_current(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_current_ctl_impl_t *cip;
	const char *name;
	boolean_t v;

	if ((cip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		cip->scci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		cip->scci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_itp(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_itp_ctl_impl_t *iip;
	const char *name;
	boolean_t v;

	if ((iip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		iip->sici_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		iip->sici_rqst_ident = v;
	else if (strcmp(name, SES_ITP_PROP_ENABLED) == 0)
		iip->sici_enable = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_sse(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_ss_ctl_impl_t *sip;
	const char *name;
	boolean_t v;

	if ((sip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		sip->ssci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		sip->ssci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_arraydev(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_array_device_ctl_impl_t *aip;
	const char *name;
	boolean_t v;

	if ((aip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_AD_PROP_RR_ABORT) == 0)
		aip->sadci_rqst_rr_abort = v;
	else if (strcmp(name, SES_AD_PROP_REBUILD) == 0)
		aip->sadci_rqst_rebuild = v;
	else if (strcmp(name, SES_AD_PROP_IN_FAILED_ARRAY) == 0)
		aip->sadci_rqst_in_failed_array = v;
	else if (strcmp(name, SES_AD_PROP_IN_CRIT_ARRAY) == 0)
		aip->sadci_rqst_in_crit_array = v;
	else if (strcmp(name, SES_AD_PROP_CONS_CHK) == 0)
		aip->sadci_rqst_cons_check = v;
	else if (strcmp(name, SES_AD_PROP_HOT_SPARE) == 0)
		aip->sadci_rqst_hot_spare = v;
	else if (strcmp(name, SES_AD_PROP_RSVD_DEVICE) == 0)
		aip->sadci_rqst_rsvd_device = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		aip->sadci_rqst_ident = v;
	else if (strcmp(name, SES_PROP_RMV) == 0)
		aip->sadci_rqst_remove = v;
	else if (strcmp(name, SES_DEV_PROP_READY_TO_INSERT) == 0)
		aip->sadci_rqst_insert = v;
	else if (strcmp(name, SES_DEV_PROP_REQ_MISSING) == 0)
		aip->sadci_rqst_missing = v;
	else if (strcmp(name, SES_DEV_PROP_DO_NOT_REMOVE) == 0)
		aip->sadci_do_not_remove = v;
	else if (strcmp(name, SES_DEV_PROP_REQ_ACTIVE) == 0)
		aip->sadci_rqst_active = v;
	else if (strcmp(name, SES_DEV_PROP_BYP_B) == 0)
		aip->sadci_enable_byp_b = v;
	else if (strcmp(name, SES_DEV_PROP_BYP_A) == 0)
		aip->sadci_enable_byp_a = v;
	else if (strcmp(name, SES_PROP_OFF) == 0)
		aip->sadci_device_off = v;
	else if (strcmp(name, SES_DEV_PROP_FAULT_RQSTD) == 0)
		aip->sadci_rqst_fault = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_expander(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_expander_ctl_impl_t *eip;
	const char *name;
	boolean_t v;

	if ((eip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_FAIL) == 0)
		eip->seci_rqst_fail = v;
	else if (strcmp(name, SES_PROP_IDENT) == 0)
		eip->seci_rqst_ident = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_setprop_sasconn(ses_plugin_t *sp, ses_node_t *np, ses2_diag_page_t page,
    nvpair_t *nvp)
{
	ses2_sasconn_ctl_impl_t *sip;
	const char *name;
	boolean_t v;

	if ((sip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	name = nvpair_name(nvp);
	(void) nvpair_value_boolean_value(nvp, &v);

	if (strcmp(name, SES_PROP_IDENT) == 0)
		sip->ssci_rqst_ident = v;
	else if (strcmp(name, SES_PROP_FAIL) == 0)
		sip->ssci_rqst_fail = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

static int
elem_common_setprop_threshold(ses_plugin_t *sp, ses_node_t *np,
    ses2_diag_page_t page, nvpair_t *nvp)
{
	ses2_threshold_impl_t *tip;
	ses2_threshold_in_page_impl_t *tp;
	ses2_threshold_out_page_impl_t *tpout;
	const char *name;
	uint64_t v;
	size_t len = 0;
	size_t i, trnums;

	ASSERT(page == SES2_DIAGPAGE_THRESHOLD_IO);

	if ((tip = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, np, B_FALSE)) == NULL)
		return (-1);

	/* Get whole IN and OUT pages to copy filled thresholds */
	if ((tpout = ses_plugin_ctlpage_lookup(sp, ses_node_snapshot(np),
	    page, 0, NULL, B_FALSE)) == NULL)
		return (-1);
	if ((tp = ses_plugin_page_lookup(sp, ses_node_snapshot(np),
	    page, NULL, &len)) == NULL)
		return (-1);

	len -= offsetof(ses2_threshold_in_page_impl_t, stipi_thresholds[0]);
	trnums = len / sizeof (ses2_threshold_impl_t);

	/* Do copy filled thresholds from In to Out page */
	for (i = 0; i < trnums; i++) {
		boolean_t filled = B_FALSE;
		ses2_threshold_impl_t *toutp = &tpout->stopi_thresholds[i];
		ses2_threshold_impl_t *tinp = &tp->stipi_thresholds[i];

		if (tinp->sti_high_crit != 0 || tinp->sti_high_warn != 0 ||
		    tinp->sti_low_crit != 0 || tinp->sti_low_warn != 0)
			filled = B_TRUE;

		if (toutp->sti_high_crit == 0 && toutp->sti_high_warn == 0 &&
		    toutp->sti_low_crit == 0 && toutp->sti_low_warn == 0 &&
		    filled)
			*toutp = *tinp;
	}

	name = nvpair_name(nvp);
	(void) nvpair_value_uint64(nvp, &v);

	if (strcmp(name, SES_PROP_THRESH_CRIT_HI) == 0)
		tip->sti_high_crit = v;
	else if (strcmp(name, SES_PROP_THRESH_CRIT_LO) == 0)
		tip->sti_low_crit = v;
	else if (strcmp(name, SES_PROP_THRESH_WARN_HI) == 0)
		tip->sti_high_warn = v;
	else if (strcmp(name, SES_PROP_THRESH_WARN_LO) == 0)
		tip->sti_low_warn = v;
	else
		ses_panic("Bad property %s", name);

	return (0);
}

#define	SES_THRESHOLD_CTL_PROPS	\
{	\
	.scp_name = SES_PROP_THRESH_CRIT_HI,	\
	.scp_type = DATA_TYPE_UINT64,	\
	.scp_num = SES2_DIAGPAGE_THRESHOLD_IO,	\
	.scp_setprop = elem_common_setprop_threshold	\
},	\
{	\
	.scp_name = SES_PROP_THRESH_WARN_HI,	\
	.scp_type = DATA_TYPE_UINT64,	\
	.scp_num = SES2_DIAGPAGE_THRESHOLD_IO,	\
	.scp_setprop = elem_common_setprop_threshold	\
},	\
{	\
	.scp_name = SES_PROP_THRESH_CRIT_LO,	\
	.scp_type = DATA_TYPE_UINT64,	\
	.scp_num = SES2_DIAGPAGE_THRESHOLD_IO,	\
	.scp_setprop = elem_common_setprop_threshold	\
},	\
{	\
	.scp_name = SES_PROP_THRESH_WARN_LO,	\
	.scp_type = DATA_TYPE_UINT64,	\
	.scp_num = SES2_DIAGPAGE_THRESHOLD_IO,	\
	.scp_setprop = elem_common_setprop_threshold	\
}

static const ses2_ctl_prop_t device_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_PROP_RMV,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_DEV_PROP_READY_TO_INSERT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_DEV_PROP_REQ_MISSING,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_DEV_PROP_DO_NOT_REMOVE,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_DEV_PROP_REQ_ACTIVE,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_DEV_PROP_BYP_B,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_DEV_PROP_BYP_A,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_PROP_OFF,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	.scp_name = SES_DEV_PROP_FAULT_RQSTD,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_device,
},
{
	NULL
}
};

static const ses2_ctl_prop_t psu_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_psu
},
{
	.scp_name = SES_PROP_REQUESTED_ON,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_psu
},
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_psu
},
{
	NULL
}
};

static const ses2_ctl_prop_t cooling_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_cooling
},
{
	.scp_name = SES_COOLING_PROP_SPEED_CODE,
	.scp_type = DATA_TYPE_UINT64,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_cooling
},
{
	.scp_name = SES_PROP_REQUESTED_ON,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_cooling
},
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_cooling
},
{
	NULL
}
};

static const ses2_ctl_prop_t temp_props[] = {
	SES_COMMON_CTL_PROPS,
	SES_THRESHOLD_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_temp
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_temp
},
{
	NULL
}
};

static const ses2_ctl_prop_t lock_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_lock
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_lock
},
{
	.scp_name = SES_LOCK_PROP_UNLOCKED,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_lock
},
{
	NULL
}
};

static const ses2_ctl_prop_t alarm_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	.scp_name = SES_ALARM_PROP_UNRECOV,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	.scp_name = SES_ALARM_PROP_CRIT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	.scp_name = SES_ALARM_PROP_NONCRIT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	.scp_name = SES_ALARM_PROP_INFO,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	.scp_name = SES_ALARM_PROP_REMIND,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	.scp_name = SES_ALARM_PROP_MUTED,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_alarm
},
{
	NULL
}
};

static const ses2_ctl_prop_t esc_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_esc
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_esc
},
{
	.scp_name = SES_ESC_PROP_SELECT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_esc
},
{
	NULL
}
};

static const ses2_ctl_prop_t scc_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_scc
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_scc
},
{
	NULL
}
};

static const ses2_ctl_prop_t cache_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_cache
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_cache
},
{
	NULL
}
};

static const ses2_ctl_prop_t ups_props[] = {
	SES_COMMON_CTL_PROPS,
	SES_THRESHOLD_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_ups
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_ups
},
{
	NULL
}
};

static const ses2_ctl_prop_t display_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_DPY_PROP_MODE,
	.scp_type = DATA_TYPE_UINT64,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_display
},
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_display
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_display
},
{
	.scp_name = SES_DPY_PROP_CHAR,
	.scp_type = DATA_TYPE_UINT16,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_display
},
{
	NULL
}
};

static const ses2_ctl_prop_t keypad_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_keypad
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_keypad
},
{
	NULL
}
};

static const ses2_ctl_prop_t px_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_px
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_px
},
{
	.scp_name = SES_PROP_DISABLED,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_px
},
{
	NULL
}
};

static const ses2_ctl_prop_t lang_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_lang
},
{
	.scp_name = SES_LANG_PROP_LANGCODE,
	.scp_type = DATA_TYPE_UINT64,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_lang
},
{
	NULL
}
};

static const ses2_ctl_prop_t comm_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_comm
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_comm
},
{
	.scp_name = SES_PROP_DISABLED,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_comm
},
{
	NULL
}
};

static const ses2_ctl_prop_t voltage_props[] = {
	SES_COMMON_CTL_PROPS,
	SES_THRESHOLD_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_voltage
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_voltage
},
{
	NULL
}
};

static const ses2_ctl_prop_t current_props[] = {
	SES_COMMON_CTL_PROPS,
	SES_THRESHOLD_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_current
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_current
},
{
	NULL
}
};

static const ses2_ctl_prop_t itp_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_itp
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_itp
},
{
	.scp_name = SES_ITP_PROP_ENABLED,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_itp
},
{
	NULL
}
};

static const ses2_ctl_prop_t sse_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_sse
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_sse
},
{
	NULL
}
};

static const ses2_ctl_prop_t arraydev_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_AD_PROP_RR_ABORT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_AD_PROP_REBUILD,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_AD_PROP_IN_FAILED_ARRAY,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_AD_PROP_IN_CRIT_ARRAY,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_AD_PROP_CONS_CHK,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_AD_PROP_HOT_SPARE,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_AD_PROP_RSVD_DEVICE,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_AD_PROP_OK,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_PROP_RMV,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_DEV_PROP_READY_TO_INSERT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_DEV_PROP_REQ_MISSING,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_DEV_PROP_DO_NOT_REMOVE,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_DEV_PROP_REQ_ACTIVE,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_DEV_PROP_BYP_B,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_DEV_PROP_BYP_A,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_PROP_OFF,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	.scp_name = SES_DEV_PROP_FAULT_RQSTD,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_arraydev
},
{
	NULL
}
};

static const ses2_ctl_prop_t expander_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_expander
},
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_expander
},
{
	NULL
}
};

static const ses2_ctl_prop_t sasconn_props[] = {
	SES_COMMON_CTL_PROPS,
{
	.scp_name = SES_PROP_IDENT,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_sasconn
},
{
	.scp_name = SES_PROP_FAIL,
	.scp_type = DATA_TYPE_BOOLEAN_VALUE,
	.scp_num = SES2_DIAGPAGE_ENCLOSURE_CTL_STATUS,
	.scp_setprop = elem_setprop_sasconn
},
{
	NULL
}
};

/*ARGSUSED*/
static int
elem_setdef_threshold(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_threshold_impl_t *tip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTL64(props, SES_PROP_THRESH_CRIT_HI, tip->sti_high_crit);
	SES_NV_CTL64(props, SES_PROP_THRESH_CRIT_LO, tip->sti_low_crit);
	SES_NV_CTL64(props, SES_PROP_THRESH_WARN_HI, tip->sti_high_warn);
	SES_NV_CTL64(props, SES_PROP_THRESH_WARN_LO, tip->sti_low_warn);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_device(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_device_ctl_impl_t *dip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_IDENT, dip->sdci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_PROP_RMV, dip->sdci_rqst_remove);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_READY_TO_INSERT,
	    dip->sdci_rqst_insert);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_MISSING,
	    dip->sdci_rqst_missing);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_DO_NOT_REMOVE,
	    dip->sdci_do_not_remove);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_ACTIVE,
	    dip->sdci_rqst_active);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_B, dip->sdci_enable_byp_b);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_A, dip->sdci_enable_byp_a);
	SES_NV_CTLBOOL(props, SES_PROP_OFF, dip->sdci_device_off);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_FAULT_RQSTD,
	    dip->sdci_rqst_fault);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_psu(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_psu_ctl_impl_t *pip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_IDENT, pip->spci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_PROP_REQUESTED_ON, pip->spci_rqst_on);
	SES_NV_CTLBOOL(props, SES_PROP_FAIL, pip->spci_rqst_fail);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_cooling(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_cooling_ctl_impl_t *cip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident);
	SES_NV_CTL64(props, SES_COOLING_PROP_SPEED_CODE,
	    cip->scci_requested_speed_code);
	SES_NV_CTLBOOL(props, SES_PROP_REQUESTED_ON, cip->scci_rqst_on);
	SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_temp(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_temp_ctl_impl_t *tip = data;
	nvlist_t *props = ses_node_props(np);

	if (page == SES2_DIAGPAGE_THRESHOLD_IO)
		return (elem_setdef_threshold(np, page, data));

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, tip->stci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, tip->stci_rqst_ident);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_lock(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_lock_ctl_impl_t *lip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, lip->slci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, lip->slci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_LOCK_PROP_UNLOCKED, lip->slci_unlock);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_alarm(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_alarm_ctl_impl_t *aip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, aip->saci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, aip->saci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_ALARM_PROP_UNRECOV, aip->saci_unrecov);
	SES_NV_CTLBOOL(props, SES_ALARM_PROP_CRIT, aip->saci_crit);
	SES_NV_CTLBOOL(props, SES_ALARM_PROP_NONCRIT, aip->saci_noncrit);
	SES_NV_CTLBOOL(props, SES_ALARM_PROP_INFO, aip->saci_info);
	SES_NV_CTLBOOL(props, SES_ALARM_PROP_REMIND, aip->saci_set_remind);
	SES_NV_CTLBOOL(props, SES_ALARM_PROP_MUTED, aip->saci_set_mute);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_esc(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_controller_ctl_impl_t *cip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_ESC_PROP_SELECT,
	    cip->scci_select_element);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_scc(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_scc_ctl_impl_t *sip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, sip->ssci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, sip->ssci_rqst_ident);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_cache(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_nvcache_ctl_impl_t *cip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->snci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->snci_rqst_ident);

	return (0);
}

static int
elem_setdef_ups(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_ups_ctl_impl_t *uip = data;
	nvlist_t *props = ses_node_props(np);

	if (page == SES2_DIAGPAGE_THRESHOLD_IO)
		return (elem_setdef_threshold(np, page, data));

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, uip->suci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, uip->suci_rqst_ident);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_display(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_display_ctl_impl_t *dip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTL64(props, SES_DPY_PROP_MODE, dip->sdci_display_mode);
	SES_NV_CTLBOOL(props, SES_PROP_FAIL, dip->sdci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, dip->sdci_rqst_ident);
	SES_NV_CTL16(props, SES_DPY_PROP_CHAR,
	    dip->sdci_display_character);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_keypad(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_keypad_ctl_impl_t *kip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, kip->skci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, kip->skci_rqst_ident);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_px(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_port_ctl_impl_t *pip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, pip->spci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, pip->spci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_PROP_DISABLED, pip->spci_disable);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_lang(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_lang_ctl_impl_t *lip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_IDENT, lip->slci_rqst_ident);
	SES_NV_CTL16(props, SES_LANG_PROP_LANGCODE,
	    lip->slci_language_code);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_comm(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_comm_ctl_impl_t *cip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_PROP_DISABLED, cip->scci_disable);

	return (0);
}

static int
elem_setdef_voltage(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_voltage_ctl_impl_t *vip = data;
	nvlist_t *props = ses_node_props(np);

	if (page == SES2_DIAGPAGE_THRESHOLD_IO)
		return (elem_setdef_threshold(np, page, data));

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, vip->svci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, vip->svci_rqst_ident);

	return (0);
}

static int
elem_setdef_current(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_current_ctl_impl_t *cip = data;
	nvlist_t *props = ses_node_props(np);

	if (page == SES2_DIAGPAGE_THRESHOLD_IO)
		return (elem_setdef_threshold(np, page, data));

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, cip->scci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, cip->scci_rqst_ident);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_itp(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_itp_ctl_impl_t *iip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, iip->sici_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, iip->sici_rqst_ident);
	SES_NV_CTLBOOL(props, SES_ITP_PROP_ENABLED, iip->sici_enable);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_sse(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_ss_ctl_impl_t *sip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, sip->ssci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, sip->ssci_rqst_ident);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_arraydev(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_array_device_ctl_impl_t *aip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_AD_PROP_RR_ABORT,
	    aip->sadci_rqst_rr_abort);
	SES_NV_CTLBOOL(props, SES_AD_PROP_REBUILD,
	    aip->sadci_rqst_rebuild);
	SES_NV_CTLBOOL(props, SES_AD_PROP_IN_FAILED_ARRAY,
	    aip->sadci_rqst_in_failed_array);
	SES_NV_CTLBOOL(props, SES_AD_PROP_IN_CRIT_ARRAY,
	    aip->sadci_rqst_in_crit_array);
	SES_NV_CTLBOOL(props, SES_AD_PROP_CONS_CHK,
	    aip->sadci_rqst_cons_check);
	SES_NV_CTLBOOL(props, SES_AD_PROP_HOT_SPARE,
	    aip->sadci_rqst_hot_spare);
	SES_NV_CTLBOOL(props, SES_AD_PROP_RSVD_DEVICE,
	    aip->sadci_rqst_rsvd_device);

	SES_NV_CTLBOOL(props, SES_PROP_IDENT, aip->sadci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_PROP_RMV, aip->sadci_rqst_remove);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_READY_TO_INSERT,
	    aip->sadci_rqst_insert);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_MISSING,
	    aip->sadci_rqst_missing);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_DO_NOT_REMOVE,
	    aip->sadci_do_not_remove);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_REQ_ACTIVE,
	    aip->sadci_rqst_active);

	SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_B, aip->sadci_enable_byp_b);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_BYP_A, aip->sadci_enable_byp_a);
	SES_NV_CTLBOOL(props, SES_PROP_OFF, aip->sadci_device_off);
	SES_NV_CTLBOOL(props, SES_DEV_PROP_FAULT_RQSTD,
	    aip->sadci_rqst_fault);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_expander(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_expander_ctl_impl_t *eip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_FAIL, eip->seci_rqst_fail);
	SES_NV_CTLBOOL(props, SES_PROP_IDENT, eip->seci_rqst_ident);

	return (0);
}

/*ARGSUSED*/
static int
elem_setdef_sasconn(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	ses2_sasconn_ctl_impl_t *sip = data;
	nvlist_t *props = ses_node_props(np);

	SES_NV_CTLBOOL(props, SES_PROP_IDENT, sip->ssci_rqst_ident);
	SES_NV_CTLBOOL(props, SES_PROP_FAIL, sip->ssci_rqst_fail);

	return (0);
}

#define	CTL_DESC(_e, _n)	\
	{	\
		.scd_et = _e,	\
		.scd_props = _n##_props,	\
		.scd_setdef = elem_setdef_##_n	\
	}

static const ses2_ctl_desc_t ctl_descs[] = {
	CTL_DESC(SES_ET_DEVICE, device),
	CTL_DESC(SES_ET_POWER_SUPPLY, psu),
	CTL_DESC(SES_ET_COOLING, cooling),
	CTL_DESC(SES_ET_TEMPERATURE_SENSOR, temp),
	CTL_DESC(SES_ET_DOOR_LOCK, lock),
	CTL_DESC(SES_ET_AUDIBLE_ALARM, alarm),
	CTL_DESC(SES_ET_ESC_ELECTRONICS, esc),
	CTL_DESC(SES_ET_SCC_ELECTRONICS, scc),
	CTL_DESC(SES_ET_NONVOLATILE_CACHE, cache),
	CTL_DESC(SES_ET_UPS, ups),
	CTL_DESC(SES_ET_DISPLAY, display),
	CTL_DESC(SES_ET_KEY_PAD_ENTRY, keypad),
	CTL_DESC(SES_ET_SCSI_PORT_XCVR, px),
	CTL_DESC(SES_ET_LANGUAGE, lang),
	CTL_DESC(SES_ET_COMMUNICATION_PORT, comm),
	CTL_DESC(SES_ET_VOLTAGE_SENSOR, voltage),
	CTL_DESC(SES_ET_CURRENT_SENSOR, current),
	CTL_DESC(SES_ET_SCSI_TARGET_PORT, itp),
	CTL_DESC(SES_ET_SCSI_INITIATOR_PORT, itp),
	CTL_DESC(SES_ET_SIMPLE_SUBENCLOSURE, sse),
	CTL_DESC(SES_ET_ARRAY_DEVICE, arraydev),
	CTL_DESC(SES_ET_SAS_EXPANDER, expander),
	CTL_DESC(SES_ET_SAS_CONNECTOR, sasconn),
	{ .scd_et = -1 }
};

int
ses2_element_ctl(ses_plugin_t *sp, ses_node_t *np, const char *op,
    nvlist_t *nvl)
{
	const ses2_ctl_desc_t *dp;
	nvlist_t *props = ses_node_props(np);
	uint64_t type;

	if (strcmp(op, SES_CTL_OP_SETPROP) != 0)
		return (0);

	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE,
	    &type) == 0);

	for (dp = &ctl_descs[0]; dp->scd_et != -1; dp++)
		if (dp->scd_et == type)
			break;

	if (dp->scd_et == -1)
		return (0);

	return (ses2_setprop(sp, np, dp->scd_props, nvl));
}

int
ses2_element_setdef(ses_node_t *np, ses2_diag_page_t page, void *data)
{
	const ses2_ctl_desc_t *dp;
	nvlist_t *props = ses_node_props(np);
	uint64_t type;

	VERIFY(nvlist_lookup_uint64(props, SES_PROP_ELEMENT_TYPE, &type) == 0);

	for (dp = &ctl_descs[0]; dp->scd_et != -1; dp++)
		if (dp->scd_et == type)
			break;

	if (dp->scd_et == -1)
		return (0);

	if (dp->scd_setdef(np, page, data) != 0)
		return (-1);

	return (0);
}