126947304SEvan Yan /*
226947304SEvan Yan  * CDDL HEADER START
326947304SEvan Yan  *
426947304SEvan Yan  * The contents of this file are subject to the terms of the
526947304SEvan Yan  * Common Development and Distribution License (the "License").
626947304SEvan Yan  * You may not use this file except in compliance with the License.
726947304SEvan Yan  *
826947304SEvan Yan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan  * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan  * See the License for the specific language governing permissions
1126947304SEvan Yan  * and limitations under the License.
1226947304SEvan Yan  *
1326947304SEvan Yan  * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan  * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan  * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan  * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan  *
1926947304SEvan Yan  * CDDL HEADER END
2026947304SEvan Yan  */
2126947304SEvan Yan /*
2270f83219SEvan Yan  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2326947304SEvan Yan  * Use is subject to license terms.
24*b3d69c05SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
2526947304SEvan Yan  */
2626947304SEvan Yan 
2726947304SEvan Yan /*
2826947304SEvan Yan  * This file contains PCI HotPlug functionality that is compatible with the
2926947304SEvan Yan  * PCI SHPC specification 1.x.
3026947304SEvan Yan  *
3126947304SEvan Yan  * NOTE: This file is compiled and delivered through misc/pcie module.
3226947304SEvan Yan  */
3326947304SEvan Yan 
3426947304SEvan Yan #include <sys/note.h>
3526947304SEvan Yan #include <sys/conf.h>
3626947304SEvan Yan #include <sys/kmem.h>
3726947304SEvan Yan #include <sys/kstat.h>
3826947304SEvan Yan #include <sys/debug.h>
3926947304SEvan Yan #include <sys/vtrace.h>
4026947304SEvan Yan #include <sys/autoconf.h>
4126947304SEvan Yan #include <sys/varargs.h>
4226947304SEvan Yan #include <sys/hwconf.h>
4326947304SEvan Yan #include <sys/ddi_impldefs.h>
4426947304SEvan Yan #include <sys/callb.h>
4526947304SEvan Yan #include <sys/ddi.h>
4626947304SEvan Yan #include <sys/sunddi.h>
4726947304SEvan Yan #include <sys/sunndi.h>
4826947304SEvan Yan #include <sys/sysevent/dr.h>
4926947304SEvan Yan #include <sys/ndi_impldefs.h>
5026947304SEvan Yan #include <sys/pci_impl.h>
5126947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
5226947304SEvan Yan #include <sys/hotplug/pci/pcishpc.h>
5326947304SEvan Yan 
5426947304SEvan Yan typedef struct pcishpc_prop {
5526947304SEvan Yan 	char	*prop_name;
5626947304SEvan Yan 	char	*prop_value;
5726947304SEvan Yan } pcishpc_prop_t;
5826947304SEvan Yan 
5926947304SEvan Yan static pcishpc_prop_t	pcishpc_props[] = {
6726947304SEvan Yan };
6826947304SEvan Yan 
6926947304SEvan Yan /* reset delay to 1 sec. */
7026947304SEvan Yan static int pcishpc_reset_delay = 1000000;
7126947304SEvan Yan 
7226947304SEvan Yan /* Local function prototype */
7326947304SEvan Yan static pcie_hp_ctrl_t *pcishpc_create_controller(dev_info_t *dip);
7426947304SEvan Yan static int	pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p);
7526947304SEvan Yan static int	pcishpc_destroy_controller(dev_info_t *dip);
7626947304SEvan Yan static pcie_hp_slot_t	*pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p);
7726947304SEvan Yan static int	pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot);
7826947304SEvan Yan static int	pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p);
7926947304SEvan Yan static int	pcishpc_slot_get_property(pcie_hp_slot_t *slot_p,
8026947304SEvan Yan 		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8126947304SEvan Yan static int	pcishpc_slot_set_property(pcie_hp_slot_t *slot_p,
8226947304SEvan Yan 		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8326947304SEvan Yan static int	pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p,
8426947304SEvan Yan 		    uint32_t cmd_code);
8526947304SEvan Yan static int	pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p);
8626947304SEvan Yan static void	pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p);
8726947304SEvan Yan static void	pcishpc_get_slot_state(pcie_hp_slot_t *slot_p);
8826947304SEvan Yan static int	pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
8926947304SEvan Yan 		    ddi_hp_cn_state_t new_slot_state);
9026947304SEvan Yan static void	pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot);
9126947304SEvan Yan static int	pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p);
9226947304SEvan Yan static int	pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
9326947304SEvan Yan 		    pcie_hp_led_state_t state);
9426947304SEvan Yan static int	pcishpc_led_shpc_to_hpc(int state);
9526947304SEvan Yan static int	pcishpc_led_hpc_to_shpc(int state);
9626947304SEvan Yan static int	pcishpc_slot_shpc_to_hpc(int shpc_state);
9726947304SEvan Yan static int	pcishpc_slot_hpc_to_shpc(int state);
9826947304SEvan Yan static char	*pcishpc_slot_textslotstate(ddi_hp_cn_state_t state);
9926947304SEvan Yan static char	*pcishpc_slot_textledstate(pcie_hp_led_state_t state);
10026947304SEvan Yan 
10126947304SEvan Yan static uint32_t	pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg);
10226947304SEvan Yan static void	pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg,
10326947304SEvan Yan 		    uint32_t data);
10426947304SEvan Yan 
10526947304SEvan Yan static int	pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
10626947304SEvan Yan 		    ddi_hp_cn_state_t target_state);
10726947304SEvan Yan static int	pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
10826947304SEvan Yan 		    ddi_hp_cn_state_t target_state);
10926947304SEvan Yan static int	pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
11026947304SEvan Yan 		    ddi_hp_cn_state_t target_state);
11126947304SEvan Yan 
11226947304SEvan Yan static int	pcishpc_slot_poweron(pcie_hp_slot_t *slot_p,
11326947304SEvan Yan 		    ddi_hp_cn_state_t *result_state);
11426947304SEvan Yan static int	pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p,
11526947304SEvan Yan 		    ddi_hp_cn_state_t *result_state);
11626947304SEvan Yan static int	pcishpc_slot_probe(pcie_hp_slot_t *slot_p);
11726947304SEvan Yan static int	pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p);
11826947304SEvan Yan #ifdef	DEBUG
11926947304SEvan Yan static void	pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p);
12026947304SEvan Yan #endif	/* DEBUG */
12126947304SEvan Yan 
12226947304SEvan Yan 
12326947304SEvan Yan /*
12426947304SEvan Yan  * Global functions (called by other drivers/modules)
12526947304SEvan Yan  */
12626947304SEvan Yan 
12726947304SEvan Yan /*
12826947304SEvan Yan  * pcishpc_init()
12926947304SEvan Yan  *
13026947304SEvan Yan  * Install and configure an SHPC controller and register the HotPlug slots
13126947304SEvan Yan  * with the Solaris HotPlug framework. This function is usually called by
13226947304SEvan Yan  * a PCI bridge Nexus driver that has a built in SHPC controller.
13326947304SEvan Yan  */
13426947304SEvan Yan int
pcishpc_init(dev_info_t * dip)13526947304SEvan Yan pcishpc_init(dev_info_t *dip)
13626947304SEvan Yan {
13726947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
13826947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
13926947304SEvan Yan 	int		i;
14026947304SEvan Yan 
14126947304SEvan Yan 	PCIE_DBG("pcishpc_init() called from %s#%d\n",
14226947304SEvan Yan 	    ddi_driver_name(dip), ddi_get_instance(dip));
14326947304SEvan Yan 
14426947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
14526947304SEvan Yan 		PCIE_DBG("pcishpc_init() shpc instance already "
14626947304SEvan Yan 		    "initialized!\n");
14726947304SEvan Yan 		return (DDI_SUCCESS);
14826947304SEvan Yan 	}
14926947304SEvan Yan 
15026947304SEvan Yan 	/* Initialize soft state structure for the SHPC instance. */
15126947304SEvan Yan 	ctrl_p = pcishpc_create_controller(dip);
15226947304SEvan Yan 
15326947304SEvan Yan 	if (ctrl_p == NULL) {
15426947304SEvan Yan 		PCIE_DBG("pcishpc_init() failed to create shpc softstate\n");
15526947304SEvan Yan 		return (DDI_FAILURE);
15626947304SEvan Yan 	}
15726947304SEvan Yan 
15826947304SEvan Yan 	if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) {
15926947304SEvan Yan 		PCIE_DBG("pcishpc_init() failed to setup controller\n");
16026947304SEvan Yan 		goto cleanup;
16126947304SEvan Yan 	}
16226947304SEvan Yan 
16326947304SEvan Yan 	/*
16426947304SEvan Yan 	 * Setup resource maps for this bus node.
16526947304SEvan Yan 	 */
16626947304SEvan Yan 	(void) pci_resource_setup(dip);
16726947304SEvan Yan 
16826947304SEvan Yan #ifdef	DEBUG
16926947304SEvan Yan 	PCIE_DBG("%s%d: P2P bridge register dump:\n",
17026947304SEvan Yan 	    ddi_driver_name(dip), ddi_get_instance(dip));
17126947304SEvan Yan 
17226947304SEvan Yan 	for (i = 0; i < 0x100; i += 4) {
17326947304SEvan Yan 		PCIE_DBG("SHPC Cfg reg 0x%02x: %08x\n", i,
17426947304SEvan Yan 		    pci_config_get32(bus_p->bus_cfg_hdl, i));
17526947304SEvan Yan 	}
17626947304SEvan Yan #endif	/* DEBUG */
17726947304SEvan Yan 
17826947304SEvan Yan 	/* Setup each HotPlug slot on this SHPC controller. */
17926947304SEvan Yan 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
18026947304SEvan Yan 		if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) {
18126947304SEvan Yan 			PCIE_DBG("pcishpc_init() failed to register "
18226947304SEvan Yan 			    "slot %d\n", i);
18326947304SEvan Yan 			goto cleanup1;
18426947304SEvan Yan 		}
18526947304SEvan Yan 		if (pcie_create_minor_node(ctrl_p, i) != DDI_SUCCESS) {
18626947304SEvan Yan 			PCIE_DBG("pcishpc_init() failed to create "
18726947304SEvan Yan 			    "minor node for slot %d\n", i);
18826947304SEvan Yan 			goto cleanup1;
18926947304SEvan Yan 		}
19026947304SEvan Yan 	}
19126947304SEvan Yan 
19226947304SEvan Yan #ifdef	DEBUG
19326947304SEvan Yan 	/* Dump out the SHPC registers. */
19426947304SEvan Yan 	pcishpc_dump_regs(ctrl_p);
19526947304SEvan Yan #endif	/* DEBUG */
19626947304SEvan Yan 
19726947304SEvan Yan 	PCIE_DBG("pcishpc_init() success(dip=%p)\n", dip);
19826947304SEvan Yan 	return (DDI_SUCCESS);
19926947304SEvan Yan 
20026947304SEvan Yan cleanup1:
20126947304SEvan Yan 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
20226947304SEvan Yan 		if (ctrl_p->hc_slots[i] == NULL)
20326947304SEvan Yan 			continue;
20426947304SEvan Yan 
20526947304SEvan Yan 		pcie_remove_minor_node(ctrl_p, i);
20626947304SEvan Yan 	}
20726947304SEvan Yan 	(void) pci_resource_destroy(dip);
20826947304SEvan Yan cleanup:
20926947304SEvan Yan 	(void) pcishpc_destroy_controller(dip);
21026947304SEvan Yan 	return (DDI_FAILURE);
21126947304SEvan Yan }
21226947304SEvan Yan 
21326947304SEvan Yan /*
21426947304SEvan Yan  * pcishpc_uninit()
21526947304SEvan Yan  * Unload the HogPlug controller driver and deallocate all resources.
21626947304SEvan Yan  */
21726947304SEvan Yan int
pcishpc_uninit(dev_info_t * dip)21826947304SEvan Yan pcishpc_uninit(dev_info_t *dip)
21926947304SEvan Yan {
22026947304SEvan Yan 	pcie_hp_ctrl_t *ctrl_p;
22126947304SEvan Yan 	int i;
22226947304SEvan Yan 
22326947304SEvan Yan 	PCIE_DBG("pcishpc_uninit() called(dip=%p)\n", dip);
22426947304SEvan Yan 
22526947304SEvan Yan 	ctrl_p = PCIE_GET_HP_CTRL(dip);
22626947304SEvan Yan 
22726947304SEvan Yan 	if (!ctrl_p) {
22826947304SEvan Yan 		PCIE_DBG("pcishpc_uninit() Unable to find softstate\n");
22926947304SEvan Yan 		return (DDI_FAILURE);
23026947304SEvan Yan 	}
23126947304SEvan Yan 
23226947304SEvan Yan 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
23326947304SEvan Yan 		if (ctrl_p->hc_slots[i] == NULL)
23426947304SEvan Yan 			continue;
23526947304SEvan Yan 
23626947304SEvan Yan 		pcie_remove_minor_node(ctrl_p, i);
23726947304SEvan Yan 	}
23826947304SEvan Yan 
23926947304SEvan Yan 	ctrl_p->hc_flags = 0;
24026947304SEvan Yan 
24126947304SEvan Yan 	/*
24226947304SEvan Yan 	 * Destroy resource maps for this bus node.
24326947304SEvan Yan 	 */
24426947304SEvan Yan 	(void) pci_resource_destroy(dip);
24526947304SEvan Yan 
24626947304SEvan Yan 	(void) pcishpc_destroy_controller(dip);
24726947304SEvan Yan 
24826947304SEvan Yan 	PCIE_DBG("pcishpc_uninit() success(dip=%p)\n", dip);
24926947304SEvan Yan 
25026947304SEvan Yan 	return (DDI_SUCCESS);
25126947304SEvan Yan }
25226947304SEvan Yan 
25326947304SEvan Yan /*
25426947304SEvan Yan  * pcishpc_intr()
25526947304SEvan Yan  *
25626947304SEvan Yan  * This is the SHPC controller interrupt handler.
25726947304SEvan Yan  */
25826947304SEvan Yan int
pcishpc_intr(dev_info_t * dip)25926947304SEvan Yan pcishpc_intr(dev_info_t *dip)
26026947304SEvan Yan {
26126947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
26226947304SEvan Yan 	uint32_t	irq_locator, irq_serr_locator, reg;
26326947304SEvan Yan 	int		slot;
26426947304SEvan Yan 
26526947304SEvan Yan 	PCIE_DBG("pcishpc_intr() called\n");
26626947304SEvan Yan 
26726947304SEvan Yan 	/* get the soft state structure for this dip */
26826947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
26926947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
27026947304SEvan Yan 
27126947304SEvan Yan 	mutex_enter(&ctrl_p->hc_mutex);
27226947304SEvan Yan 
27326947304SEvan Yan 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
27426947304SEvan Yan 		PCIE_DBG("pcishpc_intr() unclaimed\n");
27526947304SEvan Yan 		mutex_exit(&ctrl_p->hc_mutex);
27626947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
27726947304SEvan Yan 	}
27826947304SEvan Yan 
27926947304SEvan Yan 	PCIE_DBG("pcishpc_intr() interrupt received\n");
28026947304SEvan Yan 
28126947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
28226947304SEvan Yan 
28326947304SEvan Yan 	if (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) {
28426947304SEvan Yan 		PCIE_DBG("pcishpc_intr() "
28526947304SEvan Yan 		    "PCI_HP_SERR_INT_CMD_COMPLETE_IRQ detected\n");
28626947304SEvan Yan 		ctrl_p->hc_cmd_pending = B_FALSE;
28726947304SEvan Yan 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
28826947304SEvan Yan 	}
28926947304SEvan Yan 
29026947304SEvan Yan 	if (reg & PCI_HP_SERR_INT_ARBITER_IRQ) {
29126947304SEvan Yan 		PCIE_DBG("pcishpc_intr() PCI_HP_SERR_INT_ARBITER_IRQ "
29226947304SEvan Yan 		    "detected\n");
29326947304SEvan Yan 		ctrl_p->hc_arbiter_timeout = B_TRUE;
29426947304SEvan Yan 	}
29526947304SEvan Yan 
29626947304SEvan Yan 	/* Write back the SERR INT register to acknowledge the IRQs. */
29726947304SEvan Yan 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
29826947304SEvan Yan 
29926947304SEvan Yan 	irq_locator = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
30026947304SEvan Yan 	irq_serr_locator = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
30126947304SEvan Yan 
30226947304SEvan Yan 	/* Check for slot events that might have occured. */
30326947304SEvan Yan 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
30426947304SEvan Yan 		if ((irq_locator & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ||
30526947304SEvan Yan 		    (irq_serr_locator &
30626947304SEvan Yan 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot))) {
30726947304SEvan Yan 			PCIE_DBG("pcishpc_intr() slot %d and "
30826947304SEvan Yan 			    "pending IRQ\n", slot+1);
30926947304SEvan Yan 
31026947304SEvan Yan 			reg = pcishpc_read_reg(ctrl_p,
31126947304SEvan Yan 			    PCI_HP_LOGICAL_SLOT_REGS+slot);
31226947304SEvan Yan 
31326947304SEvan Yan 			if (reg & PCI_HP_SLOT_PRESENCE_DETECTED)
31426947304SEvan Yan 				PCIE_DBG("slot %d: "
31526947304SEvan Yan 				    "PCI_HP_SLOT_PRESENCE_DETECTED\n",
31626947304SEvan Yan 				    slot+1);
31726947304SEvan Yan 
31826947304SEvan Yan 			if (reg & PCI_HP_SLOT_ISO_PWR_DETECTED)
31926947304SEvan Yan 				PCIE_DBG("slot %d: "
32026947304SEvan Yan 				    "PCI_HP_SLOT_ISO_PWR_DETECTED\n",
32126947304SEvan Yan 				    slot+1);
32226947304SEvan Yan 
32326947304SEvan Yan 			if (reg & PCI_HP_SLOT_ATTN_DETECTED) {
32426947304SEvan Yan 				PCIE_DBG("slot %d: "
32526947304SEvan Yan 				    "PCI_HP_SLOT_ATTN_DETECTED\n", slot+1);
32626947304SEvan Yan 
32726947304SEvan Yan 				/*
32826947304SEvan Yan 				 * if ATTN button event is still pending
32926947304SEvan Yan 				 * then cancel it
33026947304SEvan Yan 				 */
33126947304SEvan Yan 				if (ctrl_p->hc_slots[slot]->
33226947304SEvan Yan 				    hs_attn_btn_pending == B_TRUE)
33326947304SEvan Yan 					ctrl_p->hc_slots[slot]->
33426947304SEvan Yan 					    hs_attn_btn_pending = B_FALSE;
33526947304SEvan Yan 
33626947304SEvan Yan 				/* wake up the ATTN event handler */
33726947304SEvan Yan 				cv_signal(&ctrl_p->hc_slots[slot]->
33826947304SEvan Yan 				    hs_attn_btn_cv);
33926947304SEvan Yan 			}
34026947304SEvan Yan 
34126947304SEvan Yan 			if (reg & PCI_HP_SLOT_MRL_DETECTED)
34226947304SEvan Yan 				PCIE_DBG("slot %d: "
34326947304SEvan Yan 				    "PCI_HP_SLOT_MRL_DETECTED\n", slot+1);
34426947304SEvan Yan 
34526947304SEvan Yan 			if (reg & PCI_HP_SLOT_POWER_DETECTED)
34626947304SEvan Yan 				PCIE_DBG("slot %d: "
34726947304SEvan Yan 				    "PCI_HP_SLOT_POWER_DETECTED\n", slot+1);
34826947304SEvan Yan 
34926947304SEvan Yan 			/* Acknoledge any slot interrupts */
35026947304SEvan Yan 			pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot,
35126947304SEvan Yan 			    reg);
35226947304SEvan Yan 		}
35326947304SEvan Yan 	}
35426947304SEvan Yan 
35526947304SEvan Yan 	mutex_exit(&ctrl_p->hc_mutex);
35626947304SEvan Yan 
35726947304SEvan Yan 	PCIE_DBG("pcishpc_intr() claimed\n");
35826947304SEvan Yan 
35926947304SEvan Yan 	return (DDI_INTR_CLAIMED);
36026947304SEvan Yan }
36126947304SEvan Yan 
36226947304SEvan Yan int
pcishpc_slot_get_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)36326947304SEvan Yan pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
36426947304SEvan Yan     ddi_hp_property_t *rval)
36526947304SEvan Yan {
36626947304SEvan Yan 	ddi_hp_property_t request, result;
36726947304SEvan Yan #ifdef _SYSCALL32_IMPL
36826947304SEvan Yan 	ddi_hp_property32_t request32, result32;
36926947304SEvan Yan #endif
37026947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
371296f12dcSToomas Soome 	nvlist_t	*prop_list;
37226947304SEvan Yan 	nvlist_t	*prop_rlist; /* nvlist for return values */
373296f12dcSToomas Soome 	nvpair_t	*prop_pair;
374296f12dcSToomas Soome 	char		*name, *value;
37526947304SEvan Yan 	int		ret = DDI_SUCCESS;
37626947304SEvan Yan 	int		i, n;
37726947304SEvan Yan 	boolean_t	get_all_prop = B_FALSE;
37826947304SEvan Yan 
37926947304SEvan Yan 	if (get_udatamodel() == DATAMODEL_NATIVE) {
38026947304SEvan Yan 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
38126947304SEvan Yan 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
38226947304SEvan Yan 			return (DDI_FAILURE);
38326947304SEvan Yan 	}
38426947304SEvan Yan #ifdef _SYSCALL32_IMPL
38526947304SEvan Yan 	else {
38626947304SEvan Yan 		bzero(&request, sizeof (request));
38726947304SEvan Yan 		bzero(&result, sizeof (result));
38826947304SEvan Yan 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
38926947304SEvan Yan 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
39026947304SEvan Yan 			return (DDI_FAILURE);
39126947304SEvan Yan 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
39226947304SEvan Yan 		request.buf_size = request32.buf_size;
39326947304SEvan Yan 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
39426947304SEvan Yan 		result.buf_size = result32.buf_size;
39526947304SEvan Yan 	}
39626947304SEvan Yan #endif
39726947304SEvan Yan 
39826947304SEvan Yan 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
39926947304SEvan Yan 	    &prop_list)) != DDI_SUCCESS)
40026947304SEvan Yan 		return (ret);
40126947304SEvan Yan 
40226947304SEvan Yan 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
40326947304SEvan Yan 		ret = DDI_ENOMEM;
40426947304SEvan Yan 		goto get_prop_cleanup;
40526947304SEvan Yan 	}
40626947304SEvan Yan 
40726947304SEvan Yan 	/* check whether the requested property is "all" or "help" */
40826947304SEvan Yan 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
40926947304SEvan Yan 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
41026947304SEvan Yan 		name = nvpair_name(prop_pair);
41126947304SEvan Yan 		n = sizeof (pcishpc_props) / sizeof (pcishpc_prop_t);
41226947304SEvan Yan 
41326947304SEvan Yan 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
41426947304SEvan Yan 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
41526947304SEvan Yan 
41626947304SEvan Yan 			/*
41726947304SEvan Yan 			 * Add all properties into the request list, so that we
41826947304SEvan Yan 			 * will get the values in the following for loop.
41926947304SEvan Yan 			 */
42026947304SEvan Yan 			for (i = 0; i < n; i++) {
42126947304SEvan Yan 				if (nvlist_add_string(prop_list,
42226947304SEvan Yan 				    pcishpc_props[i].prop_name, "") != 0) {
42326947304SEvan Yan 					ret = DDI_FAILURE;
42426947304SEvan Yan 					goto get_prop_cleanup1;
42526947304SEvan Yan 				}
42626947304SEvan Yan 			}
42726947304SEvan Yan 			get_all_prop = B_TRUE;
42826947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
42926947304SEvan Yan 			/*
43026947304SEvan Yan 			 * Empty the request list, and add help strings into the
43126947304SEvan Yan 			 * return list. We will pass the following for loop.
43226947304SEvan Yan 			 */
43326947304SEvan Yan 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
43426947304SEvan Yan 
43526947304SEvan Yan 			for (i = 0; i < n; i++) {