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 
2226947304SEvan Yan /*
2326947304SEvan Yan  *  Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2426947304SEvan Yan  *  Use is subject to license terms.
25b3d69c05SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
2626947304SEvan Yan  */
2726947304SEvan Yan 
2826947304SEvan Yan /*
2926947304SEvan Yan  * This file contains the common hotplug code that is used by Standard
3026947304SEvan Yan  * PCIe and PCI HotPlug Controller code.
3126947304SEvan Yan  *
3226947304SEvan Yan  * NOTE: This file is compiled and delivered through misc/pcie module.
3326947304SEvan Yan  */
3426947304SEvan Yan 
3526947304SEvan Yan #include <sys/types.h>
3626947304SEvan Yan #include <sys/conf.h>
3726947304SEvan Yan #include <sys/kmem.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/ddi_impldefs.h>
4326947304SEvan Yan #include <sys/time.h>
4426947304SEvan Yan #include <sys/note.h>
4526947304SEvan Yan #include <sys/callb.h>
4626947304SEvan Yan #include <sys/ddi.h>
4726947304SEvan Yan #include <sys/sunddi.h>
4826947304SEvan Yan #include <sys/sunndi.h>
4926947304SEvan Yan #include <sys/sysevent.h>
5026947304SEvan Yan #include <sys/sysevent/eventdefs.h>
5126947304SEvan Yan #include <sys/sysevent/dr.h>
5226947304SEvan Yan #include <sys/pci_impl.h>
5326947304SEvan Yan #include <sys/pci_cap.h>
5426947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h>
5526947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
5626947304SEvan Yan #include <sys/hotplug/pci/pciehpc.h>
5726947304SEvan Yan #include <sys/hotplug/pci/pcishpc.h>
5826947304SEvan Yan #include <io/pciex/pcieb.h>
5926947304SEvan Yan 
6026947304SEvan Yan /* Local functions prototype */
6126947304SEvan Yan static int pcie_hp_list_occupants(dev_info_t *dip, void *arg);
6226947304SEvan Yan static int pcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip,
6326947304SEvan Yan     char *cn_name);
6426947304SEvan Yan static int pcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num);
6526947304SEvan Yan static int pcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg);
6626947304SEvan Yan static int pcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg);
6726947304SEvan Yan static int pcie_hp_match_dev_func(dev_info_t *dip, void *hdl);
6826947304SEvan Yan static boolean_t pcie_hp_match_dev(dev_info_t *dip, int dev_num);
6926947304SEvan Yan static int pcie_hp_get_df_from_port_name(char *cn_name, int *dev_num,
7026947304SEvan Yan     int *func_num);
7126947304SEvan Yan static int pcie_hp_create_port_name_num(dev_info_t *dip,
7226947304SEvan Yan     ddi_hp_cn_info_t *cn_info);
7326947304SEvan Yan static int pcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num,
7426947304SEvan Yan     int func_num);
7526947304SEvan Yan 
7626947304SEvan Yan /*
7726947304SEvan Yan  * Global functions (called by other drivers/modules)
7826947304SEvan Yan  */
7926947304SEvan Yan 
8026947304SEvan Yan /*
8126947304SEvan Yan  * return description text for led state
8226947304SEvan Yan  */
8326947304SEvan Yan char *
pcie_led_state_text(pcie_hp_led_state_t state)8426947304SEvan Yan pcie_led_state_text(pcie_hp_led_state_t state)
8526947304SEvan Yan {
8626947304SEvan Yan 	switch (state) {
8726947304SEvan Yan 	case PCIE_HP_LED_ON:
8826947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_ON);
8926947304SEvan Yan 	case PCIE_HP_LED_OFF:
9026947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_OFF);
9126947304SEvan Yan 	case PCIE_HP_LED_BLINK:
9226947304SEvan Yan 	default:
9326947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_BLINK);
9426947304SEvan Yan 	}
9526947304SEvan Yan }
9626947304SEvan Yan 
9726947304SEvan Yan /*
9826947304SEvan Yan  * return description text for slot condition
9926947304SEvan Yan  */
10026947304SEvan Yan char *
pcie_slot_condition_text(ap_condition_t condition)10126947304SEvan Yan pcie_slot_condition_text(ap_condition_t condition)
10226947304SEvan Yan {
10326947304SEvan Yan 	switch (condition) {
10426947304SEvan Yan 	case AP_COND_UNKNOWN:
10526947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_UNKNOWN);
10626947304SEvan Yan 	case AP_COND_OK:
10726947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_OK);
10826947304SEvan Yan 	case AP_COND_FAILING:
10926947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_FAILING);
11026947304SEvan Yan 	case AP_COND_FAILED:
11126947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_FAILED);
11226947304SEvan Yan 	case AP_COND_UNUSABLE:
11326947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_UNUSABLE);
11426947304SEvan Yan 	default:
11526947304SEvan Yan 		return (PCIEHPC_PROP_VALUE_UNKNOWN);
11626947304SEvan Yan 	}
11726947304SEvan Yan }
11826947304SEvan Yan 
11926947304SEvan Yan /*
12026947304SEvan Yan  * routine to copy in a nvlist from userland
12126947304SEvan Yan  */
12226947304SEvan Yan int
pcie_copyin_nvlist(char * packed_buf,size_t packed_sz,nvlist_t ** nvlp)12326947304SEvan Yan pcie_copyin_nvlist(char *packed_buf, size_t packed_sz, nvlist_t **nvlp)
12426947304SEvan Yan {
12526947304SEvan Yan 	int		ret = DDI_SUCCESS;
12626947304SEvan Yan 	char		*packed;
12726947304SEvan Yan 	nvlist_t	*dest = NULL;
12826947304SEvan Yan 
12926947304SEvan Yan 	if (packed_buf == NULL || packed_sz == 0)
13026947304SEvan Yan 		return (DDI_EINVAL);
13126947304SEvan Yan 
13226947304SEvan Yan 	/* copyin packed nvlist */
13326947304SEvan Yan 	if ((packed = kmem_alloc(packed_sz, KM_SLEEP)) == NULL)
13426947304SEvan Yan 		return (DDI_ENOMEM);
13526947304SEvan Yan 
13626947304SEvan Yan 	if (copyin(packed_buf, packed, packed_sz) != 0) {
13726947304SEvan Yan 		cmn_err(CE_WARN, "pcie_copyin_nvlist: copyin failed.\n");
13826947304SEvan Yan 		ret = DDI_FAILURE;
13926947304SEvan Yan 		goto copyin_cleanup;
14026947304SEvan Yan 	}
14126947304SEvan Yan 
14226947304SEvan Yan 	/* unpack packed nvlist */
14326947304SEvan Yan 	if ((ret = nvlist_unpack(packed, packed_sz, &dest, KM_SLEEP)) != 0) {
14426947304SEvan Yan 		cmn_err(CE_WARN, "pcie_copyin_nvlist: nvlist_unpack "
14526947304SEvan Yan 		    "failed with err %d\n", ret);
14626947304SEvan Yan 		switch (ret) {
14726947304SEvan Yan 		case EINVAL:
14826947304SEvan Yan 		case ENOTSUP:
14926947304SEvan Yan 			ret = DDI_EINVAL;
15026947304SEvan Yan 			goto copyin_cleanup;
15126947304SEvan Yan 		case ENOMEM:
15226947304SEvan Yan 			ret = DDI_ENOMEM;
15326947304SEvan Yan 			goto copyin_cleanup;
15426947304SEvan Yan 		default:
15526947304SEvan Yan 			ret = DDI_FAILURE;
15626947304SEvan Yan 			goto copyin_cleanup;
15726947304SEvan Yan 		}
15826947304SEvan Yan 	}
15926947304SEvan Yan 	*nvlp = dest;
16026947304SEvan Yan copyin_cleanup:
16126947304SEvan Yan 	kmem_free(packed, packed_sz);
16226947304SEvan Yan 	return (ret);
16326947304SEvan Yan }
16426947304SEvan Yan 
16526947304SEvan Yan /*
16626947304SEvan Yan  * routine to copy out a nvlist to userland
16726947304SEvan Yan  */
16826947304SEvan Yan int
pcie_copyout_nvlist(nvlist_t * nvl,char * packed_buf,size_t * buf_sz)16926947304SEvan Yan pcie_copyout_nvlist(nvlist_t *nvl, char *packed_buf, size_t *buf_sz)
17026947304SEvan Yan {
17126947304SEvan Yan 	int	err = 0;
17226947304SEvan Yan 	char	*buf = NULL;
17326947304SEvan Yan 	size_t	packed_sz;
17426947304SEvan Yan 
17526947304SEvan Yan 	if (nvl == NULL || packed_buf == NULL || buf_sz == NULL)
17626947304SEvan Yan 		return (DDI_EINVAL);
17726947304SEvan Yan 
17826947304SEvan Yan 	/* pack nvlist, the library will allocate memory */
17926947304SEvan Yan 	if ((err = nvlist_pack(nvl, &buf, &packed_sz, NV_ENCODE_NATIVE, 0))
18026947304SEvan Yan 	    != 0) {
18126947304SEvan Yan 		cmn_err(CE_WARN, "pcie_copyout_nvlist: nvlist_pack "
18226947304SEvan Yan 		    "failed with err %d\n", err);
18326947304SEvan Yan 		switch (err) {
18426947304SEvan Yan 		case EINVAL:
18526947304SEvan Yan 		case ENOTSUP:
18626947304SEvan Yan 			return (DDI_EINVAL);
18726947304SEvan Yan 		case ENOMEM:
18826947304SEvan Yan 			return (DDI_ENOMEM);
18926947304SEvan Yan 		default:
19026947304SEvan Yan 			return (DDI_FAILURE);
19126947304SEvan Yan 		}
19226947304SEvan Yan 	}
19326947304SEvan Yan 	if (packed_sz > *buf_sz) {
19426947304SEvan Yan 		return (DDI_EINVAL);
19526947304SEvan Yan 	}
19626947304SEvan Yan 
19726947304SEvan Yan 	/* copyout packed nvlist */
19826947304SEvan Yan 	if (copyout(buf, packed_buf, packed_sz) != 0) {
19926947304SEvan Yan 		cmn_err(CE_WARN, "pcie_copyout_nvlist: copyout " "failed.\n");
20026947304SEvan Yan 		kmem_free(buf, packed_sz);
20126947304SEvan Yan 		return (DDI_FAILURE);
20226947304SEvan Yan 	}
20326947304SEvan Yan 
20426947304SEvan Yan 	*buf_sz = packed_sz;
20526947304SEvan Yan 	kmem_free(buf, packed_sz);
20626947304SEvan Yan 	return (DDI_SUCCESS);
20726947304SEvan Yan }
20826947304SEvan Yan 
20926947304SEvan Yan /*
21026947304SEvan Yan  * init bus_hp_op entry and init hotpluggable slots & virtual ports
21126947304SEvan Yan  */
21226947304SEvan Yan int
pcie_hp_init(dev_info_t * dip,caddr_t arg)21326947304SEvan Yan pcie_hp_init(dev_info_t *dip, caddr_t arg)
21426947304SEvan Yan {
21526947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
21626947304SEvan Yan 	int		ret = DDI_SUCCESS, count;
21726947304SEvan Yan 	dev_info_t	*cdip;
21826947304SEvan Yan 
21926947304SEvan Yan 	if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
22026947304SEvan Yan 		/* Init hotplug controller */
22126947304SEvan Yan 		ret = pciehpc_init(dip, arg);
22226947304SEvan Yan 	} else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
22326947304SEvan Yan 		ret = pcishpc_init(dip);
22426947304SEvan Yan 	}
22526947304SEvan Yan 
22626947304SEvan Yan 	if (ret != DDI_SUCCESS) {
227ed11b501SColin Zou - Sun Microsystems - Beijing China 		PCIE_DBG("pcie_hp_init: initialize hotplug "
22826947304SEvan Yan 		    "controller failed with %d\n", ret);
22926947304SEvan Yan 		return (ret);
23026947304SEvan Yan 	}
23126947304SEvan Yan 
23226947304SEvan Yan 	ndi_devi_enter(dip, &count);
23326947304SEvan Yan 
23426947304SEvan Yan 	/* Create port for the first level children */
23526947304SEvan Yan 	cdip = ddi_get_child(dip);
23626947304SEvan Yan 	while (cdip != NULL) {
23726947304SEvan Yan 		if ((ret = pcie_hp_register_port(cdip, dip, NULL))
23826947304SEvan Yan 		    != DDI_SUCCESS) {
23926947304SEvan Yan 			/* stop and cleanup */
24026947304SEvan Yan 			break;
24126947304SEvan Yan 		}
24226947304SEvan Yan 		cdip = ddi_get_next_sibling(cdip);
24326947304SEvan Yan 	}
24426947304SEvan Yan 	ndi_devi_exit(dip, count);
24526947304SEvan Yan 	if (ret != DDI_SUCCESS) {
24626947304SEvan Yan 		cmn_err(CE_WARN, "pcie_hp_init: initialize virtual "
24726947304SEvan Yan 		    "hotplug port failed with %d\n", ret);
24826947304SEvan Yan 		(void) pcie_hp_uninit(dip);
24926947304SEvan Yan 
25026947304SEvan Yan 		return (ret);
25126947304SEvan Yan 	}
25226947304SEvan Yan 
25326947304SEvan Yan 	return (DDI_SUCCESS);
25426947304SEvan Yan }
25526947304SEvan Yan 
25626947304SEvan Yan /*
25726947304SEvan Yan  * uninit the hotpluggable slots and virtual ports
25826947304SEvan Yan  */
25926947304SEvan Yan int
pcie_hp_uninit(dev_info_t * dip)26026947304SEvan Yan pcie_hp_uninit(dev_info_t *dip)
26126947304SEvan Yan {
26226947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
26326947304SEvan Yan 	pcie_hp_unreg_port_t arg;
26426947304SEvan Yan 
26526947304SEvan Yan 	/*
26626947304SEvan Yan 	 * Must set arg.rv to NDI_SUCCESS so that if there's no port
26726947304SEvan Yan 	 * under this dip, we still return success thus the bridge
26826947304SEvan Yan 	 * driver can be successfully detached.
26926947304SEvan Yan 	 *
27026947304SEvan Yan 	 * Note that during the probe PCI configurator calls
27126947304SEvan Yan 	 * ndi_devi_offline() to detach driver for a new probed bridge,
27226947304SEvan Yan 	 * so that it can reprogram the resources for the bridge,
27326947304SEvan Yan 	 * ndi_devi_offline() calls into pcieb_detach() which in turn
27426947304SEvan Yan 	 * calls into this function. In this case there are no ports
27526947304SEvan Yan 	 * created under a new probe bridge dip, as ports are only
27626947304SEvan Yan 	 * created after the configurator finishing probing, thus the
27726947304SEvan Yan 	 * ndi_hp_walk_cn() will see no ports when this is called
27826947304SEvan Yan 	 * from the PCI configurtor.
27926947304SEvan Yan 	 */
28026947304SEvan Yan 	arg.nexus_dip = dip;
28126947304SEvan Yan 	arg.connector_num = DDI_HP_CN_NUM_NONE;
28226947304SEvan Yan 	arg.rv = NDI_SUCCESS;
28326947304SEvan Yan 
28426947304SEvan Yan 	/* tear down all virtual hotplug handles */
28526947304SEvan Yan 	ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
28626947304SEvan Yan 
28726947304SEvan Yan 	if (arg.rv != NDI_SUCCESS)
28826947304SEvan Yan 		return (DDI_FAILURE);
28926947304SEvan Yan 
29026947304SEvan Yan 	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
29126947304SEvan Yan 		(void) pciehpc_uninit(dip);
29226947304SEvan Yan 	else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
29326947304SEvan Yan 		(void) pcishpc_uninit(dip);
29426947304SEvan Yan 
29526947304SEvan Yan 	return (DDI_SUCCESS);
29626947304SEvan Yan }
29726947304SEvan Yan 
29826947304SEvan Yan /*
29926947304SEvan Yan  * interrupt handler
30026947304SEvan Yan  */
30126947304SEvan Yan int
pcie_hp_intr(dev_info_t * dip)30226947304SEvan Yan pcie_hp_intr(dev_info_t *dip)
30326947304SEvan Yan {
30426947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
30526947304SEvan Yan 	int		ret = DDI_INTR_UNCLAIMED;
30626947304SEvan Yan 
30726947304SEvan Yan 	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
30826947304SEvan Yan 		ret = pciehpc_intr(dip);
30926947304SEvan Yan 	else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
31026947304SEvan Yan 		ret = pcishpc_intr(dip);
31126947304SEvan Yan 
31226947304SEvan Yan 	return (ret);
31326947304SEvan Yan }
31426947304SEvan Yan 
31526947304SEvan Yan /*
31626947304SEvan Yan  * Probe the given PCIe/PCI Hotplug Connection (CN).
31726947304SEvan Yan  */
31826947304SEvan Yan /*ARGSUSED*/
31926947304SEvan Yan int
pcie_hp_probe(pcie_hp_slot_t * slot_p)32026947304SEvan Yan pcie_hp_probe(pcie_hp_slot_t *slot_p)
32126947304SEvan Yan {
32226947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
32326947304SEvan Yan 	dev_info_t	*dip = ctrl_p->hc_dip;
32426947304SEvan Yan 
32526947304SEvan Yan 	/*
32626947304SEvan Yan 	 * Call the configurator to probe a given PCI hotplug
32726947304SEvan Yan 	 * Hotplug Connection (CN).
32826947304SEvan Yan 	 */
32926947304SEvan Yan 	if (pcicfg_configure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
33026947304SEvan Yan 	    != PCICFG_SUCCESS) {
33126947304SEvan Yan 		PCIE_DBG("pcie_hp_probe() failed\n");
33226947304SEvan Yan 		return (DDI_FAILURE);
33326947304SEvan Yan 	}
33426947304SEvan Yan 	slot_p->hs_condition = AP_COND_OK;
33526947304SEvan Yan 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
33626947304SEvan Yan 	    slot_p->hs_minor), slot_p->hs_device_num);
33726947304SEvan Yan 
33826947304SEvan Yan 	/*
33926947304SEvan Yan 	 * Create ports for the newly probed devices.
34026947304SEvan Yan 	 * Note, this is only for the first level children because the
34126947304SEvan Yan 	 * descendants' ports will be created during bridge driver attach.
34226947304SEvan Yan 	 */
34326947304SEvan Yan 	return (pcie_hp_register_ports_for_dev(dip, slot_p->hs_device_num));
34426947304SEvan Yan }
34526947304SEvan Yan 
34626947304SEvan Yan /*
34726947304SEvan Yan  * Unprobe the given PCIe/PCI Hotplug Connection (CN):
34826947304SEvan Yan  *	1. remove all child device nodes
34926947304SEvan Yan  *	2. unregister all dependent ports
35026947304SEvan Yan  */
35126947304SEvan Yan /*ARGSUSED*/
35226947304SEvan Yan int
pcie_hp_unprobe(pcie_hp_slot_t * slot_p)35326947304SEvan Yan pcie_hp_unprobe(pcie_hp_slot_t *slot_p)
35426947304SEvan Yan {
35526947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
35626947304SEvan Yan 	dev_info_t	*dip = ctrl_p->hc_dip;
35726947304SEvan Yan 	pcie_hp_unreg_port_t arg;
35826947304SEvan Yan 
35926947304SEvan Yan 	/*
36026947304SEvan Yan 	 * Call the configurator to unprobe a given PCI hotplug
36126947304SEvan Yan 	 * Hotplug Connection (CN).
36226947304SEvan Yan 	 */
36326947304SEvan Yan 	if (pcicfg_unconfigure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
36426947304SEvan Yan 	    != PCICFG_SUCCESS) {
36526947304SEvan Yan 		PCIE_DBG("pcie_hp_unprobe() failed\n");
36626947304SEvan Yan 		return (DDI_FAILURE);
36726947304SEvan Yan 	}
36826947304SEvan Yan 	slot_p->hs_condition = AP_COND_UNKNOWN;
36926947304SEvan Yan 	pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
37026947304SEvan Yan 	    slot_p->hs_minor));
37126947304SEvan Yan 
37226947304SEvan Yan 	/*
37326947304SEvan Yan 	 * Remove ports for the unprobed devices.
37426947304SEvan Yan 	 * Note, this is only for the first level children because the
37526947304SEvan Yan 	 * descendants' ports were already removed during bridge driver dettach.
37626947304SEvan Yan 	 */
37726947304SEvan Yan 	arg.nexus_dip = dip;
37826947304SEvan Yan 	arg.connector_num = slot_p->hs_info.cn_num;
37926947304SEvan Yan 	arg.rv = NDI_SUCCESS;
38026947304SEvan Yan 	ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
38126947304SEvan Yan 
38226947304SEvan Yan 	return (arg.rv == NDI_SUCCESS) ? (DDI_SUCCESS) : (DDI_FAILURE);
38326947304SEvan Yan }
38426947304SEvan Yan 
38526947304SEvan Yan /* Read-only probe: no hardware register programming. */
38626947304SEvan Yan int
pcie_read_only_probe(dev_info_t * dip,char * cn_name,dev_info_t ** pcdip)38726947304SEvan Yan pcie_read_only_probe(dev_info_t *dip, char *cn_name, dev_info_t **pcdip)
38826947304SEvan Yan {
38926947304SEvan Yan 	long dev, func;
39026947304SEvan Yan 	int ret;
39126947304SEvan Yan 	char *sp;
39226947304SEvan Yan 	dev_info_t *cdip;
39326947304SEvan Yan 
39426947304SEvan Yan 	*pcdip = NULL;
39526947304SEvan Yan 	/*
39626947304SEvan Yan 	 * Parse the string of a pci Port name and get the device number
39726947304SEvan Yan 	 * and function number.
39826947304SEvan Yan 	 */
39926947304SEvan Yan 	if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
40026947304SEvan Yan 		return (DDI_EINVAL);
40126947304SEvan Yan 	if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
40226947304SEvan Yan 		return (DDI_EINVAL);
40326947304SEvan Yan 
40426947304SEvan Yan 	ret = pcicfg_configure(dip, (int)dev, (int)func,
40526947304SEvan Yan 	    PCICFG_FLAG_READ_ONLY);
40626947304SEvan Yan 	if (ret == PCICFG_SUCCESS) {
40726947304SEvan Yan 		cdip = pcie_hp_devi_find(dip, (int)dev, (int)func);
40826947304SEvan Yan 		*pcdip = cdip;
40926947304SEvan Yan 	}
41026947304SEvan Yan 	return (ret);
41126947304SEvan Yan }
41226947304SEvan Yan 
41326947304SEvan Yan /* Read-only unprobe: no hardware register programming. */
41426947304SEvan Yan int
pcie_read_only_unprobe(dev_info_t * dip,char * cn_name)41526947304SEvan Yan pcie_read_only_unprobe(dev_info_t *dip, char *cn_name)
41626947304SEvan Yan {
41726947304SEvan Yan 	long dev, func;
41826947304SEvan Yan 	int ret;
41926947304SEvan Yan 	char *sp;
42026947304SEvan Yan 
42126947304SEvan Yan 	/*
42226947304SEvan Yan 	 * Parse the string of a pci Port name and get the device number
42326947304SEvan Yan 	 * and function number.
42426947304SEvan Yan 	 */
42526947304SEvan Yan 	if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
42626947304SEvan Yan 		return (DDI_EINVAL);
42726947304SEvan Yan 	if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
42826947304SEvan Yan 		return (DDI_EINVAL);
42926947304SEvan Yan 
43026947304SEvan Yan 	ret = pcicfg_unconfigure(dip, (int)dev, (int)func,
43126947304SEvan Yan 	    PCICFG_FLAG_READ_ONLY);
43226947304SEvan Yan 
43326947304SEvan Yan 	return (ret);
43426947304SEvan Yan }
43526947304SEvan Yan 
43626947304SEvan Yan /* Control structure used to find a device in the devinfo tree */
43726947304SEvan Yan struct pcie_hp_find_ctrl {
43826947304SEvan Yan 	uint_t		device;
43926947304SEvan Yan