269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The contents of this file are subject to the terms of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common Development and Distribution License (the "License").
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You may not use this file except in compliance with the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
269473047d747f7815af570197e4ef7322d3632cEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If applicable, add the following below this CDDL HEADER, with the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * This file contains the common hotplug code that is used by Standard
269473047d747f7815af570197e4ef7322d3632cEvan Yan * PCIe and PCI HotPlug Controller code.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: This file is compiled and delivered through misc/pcie module.
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Local functions prototype */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_list_occupants(dev_info_t *dip, void *arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip,
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_match_dev_func(dev_info_t *dip, void *hdl);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic boolean_t pcie_hp_match_dev(dev_info_t *dip, int dev_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_get_df_from_port_name(char *cn_name, int *dev_num,
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_create_port_name_num(dev_info_t *dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Global functions (called by other drivers/modules)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * return description text for led state
269473047d747f7815af570197e4ef7322d3632cEvan Yan * return description text for slot condition
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to copy in a nvlist from userland
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_copyin_nvlist(char *packed_buf, size_t packed_sz, nvlist_t **nvlp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* copyin packed nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((packed = kmem_alloc(packed_sz, KM_SLEEP)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_copyin_nvlist: copyin failed.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* unpack packed nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = nvlist_unpack(packed, packed_sz, &dest, KM_SLEEP)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_copyin_nvlist: nvlist_unpack "
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to copy out a nvlist to userland
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_copyout_nvlist(nvlist_t *nvl, char *packed_buf, size_t *buf_sz)
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvl == NULL || packed_buf == NULL || buf_sz == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* pack nvlist, the library will allocate memory */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((err = nvlist_pack(nvl, &buf, &packed_sz, NV_ENCODE_NATIVE, 0))
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_copyout_nvlist: nvlist_pack "
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* copyout packed nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_copyout_nvlist: copyout " "failed.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan * init bus_hp_op entry and init hotpluggable slots & virtual ports
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Init hotplug controller */
ed11b5015754f34571b1ea0fef3f0faad03a1e45Colin Zou - Sun Microsystems - Beijing China PCIE_DBG("pcie_hp_init: initialize hotplug "
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Create port for the first level children */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* stop and cleanup */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_hp_init: initialize virtual "
269473047d747f7815af570197e4ef7322d3632cEvan Yan * uninit the hotpluggable slots and virtual ports
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Must set arg.rv to NDI_SUCCESS so that if there's no port
269473047d747f7815af570197e4ef7322d3632cEvan Yan * under this dip, we still return success thus the bridge
269473047d747f7815af570197e4ef7322d3632cEvan Yan * driver can be successfully detached.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note that during the probe PCI configurator calls
269473047d747f7815af570197e4ef7322d3632cEvan Yan * ndi_devi_offline() to detach driver for a new probed bridge,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * so that it can reprogram the resources for the bridge,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * ndi_devi_offline() calls into pcieb_detach() which in turn
269473047d747f7815af570197e4ef7322d3632cEvan Yan * calls into this function. In this case there are no ports
269473047d747f7815af570197e4ef7322d3632cEvan Yan * created under a new probe bridge dip, as ports are only
269473047d747f7815af570197e4ef7322d3632cEvan Yan * created after the configurator finishing probing, thus the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * ndi_hp_walk_cn() will see no ports when this is called
269473047d747f7815af570197e4ef7322d3632cEvan Yan * from the PCI configurtor.
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* tear down all virtual hotplug handles */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * interrupt handler
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Probe the given PCIe/PCI Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Call the configurator to probe a given PCI hotplug
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcicfg_configure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Create ports for the newly probed devices.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note, this is only for the first level children because the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * descendants' ports will be created during bridge driver attach.
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (pcie_hp_register_ports_for_dev(dip, slot_p->hs_device_num));
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unprobe the given PCIe/PCI Hotplug Connection (CN):
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 1. remove all child device nodes
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 2. unregister all dependent ports
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Call the configurator to unprobe a given PCI hotplug
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcicfg_unconfigure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Remove ports for the unprobed devices.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note, this is only for the first level children because the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * descendants' ports were already removed during bridge driver dettach.
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (arg.rv == NDI_SUCCESS) ? (DDI_SUCCESS) : (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Read-only probe: no hardware register programming. */
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_read_only_probe(dev_info_t *dip, char *cn_name, dev_info_t **pcdip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Parse the string of a pci Port name and get the device number
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and function number.
269473047d747f7815af570197e4ef7322d3632cEvan Yan cdip = pcie_hp_devi_find(dip, (int)dev, (int)func);
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Read-only unprobe: no hardware register programming. */
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_read_only_unprobe(dev_info_t *dip, char *cn_name)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Parse the string of a pci Port name and get the device number
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and function number.
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Control structure used to find a device in the devinfo tree */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * find a devinfo node with specified device and function number
269473047d747f7815af570197e4ef7322d3632cEvan Yan * in the device tree under 'dip'
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_devi_find(dev_info_t *dip, uint_t device, uint_t function)
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_walk_devs(ddi_get_child(dip), pcie_hp_match_dev_func,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to create 'pci-occupant' property for a hotplug slot
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_create_occupant_props(dev_info_t *dip, dev_t dev, int pci_dev)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = (pcie_hp_ctrl_t *)bus_p->bus_hp_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan occupant = kmem_alloc(sizeof (pcie_hp_occupant_info_t), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_walk_devs(ddi_get_child(dip), pcie_hp_list_occupants,
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (occupant->i == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* no occupants right now, need to create stub property */
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *c[] = { "" };
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_prop_update_string_array(dev, dip, "pci-occupant",
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_prop_update_string_array(dev, dip, "pci-occupant",
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; i < occupant->i; i++)
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(occupant->id[i], sizeof (char[MAXPATHLEN]));
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(occupant, sizeof (pcie_hp_occupant_info_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to remove 'pci-occupant' property for a hotplug slot
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_delete_occupant_props(dev_info_t *dip, dev_t dev)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * general code to create a minor node, called from hotplug controller
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_create_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * general code to remove a minor node, called from hotplug controller
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_remove_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Local functions (called within this file)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Register ports for all the children with device number device_num
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Found the newly probed device under the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * current slot. Register a port for it.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unregister ports of a pci bridge dip, get called from ndi_hp_walk_cn()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If connector_num is specified, then unregister the slot's dependent ports
269473047d747f7815af570197e4ef7322d3632cEvan Yan * only; Otherwise, unregister all ports of a pci bridge dip.
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_unreg_port_t *unreg_arg = (pcie_hp_unreg_port_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (info->cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (unreg_arg->connector_num != DDI_HP_CN_NUM_NONE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unregister ports for all unprobed devices under a slot. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (unreg_arg->connector_num == info->cn_num_dpd_on) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unregister all ports of a pci bridge dip. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Find a port according to cn_name and get the port's state.
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_port_state_t *port = (pcie_hp_port_state_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Matched. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Find the physical slot with the given device number;
269473047d747f7815af570197e4ef7322d3632cEvan Yan * return the slot if found.
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_find_physical_slot(dev_info_t *dip, int dev_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* PCIe has only one slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (dev_num == 0) ? (ctrl->hc_slots[0]) : (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (int slot = 0; slot < ctrl->hc_num_slots_impl; slot++) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl->hc_slots[slot]->hs_device_num == dev_num) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* found */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * setup slot name/slot-number info for the port which is being registered.
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_create_port_name_num(dev_info_t *dip, ddi_hp_cn_info_t *cn_info)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * It is under a PCIe device, devcie number is always 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan * function number might > 8 in ARI supported case.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The string length of dev_num and func_num must be no longer than 4
269473047d747f7815af570197e4ef7322d3632cEvan Yan * including the string end mark. (With ARI case considered, e.g.,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * dev_num=0x0, func_num=0xff.)
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) snprintf(tmp, PCIE_HP_DEV_FUNC_NUM_STRING_LEN, "%x%x",
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Calculate the length of cn_name.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The format of pci port name is: pci.d,f
269473047d747f7815af570197e4ef7322d3632cEvan Yan * d stands for dev_num, f stands for func_num. So the length of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * name string can be calculated as following.
269473047d747f7815af570197e4ef7322d3632cEvan Yan name_len = strlen(tmp) + PCIE_HP_PORT_NAME_STRING_LEN + 1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_name = (char *)kmem_zalloc(name_len, KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) snprintf(cn_info->cn_name, name_len, "pci.%x,%x",
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Extract device and function number from port name, whose format is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * something like 'pci.1,0'
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_get_df_from_port_name(char *cn_name, int *dev_num, int *func_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* some checks for the input name */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Check/copy cn_name and set connection numbers.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If it is a valid name, then setup cn_info for the newly created port.
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_setup_port_name_num(dev_info_t *pdip, char *cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = pcie_hp_get_df_from_port_name(cn_name, &dev_num, &func_num))
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcie_hp_check_hardware_existence(pdip, dev_num, func_num) ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (n) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common routine to create and register a new port
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Create an empty port if dip is NULL, and cn_name needs to be specified in
269473047d747f7815af570197e4ef7322d3632cEvan Yan * this case. Otherwise, create a port mapping to the specified dip, and cn_name
269473047d747f7815af570197e4ef7322d3632cEvan Yan * is not needed in this case.
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip, char *cn_name)
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info = kmem_zalloc(sizeof (ddi_hp_cn_info_t), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_setup_port_name_num(pdip, cn_name, cn_info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(cn_info->cn_name, strlen(cn_info->cn_name) + 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Check if there is a piece of hardware exist corresponding to the cn_name */
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num, int func_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * According to device and function number, check if there is a hardware
269473047d747f7815af570197e4ef7322d3632cEvan Yan * device exists. Currently, this function can not be reached before
269473047d747f7815af570197e4ef7322d3632cEvan Yan * we enable state transition to or from "Port-Empty" or "Port-Present"
269473047d747f7815af570197e4ef7322d3632cEvan Yan * states. When the pci device type project is integrated, we are going
269473047d747f7815af570197e4ef7322d3632cEvan Yan * to call the pci config space access interfaces introduced by it.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Dispatch hotplug commands to different hotplug controller drivers, including
269473047d747f7815af570197e4ef7322d3632cEvan Yan * physical and virtual hotplug operations.
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* ARGSUSED */
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_common_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pcie_hp_common_ops: dip=%p cn_name=%s op=%x arg=%p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* create an empty port */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (pcie_hp_register_port(NULL, dip, cn_name));
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* this is for physical slot state change */
269473047d747f7815af570197e4ef7322d3632cEvan Yan " dip=%p cn_name=%s"
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_hp_walk_cn(dip, pcie_hp_get_port_state, &state_arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* can not find the port */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Check if this is for changing port's state: change to/from
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Upgrade state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (target_state ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Downgrade state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* PCIe hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_hp_ops(dip, cn_name, op, arg, result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* PCI SHPC hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcishpc_hp_ops(dip, cn_name, op, arg, result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_hp_common_ops: op is not supported."
269473047d747f7815af570197e4ef7322d3632cEvan Yan " dip=%p cn_name=%s"
269473047d747f7815af570197e4ef7322d3632cEvan Yan * like in attach, since hotplugging can change error registers,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * we need to ensure that the proper bits are set on this port
269473047d747f7815af570197e4ef7322d3632cEvan Yan * after a configure operation
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret == DDI_SUCCESS) && (op == DDI_HPOP_CN_CHANGE_STATE) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (*(ddi_hp_cn_state_t *)arg == DDI_HP_CN_STATE_ENABLED))
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pcie_hp_match_dev_func:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Match dip's PCI device number and function number with input ones.
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct pcie_hp_find_ctrl *ctrl = (struct pcie_hp_find_ctrl *)hdl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the PCI device address info */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free the memory allocated by ddi_prop_lookup_int_array
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* found the match for the specified device address */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * continue the walk to the next sibling to look for a match.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pcie_hp_match_dev:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Match the dip's pci device number with the input dev_num
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the PCI device address info */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free the memory allocated by ddi_prop_lookup_int_array
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* found the match for the specified device address */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Callback function to match with device number in order to list
269473047d747f7815af570197e4ef7322d3632cEvan Yan * occupants under a specific slot
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_cn_cfg_t *cn_cfg_p = (pcie_hp_cn_cfg_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Get the PCI device number information from the devinfo
269473047d747f7815af570197e4ef7322d3632cEvan Yan * node. Since the node may not have the address field
269473047d747f7815af570197e4ef7322d3632cEvan Yan * setup (this is done in the DDI_INITCHILD of the parent)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * we look up the 'reg' property to decode that information.
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the pci device id information */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free the memory allocated by ddi_prop_lookup_int_array
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Match the node for the device number of the slot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If the node is not yet attached, then don't list it
269473047d747f7815af570197e4ef7322d3632cEvan Yan * as an occupant. This is valid, since nothing can be
269473047d747f7815af570197e4ef7322d3632cEvan Yan * consuming it until it is attached, and cfgadm will
269473047d747f7815af570197e4ef7322d3632cEvan Yan * ask for the property explicitly which will cause it
269473047d747f7815af570197e4ef7322d3632cEvan Yan * to be re-freshed right before checking with rcm.
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((major == DDI_MAJOR_T_NONE) || !i_ddi_devi_attached(dip))
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If we have used all our occupants then print mesage
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and terminate walk.
269473047d747f7815af570197e4ef7322d3632cEvan Yan "pcie (%s%d): unable to list all occupants",
269473047d747f7815af570197e4ef7322d3632cEvan Yan * No need to hold the dip as ddi_walk_devs
269473047d747f7815af570197e4ef7322d3632cEvan Yan * has already arranged that for us.
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_pathname(dip, (char *)occupant->id[occupant->i]);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * continue the walk to the next sibling to look for a match
269473047d747f7815af570197e4ef7322d3632cEvan Yan * or to find other nodes if this card is a multi-function card.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Generate the System Event for ESC_DR_REQ.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * One of the consumers is pcidr, it calls to libcfgadm to perform a
269473047d747f7815af570197e4ef7322d3632cEvan Yan * configure or unconfigure operation to the AP.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Minor device name (AP) will be bus path
269473047d747f7815af570197e4ef7322d3632cEvan Yan * concatenated with slot name
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_pathname(self, cn_path + strlen("/devices"));
269473047d747f7815af570197e4ef7322d3632cEvan Yan "%s%d: Failed to allocate memory for AP ID: %s:%s",
269473047d747f7815af570197e4ef7322d3632cEvan Yan err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan "%s%d: Failed to allocate memory "
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan "%s%d: Failed to add attr [%s] "
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Add attachment point as attribute (common attribute)
269473047d747f7815af570197e4ef7322d3632cEvan Yan err = nvlist_add_string(ev_attr_list, DR_AP_ID, ap_id);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event",
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Log this event with sysevent framework.
269473047d747f7815af570197e4ef7322d3632cEvan Yan err = ddi_log_sysevent(self, DDI_VENDOR_SUNW, EC_DR,
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {