269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
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 *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * or http://www.opensolaris.org/os/licensing.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
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 *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * This file contains the common hotplug code that is used by Standard
269473047d747f7815af570197e4ef7322d3632cEvan Yan * PCIe and PCI HotPlug Controller code.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: This file is compiled and delivered through misc/pcie module.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/types.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/conf.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/kmem.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/debug.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/vtrace.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/autoconf.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/varargs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi_impldefs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/time.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/note.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/callb.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunndi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysevent.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysevent/eventdefs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysevent/dr.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/pci_impl.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/pci_cap.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/hotplug/pci/pcicfg.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/hotplug/pci/pcie_hp.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/hotplug/pci/pciehpc.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/hotplug/pci/pcishpc.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <io/pciex/pcieb.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 Yan char *cn_name);
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 Yan int *func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_create_port_name_num(dev_info_t *dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_info_t *cn_info);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num,
269473047d747f7815af570197e4ef7322d3632cEvan Yan int func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Global functions (called by other drivers/modules)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * return description text for led state
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanchar *
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_led_state_text(pcie_hp_led_state_t state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_LED_ON:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_LED_OFF:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_LED_BLINK:
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * return description text for slot condition
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanchar *
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_slot_condition_text(ap_condition_t condition)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (condition) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case AP_COND_UNKNOWN:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_UNKNOWN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case AP_COND_OK:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_OK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case AP_COND_FAILING:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_FAILING);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case AP_COND_FAILED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_FAILED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case AP_COND_UNUSABLE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_UNUSABLE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIEHPC_PROP_VALUE_UNKNOWN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to copy in a nvlist from userland
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_copyin_nvlist(char *packed_buf, size_t packed_sz, nvlist_t **nvlp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *packed;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *dest = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (packed_buf == NULL || packed_sz == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* copyin packed nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((packed = kmem_alloc(packed_sz, KM_SLEEP)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyin(packed_buf, packed, packed_sz) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_copyin_nvlist: copyin failed.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto copyin_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 "failed with err %d\n", ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (ret) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case EINVAL:
269473047d747f7815af570197e4ef7322d3632cEvan Yan case ENOTSUP:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto copyin_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case ENOMEM:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto copyin_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto copyin_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan *nvlp = dest;
269473047d747f7815af570197e4ef7322d3632cEvan Yancopyin_cleanup:
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(packed, packed_sz);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to copy out a nvlist to userland
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_copyout_nvlist(nvlist_t *nvl, char *packed_buf, size_t *buf_sz)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int err = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *buf = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan size_t packed_sz;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvl == NULL || packed_buf == NULL || buf_sz == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_copyout_nvlist: nvlist_pack "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "failed with err %d\n", err);
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (err) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case EINVAL:
269473047d747f7815af570197e4ef7322d3632cEvan Yan case ENOTSUP:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case ENOMEM:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_ENOMEM);
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (packed_sz > *buf_sz) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* copyout packed nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyout(buf, packed_buf, packed_sz) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_copyout_nvlist: copyout " "failed.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(buf, packed_sz);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *buf_sz = packed_sz;
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(buf, packed_sz);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * init bus_hp_op entry and init hotpluggable slots & virtual ports
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_init(dev_info_t *dip, caddr_t arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS, count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *cdip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Init hotplug controller */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_init(dip, arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcishpc_init(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS) {
ed11b5015754f34571b1ea0fef3f0faad03a1e45Colin Zou - Sun Microsystems - Beijing China PCIE_DBG("pcie_hp_init: initialize hotplug "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "controller failed with %d\n", ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Create port for the first level children */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cdip = ddi_get_child(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (cdip != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = pcie_hp_register_port(cdip, dip, NULL))
269473047d747f7815af570197e4ef7322d3632cEvan Yan != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* stop and cleanup */
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan cdip = ddi_get_next_sibling(cdip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_hp_init: initialize virtual "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "hotplug port failed with %d\n", ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pcie_hp_uninit(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * uninit the hotpluggable slots and virtual ports
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_uninit(dev_info_t *dip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_unreg_port_t arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 *
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.nexus_dip = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.connector_num = DDI_HP_CN_NUM_NONE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.rv = NDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* tear down all virtual hotplug handles */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (arg.rv != NDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pciehpc_uninit(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pcishpc_uninit(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * interrupt handler
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_intr(dev_info_t *dip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_INTR_UNCLAIMED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p))
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_intr(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p))
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcishpc_intr(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Probe the given PCIe/PCI Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_probe(pcie_hp_slot_t *slot_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = ctrl_p->hc_dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Call the configurator to probe a given PCI hotplug
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcicfg_configure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan != PCICFG_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pcie_hp_probe() failed\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_condition = AP_COND_OK;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_minor), slot_p->hs_device_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (pcie_hp_register_ports_for_dev(dip, slot_p->hs_device_num));
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_unprobe(pcie_hp_slot_t *slot_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = ctrl_p->hc_dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_unreg_port_t arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Call the configurator to unprobe a given PCI hotplug
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcicfg_unconfigure(dip, slot_p->hs_device_num, PCICFG_ALL_FUNC, 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan != PCICFG_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pcie_hp_unprobe() failed\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_minor));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.nexus_dip = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.connector_num = slot_p->hs_info.cn_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan arg.rv = NDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_hp_walk_cn(dip, pcie_hp_unregister_ports_cb, &arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (arg.rv == NDI_SUCCESS) ? (DDI_SUCCESS) : (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Read-only probe: no hardware register programming. */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_read_only_probe(dev_info_t *dip, char *cn_name, dev_info_t **pcdip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan long dev, func;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *sp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *cdip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *pcdip = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Parse the string of a pci Port name and get the device number
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and function number.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcicfg_configure(dip, (int)dev, (int)func,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCICFG_FLAG_READ_ONLY);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret == PCICFG_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cdip = pcie_hp_devi_find(dip, (int)dev, (int)func);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *pcdip = cdip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Read-only unprobe: no hardware register programming. */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_read_only_unprobe(dev_info_t *dip, char *cn_name)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan long dev, func;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *sp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Parse the string of a pci Port name and get the device number
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and function number.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_strtol(cn_name + 4, &sp, 10, &dev) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_strtol(sp + 1, NULL, 10, &func) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcicfg_unconfigure(dip, (int)dev, (int)func,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCICFG_FLAG_READ_ONLY);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Control structure used to find a device in the devinfo tree */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstruct pcie_hp_find_ctrl {
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t device;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t function;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan};
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * find a devinfo node with specified device and function number
269473047d747f7815af570197e4ef7322d3632cEvan Yan * in the device tree under 'dip'
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yandev_info_t *
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_devi_find(dev_info_t *dip, uint_t device, uint_t function)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct pcie_hp_find_ctrl ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl.device = device;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl.function = function;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl.dip = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_walk_devs(ddi_get_child(dip), pcie_hp_match_dev_func,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)&ctrl);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, count);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ctrl.dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to create 'pci-occupant' property for a hotplug slot
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_create_occupant_props(dev_info_t *dip, dev_t dev, int pci_dev)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = (pcie_hp_ctrl_t *)bus_p->bus_hp_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slotp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_cn_cfg_t cn_cfg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_occupant_info_t *occupant;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int circular, i;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_enter(dip, &circular);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slotp = (ctrl_p && (pci_dev == 0)) ?
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_slots[pci_dev] : NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan int slot_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_num = (ctrl_p->hc_device_increases) ?
269473047d747f7815af570197e4ef7322d3632cEvan Yan (pci_dev - ctrl_p->hc_device_start) :
269473047d747f7815af570197e4ef7322d3632cEvan Yan (pci_dev + ctrl_p->hc_device_start);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slotp = ctrl_p->hc_slots[slot_num];
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slotp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slotp == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan occupant = kmem_alloc(sizeof (pcie_hp_occupant_info_t), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan occupant->i = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_cfg.flag = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_cfg.rv = NDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_cfg.dip = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_cfg.slotp = (void *)slotp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_cfg.cn_private = (void *)occupant;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_walk_devs(ddi_get_child(dip), pcie_hp_list_occupants,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)&cn_cfg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 c, 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_prop_update_string_array(dev, dip, "pci-occupant",
269473047d747f7815af570197e4ef7322d3632cEvan Yan occupant->id, occupant->i);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; i < occupant->i; i++)
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(occupant->id[i], sizeof (char[MAXPATHLEN]));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(occupant, sizeof (pcie_hp_occupant_info_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_devi_exit(dip, circular);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * routine to remove 'pci-occupant' property for a hotplug slot
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_delete_occupant_props(dev_info_t *dip, dev_t dev)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_prop_remove(dev, dip, "pci-occupant");
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * general code to create a minor node, called from hotplug controller
269473047d747f7815af570197e4ef7322d3632cEvan Yan * drivers.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_create_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = ctrl_p->hc_dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[slot];
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_info_t *info_p = &slot_p->hs_info;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_create_minor_node(dip, info_p->cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan S_IFCHR, slot_p->hs_minor,
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_NT_PCI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_prop_update_int(DDI_DEV_T_NONE,
269473047d747f7815af570197e4ef7322d3632cEvan Yan dip, "ap-names", 1 << slot_p->hs_device_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * general code to remove a minor node, called from hotplug controller
269473047d747f7815af570197e4ef7322d3632cEvan Yan * drivers.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_remove_minor_node(pcie_hp_ctrl_t *ctrl_p, int slot)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_remove_minor_node(ctrl_p->hc_dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_slots[slot]->hs_info.cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Local functions (called within this file)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Register ports for all the children with device number device_num
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_register_ports_for_dev(dev_info_t *dip, int device_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *cdip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (cdip = ddi_get_child(dip); cdip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cdip = ddi_get_next_sibling(cdip)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcie_hp_match_dev(cdip, device_num)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Found the newly probed device under the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * current slot. Register a port for it.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = pcie_hp_register_port(cdip, dip, NULL))
269473047d747f7815af570197e4ef7322d3632cEvan Yan != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unregister ports of a pci bridge dip, get called from ndi_hp_walk_cn()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
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 Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_unregister_ports_cb(ddi_hp_cn_info_t *info, void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_unreg_port_t *unreg_arg = (pcie_hp_unreg_port_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = unreg_arg->nexus_dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv = NDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (info->cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan unreg_arg->rv = rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ndi_hp_unregister(dip, info->cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unregister all ports of a pci bridge dip. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = ndi_hp_unregister(dip, info->cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan unreg_arg->rv = rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv == NDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Find a port according to cn_name and get the port's state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_get_port_state(ddi_hp_cn_info_t *info, void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_port_state_t *port = (pcie_hp_port_state_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (info->cn_type != DDI_HP_CN_TYPE_VIRTUAL_PORT)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(info->cn_name, port->cn_name) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Matched. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan port->cn_state = info->cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan port->rv = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_CONTINUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Find the physical slot with the given device number;
269473047d747f7815af570197e4ef7322d3632cEvan Yan * return the slot if found.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pcie_hp_slot_t *
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_find_physical_slot(dev_info_t *dip, int dev_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl = PCIE_GET_HP_CTRL(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* PCIe has only one slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (dev_num == 0) ? (ctrl->hc_slots[0]) : (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
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 return (ctrl->hc_slots[slot]);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * setup slot name/slot-number info for the port which is being registered.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_create_port_name_num(dev_info_t *dip, ddi_hp_cn_info_t *cn_info)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret, dev_num, func_num, name_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *pdip = ddi_get_parent(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(pdip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_req_id_t bdf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char tmp[PCIE_HP_DEV_FUNC_NUM_STRING_LEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_get_bdf_from_dip(dip, &bdf);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_IS_PCI2PCIE(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_num = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan func_num = (bdf & ((~PCI_REG_BUS_M) >> 8));
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_num = (bdf & (PCI_REG_DEV_M >> 8)) >> 3;
269473047d747f7815af570197e4ef7322d3632cEvan Yan func_num = bdf & (PCI_REG_FUNC_M >> 8);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) snprintf(tmp, PCIE_HP_DEV_FUNC_NUM_STRING_LEN, "%x%x",
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_num, func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan name_len = strlen(tmp) + PCIE_HP_PORT_NAME_STRING_LEN + 1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 dev_num, func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_num = (dev_num << 8) | func_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot = pcie_find_physical_slot(pdip, dev_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_num_dpd_on = slot ?
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot->hs_info.cn_num : DDI_HP_CN_NUM_NONE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Extract device and function number from port name, whose format is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * something like 'pci.1,0'
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_get_df_from_port_name(char *cn_name, int *dev_num, int *func_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int name_len, ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan long d, f;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *sp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* some checks for the input name */
269473047d747f7815af570197e4ef7322d3632cEvan Yan name_len = strlen(cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((name_len <= PCIE_HP_PORT_NAME_STRING_LEN) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (name_len > (PCIE_HP_PORT_NAME_STRING_LEN +
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_HP_DEV_FUNC_NUM_STRING_LEN - 1)) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (strncmp("pci.", cn_name, 4) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = ddi_strtol(cn_name + 4, &sp, 10, &d);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strncmp(",", sp, 1) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = ddi_strtol(sp + 1, NULL, 10, &f);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *dev_num = (int)d;
269473047d747f7815af570197e4ef7322d3632cEvan Yan *func_num = (int)f;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
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 Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_setup_port_name_num(dev_info_t *pdip, char *cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_info_t *cn_info)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int dev_num, func_num, ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = pcie_hp_get_df_from_port_name(cn_name, &dev_num, &func_num))
269473047d747f7815af570197e4ef7322d3632cEvan Yan != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcie_hp_check_hardware_existence(pdip, dev_num, func_num) ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_state = DDI_HP_CN_STATE_PRESENT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_state = DDI_HP_CN_STATE_EMPTY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_name = ddi_strdup(cn_name, KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_num = (dev_num << 8) | func_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot = pcie_find_physical_slot(pdip, dev_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_num_dpd_on = slot->hs_info.cn_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanndi2ddi(int n)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (n) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case NDI_SUCCESS:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case NDI_NOMEM:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case NDI_BUSY:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_EBUSY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case NDI_EINVAL:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case NDI_ENOTSUP:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case NDI_FAILURE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common routine to create and register a new port
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
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 Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_register_port(dev_info_t *dip, dev_info_t *pdip, char *cn_name)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_info_t *cn_info;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT((dip == NULL) != (cn_name == NULL));
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info = kmem_zalloc(sizeof (ddi_hp_cn_info_t), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (dip != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_create_port_name_num(dip, cn_info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_setup_port_name_num(pdip, cn_name, cn_info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(cn_info, sizeof (ddi_hp_cn_info_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_child = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_type = DDI_HP_CN_TYPE_VIRTUAL_PORT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_info->cn_type_str = DDI_HP_CN_TYPE_STR_PORT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = ndi_hp_register(pdip, cn_info);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(cn_info->cn_name, strlen(cn_info->cn_name) + 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(cn_info, sizeof (ddi_hp_cn_info_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ndi2ddi(ret));
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Check if there is a piece of hardware exist corresponding to the cn_name */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_check_hardware_existence(dev_info_t *dip, int dev_num, int func_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * VHPTODO:
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan _NOTE(ARGUNUSED(dip, dev_num, func_num));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Dispatch hotplug commands to different hotplug controller drivers, including
269473047d747f7815af570197e4ef7322d3632cEvan Yan * physical and virtual hotplug operations.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* ARGSUSED */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_common_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
269473047d747f7815af570197e4ef7322d3632cEvan Yan void *arg, void *result)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pcie_hp_common_ops: dip=%p cn_name=%s op=%x arg=%p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan dip, cn_name, op, arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (op) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_CREATE_PORT:
269473047d747f7815af570197e4ef7322d3632cEvan Yan {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* create an empty port */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (pcie_hp_register_port(NULL, dip, cn_name));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_CHANGE_STATE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t curr_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_port_state_t state_arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (target_state < DDI_HP_CN_STATE_PORT_EMPTY) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* this is for physical slot state change */
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pcie_hp_common_ops: change port state"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " dip=%p cn_name=%s"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " op=%x arg=%p\n", (void *)dip, cn_name, op, arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan state_arg.rv = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan state_arg.cn_name = cn_name;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ndi_hp_walk_cn(dip, pcie_hp_get_port_state, &state_arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (state_arg.rv != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* can not find the port */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = state_arg.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Check if this is for changing port's state: change to/from
269473047d747f7815af570197e4ef7322d3632cEvan Yan * PORT_EMPTY/PRESENT states.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (curr_state < target_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Upgrade state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (curr_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_PORT_EMPTY:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (target_state ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_PORT_PRESENT) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan int dev_num, func_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_get_df_from_port_name(
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_name, &dev_num, &func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto port_state_done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_check_hardware_existence(
269473047d747f7815af570197e4ef7322d3632cEvan Yan dip, dev_num, func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (target_state ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_OFFLINE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_read_only_probe(dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_name, (dev_info_t **)result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto port_state_done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_PORT_PRESENT:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (target_state ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_OFFLINE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_read_only_probe(dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_name, (dev_info_t **)result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto port_state_done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT("unexpected state");
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Downgrade state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (curr_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_PORT_PRESENT:
269473047d747f7815af570197e4ef7322d3632cEvan Yan {
269473047d747f7815af570197e4ef7322d3632cEvan Yan int dev_num, func_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_get_df_from_port_name(cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &dev_num, &func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto port_state_done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_check_hardware_existence(dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_num, func_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto port_state_done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_OFFLINE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_read_only_unprobe(dip, cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto port_state_done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT("unexpected state");
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yanport_state_done:
269473047d747f7815af570197e4ef7322d3632cEvan Yan *(ddi_hp_cn_state_t *)result = curr_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (PCIE_IS_PCIE_HOTPLUG_CAPABLE(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* PCIe hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_hp_ops(dip, cn_name, op, arg, result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_CAPABLE(bus_p)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* PCI SHPC hotplug */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcishpc_hp_ops(dip, cn_name, op, arg, result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "pcie_hp_common_ops: op is not supported."
269473047d747f7815af570197e4ef7322d3632cEvan Yan " dip=%p cn_name=%s"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " op=%x arg=%p\n", (void *)dip, cn_name, op, arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#if defined(__i386) || defined(__amd64)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
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 pcieb_intel_error_workaround(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pcie_hp_match_dev_func:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Match dip's PCI device number and function number with input ones.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_match_dev_func(dev_info_t *dip, void *hdl)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct pcie_hp_find_ctrl *ctrl = (struct pcie_hp_find_ctrl *)hdl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_regspec_t *pci_rp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int length;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int pci_dev, pci_func;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 ctrl->dip = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the PCI device address info */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free the memory allocated by ddi_prop_lookup_int_array
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_prop_free(pci_rp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* found the match for the specified device address */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl->dip = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * continue the walk to the next sibling to look for a match.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_PRUNECHILD);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pcie_hp_match_dev:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Match the dip's pci device number with the input dev_num
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic boolean_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_match_dev(dev_info_t *dip, int dev_num)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_regspec_t *pci_rp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int length;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int pci_dev;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 return (B_FALSE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the PCI device address info */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free the memory allocated by ddi_prop_lookup_int_array
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_prop_free(pci_rp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pci_dev == dev_num) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* found the match for the specified device address */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (B_TRUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (B_FALSE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Callback function to match with device number in order to list
269473047d747f7815af570197e4ef7322d3632cEvan Yan * occupants under a specific slot
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_list_occupants(dev_info_t *dip, void *arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_cn_cfg_t *cn_cfg_p = (pcie_hp_cn_cfg_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_occupant_info_t *occupant =
269473047d747f7815af570197e4ef7322d3632cEvan Yan (pcie_hp_occupant_info_t *)cn_cfg_p->cn_private;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p =
269473047d747f7815af570197e4ef7322d3632cEvan Yan (pcie_hp_slot_t *)cn_cfg_p->slotp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int pci_dev;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_regspec_t *pci_rp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int length;
269473047d747f7815af570197e4ef7322d3632cEvan Yan major_t major;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (uint_t *)&length) != DDI_PROP_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_cfg_p->rv = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_cfg_p->dip = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the pci device id information */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free the memory allocated by ddi_prop_lookup_int_array
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_prop_free(pci_rp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Match the node for the device number of the slot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pci_dev == slot_p->hs_device_num) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan major = ddi_driver_major(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((major == DDI_MAJOR_T_NONE) || !i_ddi_devi_attached(dip))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_PRUNECHILD);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If we have used all our occupants then print mesage
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and terminate walk.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (occupant->i >= PCIE_HP_MAX_OCCUPANTS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "pcie (%s%d): unable to list all occupants",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(ddi_get_parent(dip)),
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_instance(ddi_get_parent(dip)));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_TERMINATE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * No need to hold the dip as ddi_walk_devs
269473047d747f7815af570197e4ef7322d3632cEvan Yan * has already arranged that for us.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan occupant->id[occupant->i] =
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_alloc(sizeof (char[MAXPATHLEN]), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_pathname(dip, (char *)occupant->id[occupant->i]);
269473047d747f7815af570197e4ef7322d3632cEvan Yan occupant->i++;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_WALK_PRUNECHILD);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpcie_hp_gen_sysevent_req(char *slot_name, int hint,
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *self, int kmflag)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan sysevent_id_t eid;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *ev_attr_list = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char cn_path[MAXPATHLEN];
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *ap_id;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int err, ap_id_len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Minor device name (AP) will be bus path
269473047d747f7815af570197e4ef7322d3632cEvan Yan * concatenated with slot name
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strcpy(cn_path, "/devices");
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ddi_pathname(self, cn_path + strlen("/devices"));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ap_id_len = strlen(cn_path) + strlen(":") +
269473047d747f7815af570197e4ef7322d3632cEvan Yan strlen(slot_name) + 1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ap_id = kmem_zalloc(ap_id_len, kmflag);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ap_id == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "%s%d: Failed to allocate memory for AP ID: %s:%s",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(self), ddi_get_instance(self),
269473047d747f7815af570197e4ef7322d3632cEvan Yan cn_path, slot_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strcpy(ap_id, cn_path);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strcat(ap_id, ":");
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) strcat(ap_id, slot_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "%s%d: Failed to allocate memory "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "for event attributes%s", ddi_driver_name(self),
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_instance(self), ESC_DR_REQ);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(ap_id, ap_id_len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (hint) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan case SE_INVESTIGATE_RES: /* fall through */
269473047d747f7815af570197e4ef7322d3632cEvan Yan case SE_INCOMING_RES: /* fall through */
269473047d747f7815af570197e4ef7322d3632cEvan Yan case SE_OUTGOING_RES: /* fall through */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan err = nvlist_add_string(ev_attr_list, DR_REQ_TYPE,
269473047d747f7815af570197e4ef7322d3632cEvan Yan SE_REQ2STR(hint));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "%s%d: Failed to add attr [%s] "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "for %s event", ddi_driver_name(self),
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_instance(self),
269473047d747f7815af570197e4ef7322d3632cEvan Yan DR_REQ_TYPE, ESC_DR_REQ);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "%s%d: Unknown hint on sysevent",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(self), ddi_get_instance(self));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Add attachment point as attribute (common attribute)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan err = nvlist_add_string(ev_attr_list, DR_AP_ID, ap_id);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(self), ddi_get_instance(self),
269473047d747f7815af570197e4ef7322d3632cEvan Yan DR_AP_ID, EC_DR);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto done;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Log this event with sysevent framework.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan err = ddi_log_sysevent(self, DDI_VENDOR_SUNW, EC_DR,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ESC_DR_REQ, ev_attr_list, &eid,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((kmflag == KM_SLEEP) ? DDI_SLEEP : DDI_NOSLEEP));
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (err != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "%s%d: Failed to log %s event",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(self), ddi_get_instance(self), EC_DR);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yandone:
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(ev_attr_list);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(ap_id, ap_id_len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}