13db86aabSstevel /* 23db86aabSstevel * CDDL HEADER START 33db86aabSstevel * 43db86aabSstevel * The contents of this file are subject to the terms of the 53db86aabSstevel * Common Development and Distribution License (the "License"). 63db86aabSstevel * You may not use this file except in compliance with the License. 73db86aabSstevel * 83db86aabSstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93db86aabSstevel * or http://www.opensolaris.org/os/licensing. 103db86aabSstevel * See the License for the specific language governing permissions 113db86aabSstevel * and limitations under the License. 123db86aabSstevel * 133db86aabSstevel * When distributing Covered Code, include this CDDL HEADER in each 143db86aabSstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153db86aabSstevel * If applicable, add the following below this CDDL HEADER, with the 163db86aabSstevel * fields enclosed by brackets "[]" replaced with your own identifying 173db86aabSstevel * information: Portions Copyright [yyyy] [name of copyright owner] 183db86aabSstevel * 193db86aabSstevel * CDDL HEADER END 203db86aabSstevel */ 213db86aabSstevel /* 225c066ec2SJerry Gilliam * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 233db86aabSstevel * Use is subject to license terms. 243db86aabSstevel */ 253db86aabSstevel 263db86aabSstevel /* 273db86aabSstevel * Copyright (c) * Copyright (c) 2001 Tadpole Technology plc 283db86aabSstevel * All rights reserved. 293db86aabSstevel * From "@(#)pcicfg.c 1.31 99/06/18 SMI" 303db86aabSstevel */ 313db86aabSstevel 323db86aabSstevel /* 333db86aabSstevel * Cardbus hotplug module 343db86aabSstevel */ 353db86aabSstevel 363db86aabSstevel #include <sys/open.h> 373db86aabSstevel #include <sys/file.h> 383db86aabSstevel #include <sys/stat.h> 393db86aabSstevel #include <sys/ddi.h> 403db86aabSstevel #include <sys/sunndi.h> 413db86aabSstevel 423db86aabSstevel #include <sys/note.h> 433db86aabSstevel 443db86aabSstevel #include <sys/pci.h> 453db86aabSstevel 463db86aabSstevel #include <sys/hotplug/hpcsvc.h> 473db86aabSstevel #include <sys/hotplug/pci/pcicfg.h> 483db86aabSstevel #include <sys/pcic_reg.h> 493db86aabSstevel 503db86aabSstevel #include "cardbus.h" 513db86aabSstevel #include "cardbus_hp.h" 523db86aabSstevel #include "cardbus_cfg.h" 533db86aabSstevel 543db86aabSstevel /* 553db86aabSstevel * ************************************************************************ 563db86aabSstevel * *** Implementation specific data structures/definitions. *** 573db86aabSstevel * ************************************************************************ 583db86aabSstevel */ 593db86aabSstevel 603db86aabSstevel #ifndef HPC_MAX_OCCUPANTS 613db86aabSstevel #define HPC_MAX_OCCUPANTS 8 623db86aabSstevel typedef struct hpc_occupant_info { 633db86aabSstevel int i; 643db86aabSstevel char *id[HPC_MAX_OCCUPANTS]; 653db86aabSstevel } hpc_occupant_info_t; 663db86aabSstevel #endif 673db86aabSstevel 683db86aabSstevel #define PCICFG_FLAGS_CONTINUE 0x1 693db86aabSstevel 703db86aabSstevel #define PCICFG_OP_ONLINE 0x1 713db86aabSstevel #define PCICFG_OP_OFFLINE 0x0 723db86aabSstevel 733db86aabSstevel #define CBHP_DEVCTL_MINOR 255 743db86aabSstevel 753db86aabSstevel #define AP_MINOR_NUM_TO_CB_INSTANCE(x) ((x) & 0xFF) 763db86aabSstevel #define AP_MINOR_NUM(x) (((uint_t)(3) << 8) | ((x) & 0xFF)) 773db86aabSstevel #define AP_IS_CB_MINOR(x) (((x)>>8) == (3)) 783db86aabSstevel 793db86aabSstevel extern int cardbus_debug; 800d282d13Srw148561 extern int number_of_cardbus_cards; 813db86aabSstevel 823db86aabSstevel static int cardbus_autocfg_enabled = 1; /* auto config is enabled by default */ 833db86aabSstevel 843db86aabSstevel /* static functions */ 853db86aabSstevel static int cardbus_event_handler(caddr_t slot_arg, uint_t event_mask); 863db86aabSstevel static int cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, 873db86aabSstevel int request, caddr_t arg); 883db86aabSstevel static int cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl, 893db86aabSstevel hpc_slot_info_t *slot_info, int slot_state); 903db86aabSstevel static int cardbus_list_occupants(dev_info_t *dip, void *hdl); 913db86aabSstevel static void create_occupant_props(dev_info_t *self, dev_t dev); 923db86aabSstevel static void delete_occupant_props(dev_info_t *dip, dev_t dev); 933db86aabSstevel static int cardbus_configure_ap(cbus_t *cbp); 943db86aabSstevel static int cardbus_unconfigure_ap(cbus_t *cbp); 953db86aabSstevel static int cbus_unconfigure(dev_info_t *devi, int prim_bus); 963db86aabSstevel void cardbus_dump_pci_config(dev_info_t *dip); 973db86aabSstevel void cardbus_dump_pci_node(dev_info_t *dip); 983db86aabSstevel 993db86aabSstevel int 1003db86aabSstevel cardbus_init_hotplug(cbus_t *cbp) 1013db86aabSstevel { 1023db86aabSstevel char tbuf[MAXNAMELEN]; 1033db86aabSstevel hpc_slot_info_t slot_info; 1043db86aabSstevel hpc_slot_ops_t *slot_ops; 1053db86aabSstevel hpc_slot_t slhandle; /* HPS slot handle */ 1063db86aabSstevel 1073db86aabSstevel /* 1083db86aabSstevel * register the bus instance with the HPS framework. 1093db86aabSstevel */ 1103db86aabSstevel if (hpc_nexus_register_bus(cbp->cb_dip, 1113db86aabSstevel cardbus_new_slot_state, 0) != 0) { 1123db86aabSstevel cmn_err(CE_WARN, "%s%d: failed to register the bus with HPS\n", 1133db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance); 1143db86aabSstevel return (DDI_FAILURE); 1153db86aabSstevel } 1163db86aabSstevel 1173db86aabSstevel (void) sprintf(cbp->ap_id, "slot%d", cbp->cb_instance); 1183db86aabSstevel (void) ddi_pathname(cbp->cb_dip, tbuf); 1193db86aabSstevel cbp->nexus_path = kmem_alloc(strlen(tbuf) + 1, KM_SLEEP); 1203db86aabSstevel (void) strcpy(cbp->nexus_path, tbuf); 1213db86aabSstevel cardbus_err(cbp->cb_dip, 8, 1223db86aabSstevel "cardbus_init_hotplug: nexus_path set to %s", cbp->nexus_path); 1233db86aabSstevel 1243db86aabSstevel slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 1253db86aabSstevel cbp->slot_ops = slot_ops; 1263db86aabSstevel 1273db86aabSstevel /* 1283db86aabSstevel * Fill in the slot information structure that 1293db86aabSstevel * describes the slot. 1303db86aabSstevel */ 1313db86aabSstevel slot_info.version = HPC_SLOT_INFO_VERSION; 1323db86aabSstevel slot_info.slot_type = HPC_SLOT_TYPE_PCI; 1333db86aabSstevel slot_info.slot.pci.device_number = 0; 1343db86aabSstevel slot_info.slot.pci.slot_capabilities = 0; 1353db86aabSstevel 1363db86aabSstevel (void) strcpy(slot_info.slot.pci.slot_logical_name, cbp->ap_id); 1373db86aabSstevel 1383db86aabSstevel slot_ops->hpc_version = HPC_SLOT_OPS_VERSION; 1393db86aabSstevel slot_ops->hpc_op_connect = NULL; 1403db86aabSstevel slot_ops->hpc_op_disconnect = NULL; 1413db86aabSstevel slot_ops->hpc_op_insert = NULL; 1423db86aabSstevel slot_ops->hpc_op_remove = NULL; 1433db86aabSstevel slot_ops->hpc_op_control = cardbus_pci_control; 1443db86aabSstevel 1453db86aabSstevel if (hpc_slot_register(cbp->cb_dip, cbp->nexus_path, &slot_info, 1463db86aabSstevel &slhandle, slot_ops, (caddr_t)cbp, 0) != 0) { 1473db86aabSstevel /* 1483db86aabSstevel * If the slot can not be registered, 1493db86aabSstevel * then the slot_ops need to be freed. 1503db86aabSstevel */ 1513db86aabSstevel cmn_err(CE_WARN, 1523db86aabSstevel "cbp%d Unable to Register Slot %s", cbp->cb_instance, 1533db86aabSstevel slot_info.slot.pci.slot_logical_name); 1543db86aabSstevel 1553db86aabSstevel (void) hpc_nexus_unregister_bus(cbp->cb_dip); 1563db86aabSstevel hpc_free_slot_ops(slot_ops); 1573db86aabSstevel cbp->slot_ops = NULL; 1583db86aabSstevel return (DDI_FAILURE); 1593db86aabSstevel } 1603db86aabSstevel 1613db86aabSstevel ASSERT(slhandle == cbp->slot_handle); 1623db86aabSstevel 1633db86aabSstevel cardbus_err(cbp->cb_dip, 8, 1643db86aabSstevel "cardbus_init_hotplug: slot_handle 0x%p", cbp->slot_handle); 1653db86aabSstevel return (DDI_SUCCESS); 1663db86aabSstevel } 1673db86aabSstevel 1683db86aabSstevel static int 1693db86aabSstevel cardbus_event_handler(caddr_t slot_arg, uint_t event_mask) 1703db86aabSstevel { 1713db86aabSstevel int ap_minor = (int)((uintptr_t)slot_arg); 1723db86aabSstevel cbus_t *cbp; 1733db86aabSstevel int cb_instance; 1743db86aabSstevel int rv = HPC_EVENT_CLAIMED; 1753db86aabSstevel 1763db86aabSstevel cb_instance = AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor); 1773db86aabSstevel 1783db86aabSstevel ASSERT(cb_instance >= 0); 1793db86aabSstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance); 1803db86aabSstevel mutex_enter(&cbp->cb_mutex); 1813db86aabSstevel 1823db86aabSstevel switch (event_mask) { 1833db86aabSstevel 1843db86aabSstevel case HPC_EVENT_SLOT_INSERTION: 1853db86aabSstevel /* 1863db86aabSstevel * A card is inserted in the slot. Just report this 1873db86aabSstevel * event and return. 1883db86aabSstevel */ 1893db86aabSstevel cardbus_err(cbp->cb_dip, 7, 1903db86aabSstevel "cardbus_event_handler(%s%d): card is inserted", 1913db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance); 1923db86aabSstevel 1933db86aabSstevel break; 1943db86aabSstevel 1953db86aabSstevel case HPC_EVENT_SLOT_CONFIGURE: 1963db86aabSstevel /* 1973db86aabSstevel * Configure the occupant that is just inserted in the slot. 1983db86aabSstevel * The receptacle may or may not be in the connected state. If 1993db86aabSstevel * the receptacle is not connected and the auto configuration 2003db86aabSstevel * is enabled on this slot then connect the slot. If auto 2013db86aabSstevel * configuration is enabled then configure the card. 2023db86aabSstevel */ 2033db86aabSstevel if (!(cbp->auto_config)) { 2043db86aabSstevel /* 2053db86aabSstevel * auto configuration is disabled. 2063db86aabSstevel */ 2073db86aabSstevel cardbus_err(cbp->cb_dip, 7, 2083db86aabSstevel "cardbus_event_handler(%s%d): " 2093db86aabSstevel "SLOT_CONFIGURE event occured (slot %s)", 2103db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 2113db86aabSstevel cbp->name); 2123db86aabSstevel 2133db86aabSstevel break; 2143db86aabSstevel } 2153db86aabSstevel 2163db86aabSstevel cardbus_err(cbp->cb_dip, 7, 2173db86aabSstevel "cardbus_event_handler(%s%d): configure event", 2183db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance); 2193db86aabSstevel 2203db86aabSstevel if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 2213db86aabSstevel cmn_err(CE_WARN, "!slot%d already configured\n", 2223db86aabSstevel cbp->cb_instance); 2233db86aabSstevel break; 2243db86aabSstevel } 2253db86aabSstevel 2263db86aabSstevel /* 2273db86aabSstevel * Auto configuration is enabled. First, make sure the 2283db86aabSstevel * receptacle is in the CONNECTED state. 2293db86aabSstevel */ 2303db86aabSstevel if ((rv = hpc_nexus_connect(cbp->slot_handle, 2313db86aabSstevel NULL, 0)) == HPC_SUCCESS) { 2323db86aabSstevel cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */ 2333db86aabSstevel } 2343db86aabSstevel 2353db86aabSstevel if (cardbus_configure_ap(cbp) == HPC_SUCCESS) 2365c066ec2SJerry Gilliam create_occupant_props(cbp->cb_dip, makedevice( 2375c066ec2SJerry Gilliam ddi_driver_major((cbp->cb_dip)), ap_minor)); 2383db86aabSstevel else 2393db86aabSstevel rv = HPC_ERR_FAILED; 2403db86aabSstevel 2413db86aabSstevel break; 2423db86aabSstevel 2433db86aabSstevel case HPC_EVENT_SLOT_UNCONFIGURE: 2443db86aabSstevel /* 2453db86aabSstevel * Unconfigure the occupant in this slot. 2463db86aabSstevel */ 2473db86aabSstevel if (!(cbp->auto_config)) { 2483db86aabSstevel /* 2493db86aabSstevel * auto configuration is disabled. 2503db86aabSstevel */ 2513db86aabSstevel cardbus_err(cbp->cb_dip, 7, 2523db86aabSstevel "cardbus_event_handler(%s%d): " 2533db86aabSstevel "SLOT_UNCONFIGURE event" 2543db86aabSstevel " occured - auto-conf disabled (slot %s)", 2553db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 2563db86aabSstevel cbp->name); 2573db86aabSstevel 2583db86aabSstevel break; 2593db86aabSstevel } 2603db86aabSstevel 2613db86aabSstevel cardbus_err(cbp->cb_dip, 7, 2623db86aabSstevel "cardbus_event_handler(%s%d): SLOT_UNCONFIGURE event" 2633db86aabSstevel " occured (slot %s)", 2643db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 2653db86aabSstevel cbp->name); 2663db86aabSstevel 2673db86aabSstevel if (cardbus_unconfigure_ap(cbp) != HPC_SUCCESS) 2683db86aabSstevel rv = HPC_ERR_FAILED; 2693db86aabSstevel 2700d282d13Srw148561 DEVI(cbp->cb_dip)->devi_ops->devo_bus_ops = cbp->orig_bopsp; 2710d282d13Srw148561 --number_of_cardbus_cards; 2723db86aabSstevel break; 2733db86aabSstevel 2743db86aabSstevel case HPC_EVENT_SLOT_REMOVAL: 2753db86aabSstevel /* 2763db86aabSstevel * Card is removed from the slot. The card must have been 2773db86aabSstevel * unconfigured before this event. 2783db86aabSstevel */ 2793db86aabSstevel if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 2803db86aabSstevel cardbus_err(cbp->cb_dip, 1, 2813db86aabSstevel "cardbus_event_handler(%s%d): " 2823db86aabSstevel "card is removed from" 2833db86aabSstevel " the slot %s before doing unconfigure!!", 2843db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 2853db86aabSstevel cbp->name); 2863db86aabSstevel 2873db86aabSstevel break; 2883db86aabSstevel } 2893db86aabSstevel 2903db86aabSstevel cardbus_err(cbp->cb_dip, 7, 2913db86aabSstevel "cardbus_event_handler(%s%d): " 2923db86aabSstevel "card is removed from the slot %s", 2933db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 2943db86aabSstevel cbp->name); 2953db86aabSstevel 2963db86aabSstevel break; 2973db86aabSstevel 2983db86aabSstevel case HPC_EVENT_SLOT_POWER_ON: 2993db86aabSstevel /* 3003db86aabSstevel * Slot is connected to the bus. i.e the card is powered 3013db86aabSstevel * on. 3023db86aabSstevel */ 3033db86aabSstevel cardbus_err(cbp->cb_dip, 7, 3043db86aabSstevel "cardbus_event_handler(%s%d): " 3053db86aabSstevel "card is powered on in the slot %s", 3063db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 3073db86aabSstevel cbp->name); 3083db86aabSstevel 3093db86aabSstevel cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */ 3103db86aabSstevel 3113db86aabSstevel break; 3123db86aabSstevel 3133db86aabSstevel case HPC_EVENT_SLOT_POWER_OFF: 3143db86aabSstevel /* 3153db86aabSstevel * Slot is disconnected from the bus. i.e the card is powered 3163db86aabSstevel * off. 3173db86aabSstevel */ 3183db86aabSstevel cardbus_err(cbp->cb_dip, 7, 3193db86aabSstevel "cardbus_event_handler(%s%d): " 3203db86aabSstevel "card is powered off in the slot %s", 3213db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 3223db86aabSstevel cbp->name); 3233db86aabSstevel 3243db86aabSstevel cbp->rstate = AP_RSTATE_DISCONNECTED; /* record rstate */ 3253db86aabSstevel 3263db86aabSstevel break; 3273db86aabSstevel 3283db86aabSstevel default: 3293db86aabSstevel cardbus_err(cbp->cb_dip, 4, 3303db86aabSstevel "cardbus_event_handler(%s%d): " 3313db86aabSstevel "unknown event %x for this slot %s", 3323db86aabSstevel ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 3333db86aabSstevel event_mask, cbp->name); 3343db86aabSstevel 3353db86aabSstevel break; 3363db86aabSstevel } 3373db86aabSstevel 3383db86aabSstevel mutex_exit(&cbp->cb_mutex); 3393db86aabSstevel 3403db86aabSstevel return (rv); 3413db86aabSstevel } 3423db86aabSstevel 3433db86aabSstevel static int 3443db86aabSstevel cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 3453db86aabSstevel caddr_t arg) 3463db86aabSstevel { 3473db86aabSstevel cbus_t *cbp; 3483db86aabSstevel int rval = HPC_SUCCESS; 3493db86aabSstevel hpc_led_info_t *hpc_led_info; 3503db86aabSstevel 3513db86aabSstevel _NOTE(ARGUNUSED(slot_hdl)) 3523db86aabSstevel 3533db86aabSstevel cbp = (cbus_t *)ops_arg; 3543db86aabSstevel ASSERT(mutex_owned(&cbp->cb_mutex)); 3553db86aabSstevel 3563db86aabSstevel switch (request) { 3573db86aabSstevel 3585c066ec2SJerry Gilliam case HPC_CTRL_GET_SLOT_STATE: { 3593db86aabSstevel hpc_slot_state_t *hpc_slot_state; 3603db86aabSstevel 3613db86aabSstevel hpc_slot_state = (hpc_slot_state_t *)arg; 3623db86aabSstevel 3633db86aabSstevel cardbus_err(cbp->cb_dip, 7, 3643db86aabSstevel "cardbus_pci_control() - " 3653db86aabSstevel "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=0x%p", 3663db86aabSstevel (void *) hpc_slot_state); 3673db86aabSstevel 3683db86aabSstevel if (cbp->card_present) 3693db86aabSstevel *hpc_slot_state = HPC_SLOT_CONNECTED; 3703db86aabSstevel else 3713db86aabSstevel *hpc_slot_state = HPC_SLOT_EMPTY; 3723db86aabSstevel 3733db86aabSstevel break; 3743db86aabSstevel } 3753db86aabSstevel 3765c066ec2SJerry Gilliam case HPC_CTRL_GET_BOARD_TYPE: { 3773db86aabSstevel hpc_board_type_t *hpc_board_type; 3783db86aabSstevel 3793db86aabSstevel hpc_board_type = (hpc_board_type_t *)arg; 3803db86aabSstevel 3813db86aabSstevel cardbus_err(cbp->cb_dip, 7, 3823db86aabSstevel "cardbus_pci_control() - HPC_CTRL_GET_BOARD_TYPE"); 3833db86aabSstevel 3843db86aabSstevel /* 3853db86aabSstevel * The HPC driver does not know what board type 3863db86aabSstevel * is plugged in. 3873db86aabSstevel */ 3883db86aabSstevel *hpc_board_type = HPC_BOARD_PCI_HOTPLUG; 3893db86aabSstevel 3903db86aabSstevel break; 3913db86aabSstevel } 3923db86aabSstevel 3933db86aabSstevel case HPC_CTRL_DEV_CONFIGURED: 3943db86aabSstevel case HPC_CTRL_DEV_UNCONFIGURED: 3953db86aabSstevel cardbus_err(cbp->cb_dip, 5, 3963db86aabSstevel "cardbus_pci_control() - HPC_CTRL_DEV_%sCONFIGURED", 3973db86aabSstevel request == HPC_CTRL_DEV_UNCONFIGURED ? "UN" : ""); 3983db86aabSstevel break; 3993db86aabSstevel 4003db86aabSstevel case HPC_CTRL_GET_LED_STATE: 4013db86aabSstevel hpc_led_info = (hpc_led_info_t *)arg; 4023db86aabSstevel cardbus_err(cbp->cb_dip, 5, 4033db86aabSstevel "cardbus_pci_control() - HPC_CTRL_GET_LED_STATE " 4043db86aabSstevel "led %d is %d", 4053db86aabSstevel hpc_led_info->led, cbp->leds[hpc_led_info->led]); 4063db86aabSstevel 4073db86aabSstevel hpc_led_info->state = cbp->leds[hpc_led_info->led]; 4083db86aabSstevel break; 4093db86aabSstevel 4103db86aabSstevel case HPC_CTRL_SET_LED_STATE: 4113db86aabSstevel hpc_led_info = (hpc_led_info_t *)arg; 4123db86aabSstevel 4133db86aabSstevel cardbus_err(cbp->cb_dip, 4, 4143db86aabSstevel "cardbus_pci_control() - HPC_CTRL_SET_LED_STATE " 4153db86aabSstevel "led %d to %d", 4163db86aabSstevel hpc_led_info->led, hpc_led_info->state); 4173db86aabSstevel 4183db86aabSstevel cbp->leds[hpc_led_info->led] = hpc_led_info->state; 4193db86aabSstevel break; 4203db86aabSstevel 4213db86aabSstevel case HPC_CTRL_ENABLE_AUTOCFG: 4223db86aabSstevel cardbus_err(cbp->cb_dip, 5, 4233db86aabSstevel "cardbus_pci_control() - HPC_CTRL_ENABLE_AUTOCFG"); 4243db86aabSstevel 4253db86aabSstevel /* 4263db86aabSstevel * Cardbus ALWAYS does auto config, from the slots point of 4273db86aabSstevel * view this is turning on the card and making sure it's ok. 4283db86aabSstevel * This is all done by the bridge driver before we see any 4293db86aabSstevel * indication. 4303db86aabSstevel */ 4313db86aabSstevel break; 4323db86aabSstevel 4333db86aabSstevel case HPC_CTRL_DISABLE_AUTOCFG: 4343db86aabSstevel cardbus_err(cbp->cb_dip, 5, 4353db86aabSstevel "cardbus_pci_control() - HPC_CTRL_DISABLE_AUTOCFG"); 4363db86aabSstevel break; 4373db86aabSstevel 4383db86aabSstevel case HPC_CTRL_DISABLE_ENUM: 4393db86aabSstevel case HPC_CTRL_ENABLE_ENUM: 4403db86aabSstevel default: 4413db86aabSstevel rval = HPC_ERR_NOTSUPPORTED; 4423db86aabSstevel break; 4433db86aabSstevel } 4443db86aabSstevel 4453db86aabSstevel return (rval); 4463db86aabSstevel } 4473db86aabSstevel 4483db86aabSstevel /* 4493db86aabSstevel * cardbus_new_slot_state() 4503db86aabSstevel * 4513db86aabSstevel * This function is called by the HPS when it finds a hot plug 4523db86aabSstevel * slot is added or being removed from the hot plug framework. 4533db86aabSstevel * It returns 0 for success and HPC_ERR_FAILED for errors. 4543db86aabSstevel */ 4553db86aabSstevel static int 4563db86aabSstevel cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl, 4573db86aabSstevel hpc_slot_info_t *slot_info, int slot_state) 4583db86aabSstevel { 4593db86aabSstevel int cb_instance; 4603db86aabSstevel cbus_t *cbp; 4613db86aabSstevel int ap_minor; 4623db86aabSstevel int rv = 0; 4633db86aabSstevel 4643db86aabSstevel cardbus_err(dip, 8, 4653db86aabSstevel "cardbus_new_slot_state: slot_handle 0x%p", hdl); 4663db86aabSstevel 4673db86aabSstevel /* 4683db86aabSstevel * get the soft state structure for the bus instance. 4693db86aabSstevel */ 4703db86aabSstevel cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 4713db86aabSstevel DDI_PROP_DONTPASS, "cbus-instance", -1); 4723db86aabSstevel ASSERT(cb_instance >= 0); 4733db86aabSstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance); 4743db86aabSstevel 4753db86aabSstevel mutex_enter(&cbp->cb_mutex); 4763db86aabSstevel 4773db86aabSstevel switch (slot_state) { 4783db86aabSstevel 4793db86aabSstevel case HPC_SLOT_ONLINE: 4803db86aabSstevel /* 4813db86aabSstevel * Make sure the slot is not already ONLINE 4823db86aabSstevel */ 4833db86aabSstevel if (cbp->slot_handle != NULL) { 4843db86aabSstevel cardbus_err(dip, 4, 4853db86aabSstevel "cardbus_new_slot_state: " 4863db86aabSstevel "cardbus already ONLINE!!"); 4873db86aabSstevel rv = HPC_ERR_FAILED; 4883db86aabSstevel break; 4893db86aabSstevel } 4903db86aabSstevel 4913db86aabSstevel /* 4923db86aabSstevel * Add the hot plug slot to the bus. 4933db86aabSstevel */ 4943db86aabSstevel 4953db86aabSstevel /* create the AP minor node */ 4963db86aabSstevel ap_minor = AP_MINOR_NUM(cb_instance); 4973db86aabSstevel if (ddi_create_minor_node(dip, slot_info->pci_slot_name, 4983db86aabSstevel S_IFCHR, ap_minor, 4993db86aabSstevel DDI_NT_PCI_ATTACHMENT_POINT, 5003db86aabSstevel 0) == DDI_FAILURE) { 5013db86aabSstevel cardbus_err(dip, 4, 5023db86aabSstevel "cardbus_new_slot_state: " 5033db86aabSstevel "ddi_create_minor_node failed"); 5043db86aabSstevel rv = HPC_ERR_FAILED; 5053db86aabSstevel break; 5063db86aabSstevel } 5073db86aabSstevel 5083db86aabSstevel /* save the slot handle */ 5093db86aabSstevel cbp->slot_handle = hdl; 5103db86aabSstevel 5113db86aabSstevel /* setup event handler for all hardware events on the slot */ 5123db86aabSstevel if (hpc_install_event_handler(hdl, -1, cardbus_event_handler, 5133db86aabSstevel (caddr_t)((long)ap_minor)) != 0) { 5143db86aabSstevel cardbus_err(dip, 4, 5153db86aabSstevel "cardbus_new_slot_state: " 5163db86aabSstevel "install event handler failed"); 5173db86aabSstevel rv = HPC_ERR_FAILED; 5183db86aabSstevel break; 5193db86aabSstevel } 5203db86aabSstevel cbp->event_mask = (uint32_t)0xFFFFFFFF; 5213db86aabSstevel create_occupant_props(dip, 5223db86aabSstevel makedevice(ddi_name_to_major(ddi_get_name(dip)), 5233db86aabSstevel ap_minor)); 5243db86aabSstevel 5253db86aabSstevel /* set default auto configuration enabled flag for this slot */ 5263db86aabSstevel cbp->auto_config = cardbus_autocfg_enabled; 5273db86aabSstevel 5283db86aabSstevel /* copy the slot information */ 5293db86aabSstevel cbp->name = (char *)kmem_alloc(strlen(slot_info->pci_slot_name) 5303db86aabSstevel + 1, KM_SLEEP); 5313db86aabSstevel (void) strcpy(cbp->name, slot_info->pci_slot_name); 5323db86aabSstevel cardbus_err(cbp->cb_dip, 10, 5333db86aabSstevel "cardbus_new_slot_state: cbp->name set to %s", cbp->name); 5343db86aabSstevel 5353db86aabSstevel cardbus_err(dip, 4, 5363db86aabSstevel "Cardbus slot \"%s\" ONLINE\n", slot_info->pci_slot_name); 5373db86aabSstevel 5383db86aabSstevel cbp->ostate = AP_OSTATE_UNCONFIGURED; 5393db86aabSstevel cbp->rstate = AP_RSTATE_EMPTY; 5403db86aabSstevel 5413db86aabSstevel break; 5423db86aabSstevel 5433db86aabSstevel case HPC_SLOT_OFFLINE: 5443db86aabSstevel /* 5453db86aabSstevel * A hot plug slot is being removed from the bus. 5463db86aabSstevel * Make sure there is no occupant configured on the 5473db86aabSstevel * slot before removing the AP minor node. 5483db86aabSstevel */ 5493db86aabSstevel if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 5503db86aabSstevel cmn_err(CE_WARN, 5513db86aabSstevel "cardbus: Card is still in configured state"); 5523db86aabSstevel rv = HPC_ERR_FAILED; 5533db86aabSstevel break; 5543db86aabSstevel } 5553db86aabSstevel 5563db86aabSstevel /* 5573db86aabSstevel * If the AP device is in open state then return 5583db86aabSstevel * error. 5593db86aabSstevel */ 5603db86aabSstevel if (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED) { 5613db86aabSstevel rv = HPC_ERR_FAILED; 5623db86aabSstevel break; 5633db86aabSstevel } 5643db86aabSstevel 5653db86aabSstevel /* remove the minor node */ 5663db86aabSstevel ddi_remove_minor_node(dip, cbp->name); 5673db86aabSstevel /* free up the memory for the name string */ 5683db86aabSstevel kmem_free(cbp->name, strlen(cbp->name) + 1); 5693db86aabSstevel 5703db86aabSstevel /* update the slot info data */ 5713db86aabSstevel cbp->name = NULL; 5723db86aabSstevel cbp->slot_handle = NULL; 5733db86aabSstevel 5743db86aabSstevel cardbus_err(dip, 6, 5753db86aabSstevel "cardbus_new_slot_state: Cardbus slot OFFLINE"); 5763db86aabSstevel break; 5773db86aabSstevel 5783db86aabSstevel default: 5793db86aabSstevel cmn_err(CE_WARN, 5803db86aabSstevel "cardbus_new_slot_state: unknown slot_state %d\n", 5813db86aabSstevel slot_state); 5823db86aabSstevel rv = HPC_ERR_FAILED; 5833db86aabSstevel } 5843db86aabSstevel 5853db86aabSstevel mutex_exit(&cbp->cb_mutex); 5863db86aabSstevel 5873db86aabSstevel return (rv); 5883db86aabSstevel } 5893db86aabSstevel 5903db86aabSstevel static int 5913db86aabSstevel cardbus_list_occupants(dev_info_t *dip, void *hdl) 5923db86aabSstevel { 5933db86aabSstevel hpc_occupant_info_t *occupant = (hpc_occupant_info_t *)hdl; 5943db86aabSstevel char pn[MAXPATHLEN]; 5953db86aabSstevel 5963db86aabSstevel /* 5973db86aabSstevel * Ignore the attachment point and pcs. 5983db86aabSstevel */ 5993db86aabSstevel if (strcmp(ddi_binding_name(dip), "pcs") == 0) { 6003db86aabSstevel return (DDI_WALK_CONTINUE); 6013db86aabSstevel } 6023db86aabSstevel 6033db86aabSstevel (void) ddi_pathname(dip, pn); 6043db86aabSstevel 6053db86aabSstevel occupant->id[occupant->i] = kmem_alloc(strlen(pn) + 1, KM_SLEEP); 6063db86aabSstevel (void) strcpy(occupant->id[occupant->i], pn); 6073db86aabSstevel 6083db86aabSstevel occupant->i++; 6093db86aabSstevel 6103db86aabSstevel /* 6113db86aabSstevel * continue the walk to the next sibling to look for a match 6123db86aabSstevel * or to find other nodes if this card is a multi-function card. 6133db86aabSstevel */ 6143db86aabSstevel return (DDI_WALK_PRUNECHILD); 6153db86aabSstevel } 6163db86aabSstevel 6173db86aabSstevel static void 6183db86aabSstevel create_occupant_props(dev_info_t *self, dev_t dev) 6193db86aabSstevel { 6203db86aabSstevel hpc_occupant_info_t occupant; 6213db86aabSstevel int i; 6223db86aabSstevel int circular; 6233db86aabSstevel 6243db86aabSstevel occupant.i = 0; 6253db86aabSstevel 6263db86aabSstevel ndi_devi_enter(self, &circular); 6273db86aabSstevel ddi_walk_devs(ddi_get_child(self), cardbus_list_occupants, 6283db86aabSstevel (void *)&occupant); 6293db86aabSstevel ndi_devi_exit(self, circular); 6303db86aabSstevel 6313db86aabSstevel if (occupant.i == 0) { 6323db86aabSstevel char *c[] = { "" }; 6333db86aabSstevel cardbus_err(self, 1, "create_occupant_props: no occupant\n"); 6343db86aabSstevel (void) ddi_prop_update_string_array(dev, self, "pci-occupant", 6353db86aabSstevel c, 1); 6363db86aabSstevel } else { 6373db86aabSstevel cardbus_err(self, 1, 6383db86aabSstevel "create_occupant_props: %d occupant\n", occupant.i); 6393db86aabSstevel (void) ddi_prop_update_string_array(dev, self, "pci-occupant", 6403db86aabSstevel occupant.id, occupant.i); 6413db86aabSstevel } 6423db86aabSstevel 6433db86aabSstevel for (i = 0; i < occupant.i; i++) { 6443db86aabSstevel kmem_free(occupant.id[i], strlen(occupant.id[i]) + 1); 6453db86aabSstevel } 6463db86aabSstevel } 6473db86aabSstevel 6483db86aabSstevel static void 6493db86aabSstevel delete_occupant_props(dev_info_t *dip, dev_t dev) 6503db86aabSstevel { 6513db86aabSstevel if (ddi_prop_remove(dev, dip, "pci-occupant") 6523db86aabSstevel != DDI_PROP_SUCCESS) 6533db86aabSstevel return; /* add error handling */ 6543db86aabSstevel 6553db86aabSstevel } 6563db86aabSstevel 6573db86aabSstevel /* 6583db86aabSstevel * ************************************** 6593db86aabSstevel * CONFIGURE the occupant in the slot. 6603db86aabSstevel * ************************************** 6613db86aabSstevel */ 6623db86aabSstevel static int 6633db86aabSstevel cardbus_configure_ap(cbus_t *cbp) 6643db86aabSstevel { 6653db86aabSstevel dev_info_t *self = cbp->cb_dip; 6663db86aabSstevel int rv = HPC_SUCCESS; 6673db86aabSstevel hpc_slot_state_t rstate; 6683db86aabSstevel struct cardbus_config_ctrl ctrl; 6693db86aabSstevel int circular_count; 6703db86aabSstevel 6713db86aabSstevel /* 6723db86aabSstevel * check for valid request: 6733db86aabSstevel * 1. It is a hotplug slot. 6743db86aabSstevel * 2. The receptacle is in the CONNECTED state. 6753db86aabSstevel */ 6763db86aabSstevel if (cbp->slot_handle == NULL || cbp->disabled) { 6773db86aabSstevel return (ENXIO); 6783db86aabSstevel } 6793db86aabSstevel 6803db86aabSstevel /* 6813db86aabSstevel * If the occupant is already in (partially) configured 6823db86aabSstevel * state then call the ndi_devi_online() on the device 6833db86aabSstevel * subtree(s) for this attachment point. 6843db86aabSstevel */ 6853db86aabSstevel 6863db86aabSstevel if (cbp->ostate == AP_OSTATE_CONFIGURED) { 6873db86aabSstevel ctrl.flags = PCICFG_FLAGS_CONTINUE; 6883db86aabSstevel ctrl.busno = cardbus_primary_busno(self); 6893db86aabSstevel ctrl.rv = NDI_SUCCESS; 6903db86aabSstevel ctrl.dip = NULL; 6913db86aabSstevel ctrl.op = PCICFG_OP_ONLINE; 6923db86aabSstevel 6933db86aabSstevel ndi_devi_enter(self, &circular_count); 6943db86aabSstevel ddi_walk_devs(ddi_get_child(self), 6953db86aabSstevel cbus_configure, (void *)&ctrl); 6963db86aabSstevel ndi_devi_exit(self, circular_count); 6973db86aabSstevel 6983db86aabSstevel if (cardbus_debug) { 6993db86aabSstevel cardbus_dump_pci_config(self); 7003db86aabSstevel cardbus_dump_pci_node(self); 7013db86aabSstevel } 7023db86aabSstevel 7033db86aabSstevel if (ctrl.rv != NDI_SUCCESS) { 7043db86aabSstevel /* 7053db86aabSstevel * one or more of the devices are not 7063db86aabSstevel * onlined. 7073db86aabSstevel */ 7083db86aabSstevel cmn_err(CE_WARN, "cardbus(%s%d): failed to attach " 7093db86aabSstevel "one or more drivers for the card in the slot %s", 7103db86aabSstevel ddi_driver_name(self), cbp->cb_instance, 7113db86aabSstevel cbp->name); 7123db86aabSstevel } 7133db86aabSstevel 7143db86aabSstevel /* tell HPC driver that the occupant is configured */ 7153db86aabSstevel (void) hpc_nexus_control(cbp->slot_handle, 7163db86aabSstevel HPC_CTRL_DEV_CONFIGURED, NULL); 7173db86aabSstevel return (rv); 7183db86aabSstevel } 7193db86aabSstevel 7203db86aabSstevel /* 7213db86aabSstevel * Occupant is in the UNCONFIGURED state. 7223db86aabSstevel */ 7233db86aabSstevel 7243db86aabSstevel /* Check if the receptacle is in the CONNECTED state. */ 7253db86aabSstevel if (hpc_nexus_control(cbp->slot_handle, 7263db86aabSstevel HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) { 7273db86aabSstevel return (ENXIO); 7283db86aabSstevel } 7293db86aabSstevel 7303db86aabSstevel if (rstate != HPC_SLOT_CONNECTED) { 7313db86aabSstevel /* error. either the slot is empty or connect failed */ 7323db86aabSstevel return (ENXIO); 7333db86aabSstevel } 7343db86aabSstevel 7353db86aabSstevel cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */ 7363db86aabSstevel 7373db86aabSstevel /* 7383db86aabSstevel * Call the configurator to configure the card. 7393db86aabSstevel */ 7403db86aabSstevel if (cardbus_configure(cbp) != PCICFG_SUCCESS) { 7413db86aabSstevel return (EIO); 7423db86aabSstevel } 7433db86aabSstevel 7443db86aabSstevel /* record the occupant state as CONFIGURED */ 7453db86aabSstevel cbp->ostate = AP_OSTATE_CONFIGURED; 7463db86aabSstevel cbp->condition = AP_COND_OK; 7473db86aabSstevel 7483db86aabSstevel /* now, online all the devices in the AP */ 7493db86aabSstevel ctrl.flags = PCICFG_FLAGS_CONTINUE; 7503db86aabSstevel ctrl.busno = cardbus_primary_busno(self); 7513db86aabSstevel ctrl.rv = NDI_SUCCESS; 7523db86aabSstevel ctrl.dip = NULL; 7533db86aabSstevel ctrl.op = PCICFG_OP_ONLINE; 7543db86aabSstevel 7553db86aabSstevel ndi_devi_enter(self, &circular_count); 7563db86aabSstevel ddi_walk_devs(ddi_get_child(self), cbus_configure, (void *)&ctrl); 7573db86aabSstevel ndi_devi_exit(self, circular_count); 7583db86aabSstevel 7593db86aabSstevel if (cardbus_debug) { 7603db86aabSstevel cardbus_dump_pci_config(self); 7613db86aabSstevel cardbus_dump_pci_node(self); 7623db86aabSstevel } 7633db86aabSstevel if (ctrl.rv != NDI_SUCCESS) { 7643db86aabSstevel /* 7653db86aabSstevel * one or more of the devices are not 7663db86aabSstevel * ONLINE'd. 7673db86aabSstevel */ 7683db86aabSstevel cmn_err(CE_WARN, "cbhp (%s%d): failed to attach one or" 7693db86aabSstevel " more drivers for the card in the slot %s", 7703db86aabSstevel ddi_driver_name(cbp->cb_dip), 7713db86aabSstevel cbp->cb_instance, cbp->name); 7723db86aabSstevel /* rv = EFAULT; */ 7733db86aabSstevel } 7743db86aabSstevel 7753db86aabSstevel /* tell HPC driver that the occupant is configured */ 7763db86aabSstevel (void) hpc_nexus_control(cbp->slot_handle, 7773db86aabSstevel HPC_CTRL_DEV_CONFIGURED, NULL); 7783db86aabSstevel 7793db86aabSstevel return (rv); 7803db86aabSstevel } 7813db86aabSstevel 7823db86aabSstevel /* 7833db86aabSstevel * ************************************** 7843db86aabSstevel * UNCONFIGURE the occupant in the slot. 7853db86aabSstevel * ************************************** 7863db86aabSstevel */ 7873db86aabSstevel static int 7883db86aabSstevel cardbus_unconfigure_ap(cbus_t *cbp) 7893db86aabSstevel { 7903db86aabSstevel dev_info_t *self = cbp->cb_dip; 7913db86aabSstevel int rv = HPC_SUCCESS, nrv; 7923db86aabSstevel 7933db86aabSstevel /* 7943db86aabSstevel * check for valid request: 7953db86aabSstevel * 1. It is a hotplug slot. 7963db86aabSstevel * 2. The occupant is in the CONFIGURED state. 7973db86aabSstevel */ 7983db86aabSstevel 7993db86aabSstevel if (cbp->slot_handle == NULL || cbp->disabled) { 8003db86aabSstevel return (ENXIO); 8013db86aabSstevel } 8023db86aabSstevel 8033db86aabSstevel /* 8043db86aabSstevel * If the occupant is in the CONFIGURED state then 8053db86aabSstevel * call the configurator to unconfigure the slot. 8063db86aabSstevel */ 8073db86aabSstevel if (cbp->ostate == AP_OSTATE_CONFIGURED) { 8083db86aabSstevel /* 8093db86aabSstevel * Detach all the drivers for the devices in the 8103db86aabSstevel * slot. 8113db86aabSstevel */ 8123db86aabSstevel nrv = cardbus_unconfigure_node(self, 8133db86aabSstevel cardbus_primary_busno(self), 8143db86aabSstevel B_TRUE); 8153db86aabSstevel 8163db86aabSstevel if (nrv != NDI_SUCCESS) { 8173db86aabSstevel /* 8183db86aabSstevel * Failed to detach one or more drivers. 8193db86aabSstevel * Restore the status for the drivers 8203db86aabSstevel * which are offlined during this step. 8213db86aabSstevel */ 8223db86aabSstevel cmn_err(CE_WARN, 8233db86aabSstevel "cbhp (%s%d): Failed to offline all devices" 8243db86aabSstevel " (slot %s)", ddi_driver_name(cbp->cb_dip), 8253db86aabSstevel cbp->cb_instance, cbp->name); 8263db86aabSstevel rv = EBUSY; 8273db86aabSstevel } else { 8283db86aabSstevel 8293db86aabSstevel if (cardbus_unconfigure(cbp) == PCICFG_SUCCESS) { 8303db86aabSstevel /* 8313db86aabSstevel * Now that resources are freed, 8323db86aabSstevel * clear EXT and Turn LED ON. 8333db86aabSstevel */ 8343db86aabSstevel cbp->ostate = AP_OSTATE_UNCONFIGURED; 8353db86aabSstevel cbp->condition = AP_COND_UNKNOWN; 8363db86aabSstevel /* 8373db86aabSstevel * send the notification of state change 8383db86aabSstevel * to the HPC driver. 8393db86aabSstevel */ 8403db86aabSstevel (void) hpc_nexus_control(cbp->slot_handle, 8413db86aabSstevel HPC_CTRL_DEV_UNCONFIGURED, NULL); 8423db86aabSstevel } else { 8433db86aabSstevel rv = EIO; 8443db86aabSstevel } 8453db86aabSstevel } 8463db86aabSstevel } 8473db86aabSstevel 8483db86aabSstevel return (rv); 8493db86aabSstevel } 8503db86aabSstevel 8513db86aabSstevel int 8523db86aabSstevel cbus_configure(dev_info_t *dip, void *hdl) 8533db86aabSstevel { 8543db86aabSstevel pci_regspec_t *pci_rp; 8553db86aabSstevel int length, rc; 8563db86aabSstevel struct cardbus_config_ctrl *ctrl = (struct cardbus_config_ctrl *)hdl; 8573db86aabSstevel uint8_t bus, device, function; 8583db86aabSstevel 8593db86aabSstevel /* 8603db86aabSstevel * Ignore the attachment point and pcs. 8613db86aabSstevel */ 8623db86aabSstevel if (strcmp(ddi_binding_name(dip), "hp_attachment") == 0 || 8633db86aabSstevel strcmp(ddi_binding_name(dip), "pcs") == 0) { 8643db86aabSstevel cardbus_err(dip, 8, "cbus_configure: Ignoring\n"); 8653db86aabSstevel return (DDI_WALK_CONTINUE); 8663db86aabSstevel } 8673db86aabSstevel 8683db86aabSstevel cardbus_err(dip, 6, "cbus_configure\n"); 8693db86aabSstevel 8703db86aabSstevel ASSERT(ctrl->op == PCICFG_OP_ONLINE); 8713db86aabSstevel 8723db86aabSstevel /* 8733db86aabSstevel * Get the PCI device number information from the devinfo 8743db86aabSstevel * node. Since the node may not have the address field 8753db86aabSstevel * setup (this is done in the DDI_INITCHILD of the parent) 8763db86aabSstevel * we look up the 'reg' property to decode that information. 8773db86aabSstevel */ 8783db86aabSstevel if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 8793db86aabSstevel DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 8803db86aabSstevel (uint_t *)&length) != DDI_PROP_SUCCESS) { 8813db86aabSstevel /* Porbably not a real device, like PCS for example */ 8823db86aabSstevel if (ddi_get_child(dip) == NULL) 8833db86aabSstevel return (DDI_WALK_PRUNECHILD); 8843db86aabSstevel 8853db86aabSstevel cardbus_err(dip, 1, "cubs_configure: Don't configure device\n"); 8863db86aabSstevel ctrl->rv = DDI_FAILURE; 8873db86aabSstevel ctrl->dip = dip; 8883db86aabSstevel return (DDI_WALK_TERMINATE); 8893db86aabSstevel } 8903db86aabSstevel 8913db86aabSstevel if (pci_rp->pci_phys_hi == 0) 8923db86aabSstevel return (DDI_WALK_CONTINUE); 8933db86aabSstevel 8943db86aabSstevel /* get the pci device id information */ 8953db86aabSstevel bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 8963db86aabSstevel device = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 8973db86aabSstevel function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 8983db86aabSstevel 8993db86aabSstevel /* 9003db86aabSstevel * free the memory allocated by ddi_prop_lookup_int_array 9013db86aabSstevel */ 9023db86aabSstevel ddi_prop_free(pci_rp); 9033db86aabSstevel 9043db86aabSstevel if (bus <= ctrl->busno) 9053db86aabSstevel return (DDI_WALK_CONTINUE); 9063db86aabSstevel 9073db86aabSstevel cardbus_err(dip, 8, 9083db86aabSstevel "cbus_configure on-line device at: " 9093db86aabSstevel "[0x%x][0x%x][0x%x]\n", bus, device, function); 9103db86aabSstevel 9113db86aabSstevel rc = ndi_devi_online(dip, NDI_ONLINE_ATTACH|NDI_CONFIG); 9123db86aabSstevel 9133db86aabSstevel cardbus_err(dip, 7, 9143db86aabSstevel "cbus_configure %s\n", 9153db86aabSstevel rc == NDI_SUCCESS ? "Success": "Failure"); 9163db86aabSstevel 9173db86aabSstevel if (rc != NDI_SUCCESS) 9183db86aabSstevel return (DDI_WALK_PRUNECHILD); 9193db86aabSstevel 9203db86aabSstevel return (DDI_WALK_CONTINUE); 9213db86aabSstevel } 9223db86aabSstevel 9233db86aabSstevel int 9243db86aabSstevel cardbus_unconfigure_node(dev_info_t *dip, int prim_bus, boolean_t top_bridge) 9253db86aabSstevel { 9263db86aabSstevel dev_info_t *child, *next; 9273db86aabSstevel 9283db86aabSstevel cardbus_err(dip, 6, "cardbus_unconfigure_node\n"); 9293db86aabSstevel 9303db86aabSstevel /* 9313db86aabSstevel * Ignore pcs. 9323db86aabSstevel */ 9333db86aabSstevel if (strcmp(ddi_binding_name(dip), "pcs") == 0) { 9343db86aabSstevel cardbus_err(dip, 8, "cardbus_unconfigure_node: Ignoring\n"); 9353db86aabSstevel return (NDI_SUCCESS); 9363db86aabSstevel } 9373db86aabSstevel 9383db86aabSstevel /* 9393db86aabSstevel * bottom up off-line 9403db86aabSstevel */ 9413db86aabSstevel for (child = ddi_get_child(dip); child; child = next) { 9423db86aabSstevel int rc; 9433db86aabSstevel next = ddi_get_next_sibling(child); 9443db86aabSstevel rc = cardbus_unconfigure_node(child, prim_bus, B_FALSE); 9453db86aabSstevel if (rc != NDI_SUCCESS) 9463db86aabSstevel return (rc); 9473db86aabSstevel } 9483db86aabSstevel 9493db86aabSstevel /* 9503db86aabSstevel * Don't unconfigure the bridge itself. 9513db86aabSstevel */ 9523db86aabSstevel if (top_bridge) 9533db86aabSstevel return (NDI_SUCCESS); 9543db86aabSstevel 9553db86aabSstevel if (cbus_unconfigure(dip, prim_bus) != NDI_SUCCESS) { 9563db86aabSstevel cardbus_err(dip, 1, 9573db86aabSstevel "cardbus_unconfigure_node: cardbus_unconfigure failed\n"); 9583db86aabSstevel return (NDI_FAILURE); 9593db86aabSstevel } 9603db86aabSstevel return (NDI_SUCCESS); 9613db86aabSstevel } 9623db86aabSstevel 9633db86aabSstevel /* 9643db86aabSstevel * This will turn resources allocated by cbus_configure() 9653db86aabSstevel * and remove the device tree from the attachment point 9663db86aabSstevel * and below. The routine assumes the devices have their 9673db86aabSstevel * drivers detached. 9683db86aabSstevel */ 9693db86aabSstevel static int 9703db86aabSstevel cbus_unconfigure(dev_info_t *devi, int prim_bus) 9713db86aabSstevel { 9723db86aabSstevel pci_regspec_t *pci_rp; 9733db86aabSstevel uint_t bus, device, func, length; 9743db86aabSstevel int ndi_flags = NDI_UNCONFIG; 9753db86aabSstevel 9763db86aabSstevel if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi, 9773db86aabSstevel DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 9783db86aabSstevel &length) != DDI_PROP_SUCCESS) { 9793db86aabSstevel /* 9803db86aabSstevel * This cannot be one of our devices. If it's something like a 9813db86aabSstevel * SCSI device then the attempt to offline the HBA 9823db86aabSstevel * (which probably is one of our devices) 9833db86aabSstevel * will also do bottom up offlining. That 9843db86aabSstevel * will fail if this device is busy. So always 9853db86aabSstevel * return success here 9863db86aabSstevel * so that the walk will continue. 9873db86aabSstevel */ 9883db86aabSstevel return (NDI_SUCCESS); 9893db86aabSstevel } 9903db86aabSstevel 9913db86aabSstevel if (pci_rp->pci_phys_hi == 0) 9923db86aabSstevel return (NDI_FAILURE); 9933db86aabSstevel 9943db86aabSstevel bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 9953db86aabSstevel 9963db86aabSstevel if (bus <= prim_bus) 9973db86aabSstevel return (NDI_SUCCESS); 9983db86aabSstevel 9993db86aabSstevel device = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 10003db86aabSstevel func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 10013db86aabSstevel ddi_prop_free(pci_rp); 10023db86aabSstevel 10033db86aabSstevel cardbus_err(devi, 8, 10043db86aabSstevel "cbus_unconfigure: " 10053db86aabSstevel "offline bus [0x%x] device [0x%x] function [%x]\n", 10063db86aabSstevel bus, device, func); 10073db86aabSstevel if (ndi_devi_offline(devi, ndi_flags) != NDI_SUCCESS) { 10083db86aabSstevel cardbus_err(devi, 1, 10093db86aabSstevel "Device [0x%x] function [%x] is busy\n", device, func); 10103db86aabSstevel return (NDI_FAILURE); 10113db86aabSstevel } 10123db86aabSstevel 10133db86aabSstevel cardbus_err(devi, 9, 10143db86aabSstevel "Tearing down device [0x%x] function [0x%x]\n", device, func); 10153db86aabSstevel 10163db86aabSstevel if (cardbus_teardown_device(devi) != PCICFG_SUCCESS) { 10173db86aabSstevel cardbus_err(devi, 1, 10183db86aabSstevel "Failed to tear down " 10193db86aabSstevel "device [0x%x] function [0x%x]\n", device, func); 10203db86aabSstevel return (NDI_FAILURE); 10213db86aabSstevel } 10223db86aabSstevel 10233db86aabSstevel return (NDI_SUCCESS); 10243db86aabSstevel } 10253db86aabSstevel 10263db86aabSstevel boolean_t 10273db86aabSstevel cardbus_is_cb_minor(dev_t dev) 10283db86aabSstevel { 10293db86aabSstevel return (AP_IS_CB_MINOR(getminor(dev)) ? B_TRUE : B_FALSE); 10303db86aabSstevel } 10313db86aabSstevel 10323db86aabSstevel int 10333db86aabSstevel cardbus_open(dev_t *devp, int flags, int otyp, cred_t *credp) 10343db86aabSstevel { 10353db86aabSstevel cbus_t *cbp; 10363db86aabSstevel int minor; 10373db86aabSstevel 10383db86aabSstevel _NOTE(ARGUNUSED(credp)) 10393db86aabSstevel 10403db86aabSstevel minor = getminor(*devp); 10413db86aabSstevel 10423db86aabSstevel /* 10433db86aabSstevel * Make sure the open is for the right file type. 10443db86aabSstevel */ 10453db86aabSstevel if (otyp != OTYP_CHR) 10463db86aabSstevel return (EINVAL); 10473db86aabSstevel 10483db86aabSstevel /* 10493db86aabSstevel * Get the soft state structure for the 'devctl' device. 10503db86aabSstevel */ 10513db86aabSstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, 10523db86aabSstevel AP_MINOR_NUM_TO_CB_INSTANCE(minor)); 10533db86aabSstevel if (cbp == NULL) 10543db86aabSstevel return (ENXIO); 10553db86aabSstevel 10563db86aabSstevel mutex_enter(&cbp->cb_mutex); 10573db86aabSstevel 10583db86aabSstevel /* 10593db86aabSstevel * Handle the open by tracking the device state. 10603db86aabSstevel * 10613db86aabSstevel * Note: Needs review w.r.t exclusive access to AP or the bus. 10623db86aabSstevel * Currently in the pci plug-in we don't use EXCL open at all 10633db86aabSstevel * so the code below implements EXCL access on the bus. 10643db86aabSstevel */ 10653db86aabSstevel 10663db86aabSstevel /* enforce exclusive access to the bus */ 10673db86aabSstevel if ((cbp->soft_state == PCIHP_SOFT_STATE_OPEN_EXCL) || 10683db86aabSstevel ((flags & FEXCL) && 10693db86aabSstevel (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED))) { 10703db86aabSstevel mutex_exit(&cbp->cb_mutex); 10713db86aabSstevel return (EBUSY); 10723db86aabSstevel } 10733db86aabSstevel 10743db86aabSstevel if (flags & FEXCL) 10753db86aabSstevel cbp->soft_state = PCIHP_SOFT_STATE_OPEN_EXCL; 10763db86aabSstevel else 10773db86aabSstevel cbp->soft_state = PCIHP_SOFT_STATE_OPEN; 10783db86aabSstevel 10793db86aabSstevel mutex_exit(&cbp->cb_mutex); 10803db86aabSstevel return (0); 10813db86aabSstevel } 10823db86aabSstevel 10833db86aabSstevel /*ARGSUSED*/ 10843db86aabSstevel int 10853db86aabSstevel cardbus_close(dev_t dev, int flags, int otyp, cred_t *credp) 10863db86aabSstevel { 10873db86aabSstevel cbus_t *cbp; 10883db86aabSstevel int minor; 10893db86aabSstevel 10903db86aabSstevel _NOTE(ARGUNUSED(credp)) 10913db86aabSstevel 10923db86aabSstevel minor = getminor(dev); 10933db86aabSstevel 10943db86aabSstevel if (otyp != OTYP_CHR) 10953db86aabSstevel return (EINVAL); 10963db86aabSstevel 10973db86aabSstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, 10983db86aabSstevel AP_MINOR_NUM_TO_CB_INSTANCE(minor)); 10993db86aabSstevel if (cbp == NULL) 11003db86aabSstevel return (ENXIO); 11013db86aabSstevel 11023db86aabSstevel mutex_enter(&cbp->cb_mutex); 11033db86aabSstevel cbp->soft_state = PCIHP_SOFT_STATE_CLOSED; 11043db86aabSstevel mutex_exit(&cbp->cb_mutex); 11053db86aabSstevel return (0); 11063db86aabSstevel } 11073db86aabSstevel 11083db86aabSstevel /* 11093db86aabSstevel * cardbus_ioctl: devctl hotplug controls 11103db86aabSstevel */ 11113db86aabSstevel /*ARGSUSED*/ 11123db86aabSstevel int 11133db86aabSstevel cardbus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 11143db86aabSstevel int *rvalp) 11153db86aabSstevel { 11163db86aabSstevel cbus_t *cbp; 11173db86aabSstevel dev_info_t *self; 11183db86aabSstevel dev_info_t *child_dip = NULL; 11193db86aabSstevel struct devctl_iocdata *dcp; 11203db86aabSstevel uint_t bus_state; 11213db86aabSstevel int rv = 0; 11223db86aabSstevel int nrv = 0; 11233db86aabSstevel int ap_minor; 11243db86aabSstevel hpc_slot_state_t rstate; 11253db86aabSstevel devctl_ap_state_t ap_state; 11263db86aabSstevel struct hpc_control_data hpc_ctrldata; 11273db86aabSstevel struct hpc_led_info led_info; 11283db86aabSstevel 11293db86aabSstevel _NOTE(ARGUNUSED(credp)) 11303db86aabSstevel 11313db86aabSstevel ap_minor = getminor(dev); 11323db86aabSstevel cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, 11333db86aabSstevel AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor)); 11343db86aabSstevel if (cbp == NULL) 11353db86aabSstevel return (ENXIO); 11363db86aabSstevel 11373db86aabSstevel self = cbp->cb_dip; 11383db86aabSstevel /* 11393db86aabSstevel * read devctl ioctl data 11403db86aabSstevel */ 11413db86aabSstevel if ((cmd != DEVCTL_AP_CONTROL) && ndi_dc_allochdl((void *)arg, 11423db86aabSstevel &dcp) != NDI_SUCCESS) 11433db86aabSstevel return (EFAULT); 11443db86aabSstevel 11453db86aabSstevel #ifdef CARDBUS_DEBUG 11463db86aabSstevel { 11473db86aabSstevel char *cmd_name; 11483db86aabSstevel 11493db86aabSstevel switch (cmd) { 11503db86aabSstevel case DEVCTL_DEVICE_GETSTATE: cmd_name = "DEVCTL_DEVICE_GETSTATE"; break; 11513db86aabSstevel case DEVCTL_DEVICE_ONLINE: cmd_name = "DEVCTL_DEVICE_ONLINE"; break; 11523db86aabSstevel case DEVCTL_DEVICE_OFFLINE: cmd_name = "DEVCTL_DEVICE_OFFLINE"; break; 11533db86aabSstevel case DEVCTL_DEVICE_RESET: cmd_name = "DEVCTL_DEVICE_RESET"; break; 11543db86aabSstevel case DEVCTL_BUS_QUIESCE: cmd_name = "DEVCTL_BUS_QUIESCE"; break; 11553db86aabSstevel case DEVCTL_BUS_UNQUIESCE: cmd_name = "DEVCTL_BUS_UNQUIESCE"; break; 11563db86aabSstevel case DEVCTL_BUS_RESET: cmd_name = "DEVCTL_BUS_RESET"; break; 11573db86aabSstevel case DEVCTL_BUS_RESETALL: cmd_name = "DEVCTL_BUS_RESETALL"; break; 11583db86aabSstevel case DEVCTL_BUS_GETSTATE: cmd_name = "DEVCTL_BUS_GETSTATE"; break; 11593db86aabSstevel case DEVCTL_AP_CONNECT: cmd_name = "DEVCTL_AP_CONNECT"; break; 11603db86aabSstevel case DEVCTL_AP_DISCONNECT: cmd_name = "DEVCTL_AP_DISCONNECT"; break; 11613db86aabSstevel case DEVCTL_AP_INSERT: cmd_name = "DEVCTL_AP_INSERT"; break; 11623db86aabSstevel case DEVCTL_AP_REMOVE: cmd_name = "DEVCTL_AP_REMOVE"; break; 11633db86aabSstevel case DEVCTL_AP_CONFIGURE: cmd_name = "DEVCTL_AP_CONFIGURE"; break; 11643db86aabSstevel case DEVCTL_AP_UNCONFIGURE: cmd_name = "DEVCTL_AP_UNCONFIGURE"; break; 11653db86aabSstevel case DEVCTL_AP_GETSTATE: cmd_name = "DEVCTL_AP_GETSTATE"; break; 11663db86aabSstevel case DEVCTL_AP_CONTROL: cmd_name = "DEVCTL_AP_CONTROL"; break; 11673db86aabSstevel default: cmd_name = "Unknown"; break; 11683db86aabSstevel } 11693db86aabSstevel cardbus_err(cbp->cb_dip, 7, 11703db86aabSstevel "cardbus_ioctl: cmd = 0x%x, \"%s\"", cmd, cmd_name); 11713db86aabSstevel } 11723db86aabSstevel #endif 11733db86aabSstevel 11743db86aabSstevel switch (cmd) { 11753db86aabSstevel case DEVCTL_DEVICE_GETSTATE: 11763db86aabSstevel case DEVCTL_DEVICE_ONLINE: 11773db86aabSstevel case DEVCTL_DEVICE_OFFLINE: 11783db86aabSstevel case DEVCTL_BUS_GETSTATE: 11793db86aabSstevel rv = ndi_devctl_ioctl(self, cmd, arg, mode, 0); 11803db86aabSstevel ndi_dc_freehdl(dcp); 11813db86aabSstevel return (rv); 11823db86aabSstevel default: 11833db86aabSstevel break; 11843db86aabSstevel } 11853db86aabSstevel 11863db86aabSstevel switch (cmd) { 11873db86aabSstevel case DEVCTL_DEVICE_RESET: 11883db86aabSstevel rv = ENOTSUP; 11893db86aabSstevel break; 11903db86aabSstevel 11913db86aabSstevel case DEVCTL_BUS_QUIESCE: 11923db86aabSstevel if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 11933db86aabSstevel if (bus_state == BUS_QUIESCED) 11943db86aabSstevel break; 11953db86aabSstevel (void) ndi_set_bus_state(self, BUS_QUIESCED); 11963db86aabSstevel break; 11973db86aabSstevel 11983db86aabSstevel case DEVCTL_BUS_UNQUIESCE: 11993db86aabSstevel if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 12003db86aabSstevel if (bus_state == BUS_ACTIVE) 12013db86aabSstevel break; 12023db86aabSstevel (void) ndi_set_bus_state(self, BUS_ACTIVE); 12033db86aabSstevel break; 12043db86aabSstevel 12053db86aabSstevel case DEVCTL_BUS_RESET: 12063db86aabSstevel rv = ENOTSUP; 12073db86aabSstevel break; 12083db86aabSstevel 12093db86aabSstevel case DEVCTL_BUS_RESETALL: 12103db86aabSstevel rv = ENOTSUP; 12113db86aabSstevel break; 12123db86aabSstevel 12133db86aabSstevel case DEVCTL_AP_CONNECT: 12143db86aabSstevel case DEVCTL_AP_DISCONNECT: 12153db86aabSstevel /* 12163db86aabSstevel * CONNECT(DISCONNECT) the hot plug slot to(from) the bus. 12173db86aabSstevel */ 12183db86aabSstevel case DEVCTL_AP_INSERT: 12193db86aabSstevel case DEVCTL_AP_REMOVE: 12203db86aabSstevel /* 12213db86aabSstevel * Prepare the slot for INSERT/REMOVE operation. 12223db86aabSstevel */ 12233db86aabSstevel 12243db86aabSstevel /* 12253db86aabSstevel * check for valid request: 12263db86aabSstevel * 1. It is a hotplug slot. 12273db86aabSstevel * 2. The slot has no occupant that is in 12283db86aabSstevel * the 'configured' state. 12293db86aabSstevel * 12303db86aabSstevel * The lower 8 bits of the minor number is the PCI 12313db86aabSstevel * device number for the slot. 12323db86aabSstevel */ 12333db86aabSstevel if ((cbp->slot_handle == NULL) || cbp->disabled) { 12343db86aabSstevel rv = ENXIO; 12353db86aabSstevel break; 12363db86aabSstevel } 12373db86aabSstevel 12383db86aabSstevel /* the slot occupant must be in the UNCONFIGURED state */ 12393db86aabSstevel if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 12403db86aabSstevel rv = EINVAL; 12413db86aabSstevel break; 12423db86aabSstevel } 12433db86aabSstevel 12443db86aabSstevel /* 12453db86aabSstevel * Call the HPC driver to perform the operation on the slot. 12463db86aabSstevel */ 12473db86aabSstevel mutex_enter(&cbp->cb_mutex); 12483db86aabSstevel switch (cmd) { 12493db86aabSstevel case DEVCTL_AP_INSERT: 12503db86aabSstevel rv = hpc_nexus_insert(cbp->slot_handle, NULL, 0); 12513db86aabSstevel break; 12523db86aabSstevel case DEVCTL_AP_REMOVE: 12533db86aabSstevel rv = hpc_nexus_remove(cbp->slot_handle, NULL, 0); 12543db86aabSstevel break; 12553db86aabSstevel case DEVCTL_AP_CONNECT: 12563db86aabSstevel if ((rv = hpc_nexus_connect(cbp->slot_handle, 12573db86aabSstevel NULL, 0)) == 0) 12583db86aabSstevel cbp->rstate = AP_RSTATE_CONNECTED; 12593db86aabSstevel break; 12603db86aabSstevel case DEVCTL_AP_DISCONNECT: 12613db86aabSstevel if ((rv = hpc_nexus_disconnect(cbp->slot_handle, 12623db86aabSstevel NULL, 0)) == 0) 12633db86aabSstevel cbp->rstate = AP_RSTATE_DISCONNECTED; 12643db86aabSstevel break; 12653db86aabSstevel } 12663db86aabSstevel mutex_exit(&cbp->cb_mutex); 12673db86aabSstevel 12683db86aabSstevel switch (rv) { 12693db86aabSstevel case HPC_ERR_INVALID: 12703db86aabSstevel rv = ENXIO; 12713db86aabSstevel break; 12723db86aabSstevel case HPC_ERR_NOTSUPPORTED: 12733db86aabSstevel rv = ENOTSUP; 12743db86aabSstevel break; 12753db86aabSstevel case HPC_ERR_FAILED: 12763db86aabSstevel rv = EIO; 12773db86aabSstevel break; 12783db86aabSstevel } 12793db86aabSstevel 12803db86aabSstevel break; 12813db86aabSstevel 12823db86aabSstevel case DEVCTL_AP_CONFIGURE: 12833db86aabSstevel /* 12843db86aabSstevel * ************************************** 12853db86aabSstevel * CONFIGURE the occupant in the slot. 12863db86aabSstevel * ************************************** 12873db86aabSstevel */ 12883db86aabSstevel 12893db86aabSstevel mutex_enter(&cbp->cb_mutex); 12903db86aabSstevel if ((nrv = cardbus_configure_ap(cbp)) == HPC_SUCCESS) { 12913db86aabSstevel create_occupant_props(cbp->cb_dip, dev); 12923db86aabSstevel } else 12933db86aabSstevel rv = nrv; 12943db86aabSstevel mutex_exit(&cbp->cb_mutex); 12953db86aabSstevel break; 12963db86aabSstevel 12973db86aabSstevel case DEVCTL_AP_UNCONFIGURE: 12983db86aabSstevel /* 12993db86aabSstevel * ************************************** 13003db86aabSstevel * UNCONFIGURE the occupant in the slot. 13013db86aabSstevel * ************************************** 13023db86aabSstevel */ 13033db86aabSstevel 13043db86aabSstevel mutex_enter(&cbp->cb_mutex); 13053db86aabSstevel if ((nrv = cardbus_unconfigure_ap(cbp)) == HPC_SUCCESS) { 13063db86aabSstevel delete_occupant_props(cbp->cb_dip, dev); 13073db86aabSstevel } else 13083db86aabSstevel rv = nrv; 13093db86aabSstevel mutex_exit(&cbp->cb_mutex); 13103db86aabSstevel break; 13113db86aabSstevel 13123db86aabSstevel case DEVCTL_AP_GETSTATE: 13133db86aabSstevel { 13143db86aabSstevel int mutex_held; 13153db86aabSstevel 13163db86aabSstevel /* 13173db86aabSstevel * return the state of Attachment Point. 13183db86aabSstevel * 13193db86aabSstevel * If the occupant is in UNCONFIGURED state then 13203db86aabSstevel * we should get the receptacle state from the 13213db86aabSstevel * HPC driver because the receptacle state 13223db86aabSstevel * maintained in the nexus may not be accurate. 13233db86aabSstevel */ 13243db86aabSstevel 13253db86aabSstevel /* 13263db86aabSstevel * check for valid request: 13273db86aabSstevel * 1. It is a hotplug slot. 13283db86aabSstevel */ 13293db86aabSstevel if (cbp->slot_handle == NULL) { 13303db86aabSstevel rv = ENXIO; 13313db86aabSstevel break; 13323db86aabSstevel } 13333db86aabSstevel 13343db86aabSstevel /* try to acquire the slot mutex */ 13353db86aabSstevel mutex_held = mutex_tryenter(&cbp->cb_mutex); 13363db86aabSstevel 13373db86aabSstevel if (cbp->ostate == AP_OSTATE_UNCONFIGURED) { 13383db86aabSstevel if (hpc_nexus_control(cbp->slot_handle, 13393db86aabSstevel HPC_CTRL_GET_SLOT_STATE, 13403db86aabSstevel (caddr_t)&rstate) != 0) { 13413db86aabSstevel rv = ENXIO; 13423db86aabSstevel if (mutex_held) 13433db86aabSstevel mutex_exit(&cbp->cb_mutex); 13443db86aabSstevel break; 13453db86aabSstevel } 13463db86aabSstevel cbp->rstate = (ap_rstate_t)rstate; 13473db86aabSstevel } 13483db86aabSstevel 13493db86aabSstevel ap_state.ap_rstate = cbp->rstate; 13503db86aabSstevel ap_state.ap_ostate = cbp->ostate; 13513db86aabSstevel ap_state.ap_condition = cbp->condition; 13523db86aabSstevel ap_state.ap_last_change = 0; 13533db86aabSstevel ap_state.ap_error_code = 0; 13543db86aabSstevel if (mutex_held) 13553db86aabSstevel ap_state.ap_in_transition = 0; /* AP is not busy */ 13563db86aabSstevel else 13573db86aabSstevel ap_state.ap_in_transition = 1; /* AP is busy */ 13583db86aabSstevel 13593db86aabSstevel if (mutex_held) 13603db86aabSstevel mutex_exit(&cbp->cb_mutex); 13613db86aabSstevel 13623db86aabSstevel /* copy the return-AP-state information to the user space */ 13633db86aabSstevel if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) 13643db86aabSstevel rv = ENXIO; 13653db86aabSstevel 13663db86aabSstevel break; 13673db86aabSstevel 13683db86aabSstevel } 13693db86aabSstevel 13703db86aabSstevel case DEVCTL_AP_CONTROL: 13713db86aabSstevel /* 13723db86aabSstevel * HPC control functions: 13733db86aabSstevel * HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT 13743db86aabSstevel * Changes the state of the slot and preserves 13753db86aabSstevel * the state across the reboot. 13763db86aabSstevel * HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG 13773db86aabSstevel * Enables or disables the auto configuration 13783db86aabSstevel * of hot plugged occupant if the hardware 13793db86aabSstevel * supports notification of the hot plug 13803db86aabSstevel * events. 13813db86aabSstevel * HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE 13823db86aabSstevel * Controls the state of an LED. 13833db86aabSstevel * HPC_CTRL_GET_SLOT_INFO 13843db86aabSstevel * Get slot information data structure 13853db86aabSstevel * (hpc_slot_info_t). 13863db86aabSstevel * HPC_CTRL_GET_BOARD_TYPE 13873db86aabSstevel * Get board type information (hpc_board_type_t). 13883db86aabSstevel * HPC_CTRL_GET_CARD_INFO 13893db86aabSstevel * Get card information (hpc_card_info_t). 13903db86aabSstevel * 13913db86aabSstevel * These control functions are used by the cfgadm plug-in 13923db86aabSstevel * to implement "-x" and "-v" options. 13933db86aabSstevel */ 13943db86aabSstevel 13953db86aabSstevel /* copy user ioctl data first */ 13963db86aabSstevel #ifdef _MULTI_DATAMODEL 13973db86aabSstevel if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 13983db86aabSstevel struct hpc_control32_data hpc_ctrldata32; 13993db86aabSstevel 14003db86aabSstevel if (copyin((void *)arg, (void *)&hpc_ctrldata32, 14013db86aabSstevel sizeof (struct hpc_control32_data)) != 0) { 14023db86aabSstevel rv = EFAULT; 14033db86aabSstevel break; 14043db86aabSstevel } 14053db86aabSstevel hpc_ctrldata.cmd = hpc_ctrldata32.cmd; 14063db86aabSstevel hpc_ctrldata.data = 14073db86aabSstevel (void *)(intptr_t)hpc_ctrldata32.data; 14083db86aabSstevel } 14093db86aabSstevel #else 14103db86aabSstevel if (copyin((void *)arg, (void *)&hpc_ctrldata, 14113db86aabSstevel sizeof (struct hpc_control_data)) != 0) { 14123db86aabSstevel rv = EFAULT; 14133db86aabSstevel break; 14143db86aabSstevel } 14153db86aabSstevel #endif 14163db86aabSstevel 14173db86aabSstevel #ifdef CARDBUS_DEBUG 14183db86aabSstevel { 14193db86aabSstevel char *hpc_name; 14203db86aabSstevel switch (hpc_ctrldata.cmd) { 14213db86aabSstevel case HPC_CTRL_GET_LED_STATE: 14223db86aabSstevel hpc_name = "HPC_CTRL_GET_LED_STATE"; 14233db86aabSstevel break; 14243db86aabSstevel case HPC_CTRL_SET_LED_STATE: 14253db86aabSstevel hpc_name = "HPC_CTRL_SET_LED_STATE"; 14263db86aabSstevel break; 14273db86aabSstevel case HPC_CTRL_ENABLE_SLOT: 14283db86aabSstevel hpc_name = "HPC_CTRL_ENABLE_SLOT"; 14293db86aabSstevel break; 14303db86aabSstevel case HPC_CTRL_DISABLE_SLOT: 14313db86aabSstevel hpc_name = "HPC_CTRL_DISABLE_SLOT"; 14323db86aabSstevel break; 14333db86aabSstevel case HPC_CTRL_ENABLE_AUTOCFG: 14343db86aabSstevel hpc_name = "HPC_CTRL_ENABLE_AUTOCFG"; 14353db86aabSstevel break; 14363db86aabSstevel case HPC_CTRL_DISABLE_AUTOCFG: 14373db86aabSstevel hpc_name = "HPC_CTRL_DISABLE_AUTOCFG"; 14383db86aabSstevel break; 14393db86aabSstevel case HPC_CTRL_GET_BOARD_TYPE: 14403db86aabSstevel hpc_name = "HPC_CTRL_GET_BOARD_TYPE"; 14413db86aabSstevel break; 14423db86aabSstevel case HPC_CTRL_GET_SLOT_INFO: 14433db86aabSstevel hpc_name = "HPC_CTRL_GET_SLOT_INFO"; 14443db86aabSstevel break; 14453db86aabSstevel case HPC_CTRL_GET_CARD_INFO: 14463db86aabSstevel hpc_name = "HPC_CTRL_GET_CARD_INFO"; 14473db86aabSstevel break; 14483db86aabSstevel default: hpc_name = "Unknown"; break; 14493db86aabSstevel } 14503db86aabSstevel cardbus_err(cbp->cb_dip, 7, 14513db86aabSstevel "cardbus_ioctl: HP Control cmd 0x%x - \"%s\"", 14523db86aabSstevel hpc_ctrldata.cmd, hpc_name); 14533db86aabSstevel } 14543db86aabSstevel #endif 14553db86aabSstevel /* 14563db86aabSstevel * check for valid request: 14573db86aabSstevel * 1. It is a hotplug slot. 14583db86aabSstevel */ 14593db86aabSstevel if (cbp->slot_handle == NULL) { 14603db86aabSstevel rv = ENXIO; 14613db86aabSstevel break; 14623db86aabSstevel } 14633db86aabSstevel 14643db86aabSstevel mutex_enter(&cbp->cb_mutex); 14653db86aabSstevel switch (hpc_ctrldata.cmd) { 14663db86aabSstevel case HPC_CTRL_GET_LED_STATE: 14673db86aabSstevel /* copy the led info from the user space */ 14683db86aabSstevel if (copyin(hpc_ctrldata.data, (void *)&led_info, 14693db86aabSstevel sizeof (hpc_led_info_t)) != 0) { 14703db86aabSstevel rv = ENXIO; 14713db86aabSstevel break; 14723db86aabSstevel } 14733db86aabSstevel 14743db86aabSstevel /* get the state of LED information */ 14753db86aabSstevel if (hpc_nexus_control(cbp->slot_handle, 14763db86aabSstevel HPC_CTRL_GET_LED_STATE, 14773db86aabSstevel (caddr_t)&led_info) != 0) { 14783db86aabSstevel rv = ENXIO; 14793db86aabSstevel break; 14803db86aabSstevel } 14813db86aabSstevel 14823db86aabSstevel /* copy the led info to the user space */ 14833db86aabSstevel if (copyout((void *)&led_info, hpc_ctrldata.data, 14843db86aabSstevel sizeof (hpc_led_info_t)) != 0) { 14853db86aabSstevel rv = ENXIO; 14863db86aabSstevel break; 14873db86aabSstevel } 14883db86aabSstevel break; 14893db86aabSstevel 14903db86aabSstevel case HPC_CTRL_SET_LED_STATE: 14913db86aabSstevel /* copy the led info from the user space */ 14923db86aabSstevel if (copyin(hpc_ctrldata.data, (void *)&led_info, 14933db86aabSstevel sizeof (hpc_led_info_t)) != 0) { 14943db86aabSstevel rv = ENXIO; 14953db86aabSstevel break; 14963db86aabSstevel } 14973db86aabSstevel 14983db86aabSstevel /* set the state of an LED */ 14993db86aabSstevel if (hpc_nexus_control(cbp->slot_handle, 15003db86aabSstevel HPC_CTRL_SET_LED_STATE, 15013db86aabSstevel (caddr_t)&led_info) != 0) { 15023db86aabSstevel rv = ENXIO; 15033db86aabSstevel break; 15043db86aabSstevel } 15053db86aabSstevel 15063db86aabSstevel break; 15073db86aabSstevel 15083db86aabSstevel case HPC_CTRL_ENABLE_SLOT: 15093db86aabSstevel /* 15103db86aabSstevel * Enable the slot for hotplug operations. 15113db86aabSstevel */ 15123db86aabSstevel cbp->disabled = B_FALSE; 15133db86aabSstevel 15143db86aabSstevel /* tell the HPC driver also */ 15153db86aabSstevel (void) hpc_nexus_control(cbp->slot_handle, 15163db86aabSstevel HPC_CTRL_ENABLE_SLOT, NULL); 15173db86aabSstevel 15183db86aabSstevel break; 15193db86aabSstevel 15203db86aabSstevel case HPC_CTRL_DISABLE_SLOT: 15213db86aabSstevel /* 15223db86aabSstevel * Disable the slot for hotplug operations. 15233db86aabSstevel */ 15243db86aabSstevel cbp->disabled = B_TRUE; 15253db86aabSstevel 15263db86aabSstevel /* tell the HPC driver also */ 15273db86aabSstevel (void) hpc_nexus_control(cbp->slot_handle, 15283db86aabSstevel HPC_CTRL_DISABLE_SLOT, NULL); 15293db86aabSstevel 15303db86aabSstevel break; 15313db86aabSstevel 15323db86aabSstevel case HPC_CTRL_ENABLE_AUTOCFG: 15333db86aabSstevel /* 15343db86aabSstevel * Enable auto configuration on this slot. 15353db86aabSstevel */ 15363db86aabSstevel cbp->auto_config = B_TRUE; 15373db86aabSstevel 15383db86aabSstevel /* tell the HPC driver also */ 15393db86aabSstevel (void) hpc_nexus_control(cbp->slot_handle, 15403db86aabSstevel HPC_CTRL_ENABLE_AUTOCFG, NULL); 15413db86aabSstevel break; 15423db86aabSstevel 15433db86aabSstevel case HPC_CTRL_DISABLE_AUTOCFG: 15443db86aabSstevel /* 15453db86aabSstevel * Disable auto configuration on this slot. 15463db86aabSstevel */ 15473db86aabSstevel cbp->auto_config = B_FALSE; 15483db86aabSstevel 15493db86aabSstevel /* tell the HPC driver also */ 15503db86aabSstevel (void) hpc_nexus_control(cbp->slot_handle, 15513db86aabSstevel HPC_CTRL_DISABLE_AUTOCFG, NULL); 15523db86aabSstevel 15533db86aabSstevel break; 15543db86aabSstevel 15553db86aabSstevel case HPC_CTRL_GET_BOARD_TYPE: 15563db86aabSstevel { 15573db86aabSstevel hpc_board_type_t board_type; 15583db86aabSstevel 15593db86aabSstevel /* 15603db86aabSstevel * Get board type data structure, hpc_board_type_t. 15613db86aabSstevel */ 15623db86aabSstevel if (hpc_nexus_control(cbp->slot_handle, 15633db86aabSstevel HPC_CTRL_GET_BOARD_TYPE, 15643db86aabSstevel (caddr_t)&board_type) != 0) { 15653db86aabSstevel rv = ENXIO; 15663db86aabSstevel break; 15673db86aabSstevel } 15683db86aabSstevel 15693db86aabSstevel /* copy the board type info to the user space */ 15703db86aabSstevel if (copyout((void *)&board_type, hpc_ctrldata.data, 15713db86aabSstevel sizeof (hpc_board_type_t)) != 0) { 15723db86aabSstevel rv = ENXIO; 15733db86aabSstevel break; 15743db86aabSstevel } 15753db86aabSstevel 15763db86aabSstevel break; 15773db86aabSstevel } 15783db86aabSstevel 15793db86aabSstevel case HPC_CTRL_GET_SLOT_INFO: 15803db86aabSstevel { 15813db86aabSstevel hpc_slot_info_t slot_info; 15823db86aabSstevel 15833db86aabSstevel /* 15843db86aabSstevel * Get slot information structure, hpc_slot_info_t. 15853db86aabSstevel */ 15863db86aabSstevel slot_info.version = HPC_SLOT_INFO_VERSION; 15873db86aabSstevel slot_info.slot_type = 0; 15883db86aabSstevel slot_info.pci_slot_capabilities = 0; 15893db86aabSstevel slot_info.pci_dev_num = 15903db86aabSstevel (uint16_t)AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor); 15913db86aabSstevel (void) strcpy(slot_info.pci_slot_name, cbp->name); 15923db86aabSstevel 15933db86aabSstevel /* copy the slot info structure to the user space */ 15943db86aabSstevel if (copyout((void *)&slot_info, hpc_ctrldata.data, 15953db86aabSstevel sizeof (hpc_slot_info_t)) != 0) { 15963db86aabSstevel rv = ENXIO; 15973db86aabSstevel break; 15983db86aabSstevel } 15993db86aabSstevel 16003db86aabSstevel break; 16013db86aabSstevel } 16023db86aabSstevel 16033db86aabSstevel case HPC_CTRL_GET_CARD_INFO: 16043db86aabSstevel { 16053db86aabSstevel hpc_card_info_t card_info; 16063db86aabSstevel ddi_acc_handle_t handle; 16073db86aabSstevel 16083db86aabSstevel /* 16093db86aabSstevel * Get card information structure, hpc_card_info_t. 16103db86aabSstevel */ 16113db86aabSstevel 16120d282d13Srw148561 if (cbp->card_present == B_FALSE) { 16130d282d13Srw148561 rv = ENXIO; 16140d282d13Srw148561 break; 16150d282d13Srw148561 } 16163db86aabSstevel /* verify that the card is configured */ 16173db86aabSstevel if (cbp->ostate != AP_OSTATE_CONFIGURED) { 16183db86aabSstevel /* either the card is not present or */ 16193db86aabSstevel /* it is not configured. */ 16203db86aabSstevel rv = ENXIO; 16213db86aabSstevel break; 16223db86aabSstevel } 16233db86aabSstevel 16243db86aabSstevel /* get the information from the PCI config header */ 16253db86aabSstevel /* for the function 0. */ 16263db86aabSstevel for (child_dip = ddi_get_child(cbp->cb_dip); child_dip; 16273db86aabSstevel child_dip = ddi_get_next_sibling(child_dip)) 16283db86aabSstevel if (strcmp("pcs", ddi_get_name(child_dip))) 16293db86aabSstevel break; 16303db86aabSstevel 16313db86aabSstevel if (!child_dip) { 16323db86aabSstevel rv = ENXIO; 16333db86aabSstevel break; 16343db86aabSstevel } 16353db86aabSstevel 16363db86aabSstevel if (pci_config_setup(child_dip, &handle) 16373db86aabSstevel != DDI_SUCCESS) { 16383db86aabSstevel rv = EIO; 16393db86aabSstevel break; 16403db86aabSstevel } 16413db86aabSstevel card_info.prog_class = pci_config_get8(handle, 16423db86aabSstevel PCI_CONF_PROGCLASS); 16433db86aabSstevel card_info.base_class = pci_config_get8(handle, 16443db86aabSstevel PCI_CONF_BASCLASS); 16453db86aabSstevel card_info.sub_class = pci_config_get8(handle, 16463db86aabSstevel PCI_CONF_SUBCLASS); 16473db86aabSstevel card_info.header_type = pci_config_get8(handle, 16483db86aabSstevel PCI_CONF_HEADER); 16493db86aabSstevel pci_config_teardown(&handle); 16503db86aabSstevel 16513db86aabSstevel /* copy the card info structure to the user space */ 16523db86aabSstevel if (copyout((void *)&card_info, hpc_ctrldata.data, 16533db86aabSstevel sizeof (hpc_card_info_t)) != 0) { 16543db86aabSstevel rv = ENXIO; 16553db86aabSstevel break; 16563db86aabSstevel } 16573db86aabSstevel 16583db86aabSstevel break; 16593db86aabSstevel } 16603db86aabSstevel 16613db86aabSstevel default: 16623db86aabSstevel rv = EINVAL; 16633db86aabSstevel break; 16643db86aabSstevel } 16653db86aabSstevel 16663db86aabSstevel mutex_exit(&cbp->cb_mutex); 16673db86aabSstevel break; 16683db86aabSstevel 16693db86aabSstevel default: 16703db86aabSstevel rv = ENOTTY; 16713db86aabSstevel } 16723db86aabSstevel 16733db86aabSstevel if (cmd != DEVCTL_AP_CONTROL) 16743db86aabSstevel ndi_dc_freehdl(dcp); 16753db86aabSstevel 16763db86aabSstevel cardbus_err(cbp->cb_dip, 7, 16773db86aabSstevel "cardbus_ioctl: rv = 0x%x", rv); 16783db86aabSstevel 16793db86aabSstevel return (rv); 16803db86aabSstevel } 16813db86aabSstevel 16823db86aabSstevel struct cardbus_pci_desc { 16833db86aabSstevel char *name; 16843db86aabSstevel ushort_t offset; 16853db86aabSstevel int (*cfg_get_func)(); 16863db86aabSstevel char *fmt; 16873db86aabSstevel }; 16883db86aabSstevel 1689*647709cbSToomas Soome #define CFG_GET(f) ((int(*)())(uintptr_t)f) 1690*647709cbSToomas Soome 16913db86aabSstevel static struct cardbus_pci_desc generic_pci_cfg[] = { 1692*647709cbSToomas Soome { "VendorId =", 0, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1693*647709cbSToomas Soome { "DeviceId =", 2, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1694*647709cbSToomas Soome { "Command =", 4, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1695*647709cbSToomas Soome { "Status =", 6, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1696*647709cbSToomas Soome { "Latency =", 0xd, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1697*647709cbSToomas Soome { "BASE0 =", 0x10, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1698*647709cbSToomas Soome { "BASE1 =", 0x14, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1699*647709cbSToomas Soome { "BASE2 =", 0x18, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1700*647709cbSToomas Soome { "BASE3 =", 0x1c, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1701*647709cbSToomas Soome { "BASE4 =", 0x20, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1702*647709cbSToomas Soome { "CIS Pointer =", 0x28, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1703*647709cbSToomas Soome { "ILINE =", 0x3c, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1704*647709cbSToomas Soome { "IPIN =", 0x3d, CFG_GET(pci_config_get8), "%s 0x%02x" }, 17053db86aabSstevel { NULL, 0, NULL, NULL } 17063db86aabSstevel }; 17073db86aabSstevel 17083db86aabSstevel static struct cardbus_pci_desc cardbus_pci_cfg[] = { 1709*647709cbSToomas Soome { "VendorId =", 0, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1710*647709cbSToomas Soome { "DeviceId =", 2, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1711*647709cbSToomas Soome { "Command =", 4, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1712*647709cbSToomas Soome { "Status =", 6, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1713*647709cbSToomas Soome { "CacheLineSz =", 0xc, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1714*647709cbSToomas Soome { "Latency =", 0xd, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1715*647709cbSToomas Soome { "MemBase Addr=", 0x10, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1716*647709cbSToomas Soome { "Pri Bus =", 0x18, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1717*647709cbSToomas Soome { "Sec Bus =", 0x19, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1718*647709cbSToomas Soome { "Sub Bus =", 0x1a, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1719*647709cbSToomas Soome { "CBus Latency=", 0x1b, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1720*647709cbSToomas Soome { "Mem0 Base =", 0x1c, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1721*647709cbSToomas Soome { "Mem0 Limit =", 0x20, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1722*647709cbSToomas Soome { "Mem1 Base =", 0x24, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1723*647709cbSToomas Soome { "Mem1 Limit =", 0x28, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1724*647709cbSToomas Soome { "I/O0 Base =", 0x2c, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1725*647709cbSToomas Soome { "I/O0 Limit =", 0x30, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1726*647709cbSToomas Soome { "I/O1 Base =", 0x34, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1727*647709cbSToomas Soome { "I/O1 Limit =", 0x38, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1728*647709cbSToomas Soome { "ILINE =", 0x3c, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1729*647709cbSToomas Soome { "IPIN =", 0x3d, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1730*647709cbSToomas Soome { "Bridge Ctrl =", 0x3e, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1731*647709cbSToomas Soome { "Legacy Addr =", 0x44, CFG_GET(pci_config_get32), "%s 0x%08x" }, 17323db86aabSstevel { NULL, 0, NULL, NULL } 17333db86aabSstevel }; 17343db86aabSstevel 17353db86aabSstevel static void 17363db86aabSstevel cardbus_dump(struct cardbus_pci_desc *spcfg, ddi_acc_handle_t handle) 17373db86aabSstevel { 17383db86aabSstevel int i; 17393db86aabSstevel for (i = 0; spcfg[i].name; i++) { 17403db86aabSstevel 17413db86aabSstevel cmn_err(CE_NOTE, spcfg[i].fmt, spcfg[i].name, 17423db86aabSstevel spcfg[i].cfg_get_func(handle, spcfg[i].offset)); 17433db86aabSstevel } 17443db86aabSstevel 17453db86aabSstevel } 17463db86aabSstevel 17473db86aabSstevel void 17483db86aabSstevel cardbus_dump_pci_node(dev_info_t *dip) 17493db86aabSstevel { 17503db86aabSstevel dev_info_t *next; 17513db86aabSstevel struct cardbus_pci_desc *spcfg; 17523db86aabSstevel ddi_acc_handle_t config_handle; 17533db86aabSstevel uint32_t VendorId; 17543db86aabSstevel 17553db86aabSstevel cmn_err(CE_NOTE, "\nPCI leaf node of dip 0x%p:\n", (void *)dip); 17563db86aabSstevel for (next = ddi_get_child(dip); next; 17573db86aabSstevel next = ddi_get_next_sibling(next)) { 17583db86aabSstevel 17593db86aabSstevel VendorId = ddi_getprop(DDI_DEV_T_ANY, next, 17603db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 17613db86aabSstevel "vendor-id", -1); 17623db86aabSstevel if (VendorId == -1) { 17633db86aabSstevel /* not a pci device */ 17643db86aabSstevel continue; 17653db86aabSstevel } 17663db86aabSstevel 17673db86aabSstevel if (pci_config_setup(next, &config_handle) != DDI_SUCCESS) { 17683db86aabSstevel cmn_err(CE_WARN, "!pcic child: non pci device\n"); 17693db86aabSstevel continue; 17703db86aabSstevel } 17713db86aabSstevel 17723db86aabSstevel spcfg = generic_pci_cfg; 17733db86aabSstevel cardbus_dump(spcfg, config_handle); 17743db86aabSstevel pci_config_teardown(&config_handle); 17753db86aabSstevel 17763db86aabSstevel } 17773db86aabSstevel 17783db86aabSstevel } 17793db86aabSstevel 17803db86aabSstevel void 17813db86aabSstevel cardbus_dump_pci_config(dev_info_t *dip) 17823db86aabSstevel { 17833db86aabSstevel struct cardbus_pci_desc *spcfg; 17843db86aabSstevel ddi_acc_handle_t config_handle; 17853db86aabSstevel 17863db86aabSstevel if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) { 17875c066ec2SJerry Gilliam cmn_err(CE_WARN, 17885c066ec2SJerry Gilliam "!pci_config_setup() failed on 0x%p", (void *)dip); 17893db86aabSstevel return; 17903db86aabSstevel } 17913db86aabSstevel 17923db86aabSstevel spcfg = cardbus_pci_cfg; 17933db86aabSstevel cardbus_dump(spcfg, config_handle); 17943db86aabSstevel 17953db86aabSstevel pci_config_teardown(&config_handle); 17963db86aabSstevel } 17973db86aabSstevel 17983db86aabSstevel void 17993db86aabSstevel cardbus_dump_socket(dev_info_t *dip) 18003db86aabSstevel { 18013db86aabSstevel ddi_acc_handle_t iohandle; 18023db86aabSstevel caddr_t ioaddr; 18033db86aabSstevel ddi_device_acc_attr_t attr; 18043db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 18053db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 18063db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 18073db86aabSstevel if (ddi_regs_map_setup(dip, 1, 18083db86aabSstevel (caddr_t *)&ioaddr, 18093db86aabSstevel 0, 18103db86aabSstevel 4096, 18113db86aabSstevel &attr, &iohandle) != DDI_SUCCESS) { 18123db86aabSstevel cmn_err(CE_WARN, "Failed to map address for 0x%p", (void *)dip); 18133db86aabSstevel return; 18143db86aabSstevel } 18153db86aabSstevel 18163db86aabSstevel cmn_err(CE_NOTE, "////////////////////////////////////////"); 18173db86aabSstevel cmn_err(CE_NOTE, "SOCKET_EVENT = [0x%x]", 18183db86aabSstevel ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT))); 18193db86aabSstevel cmn_err(CE_NOTE, "SOCKET_MASK = [0x%x]", 18203db86aabSstevel ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK))); 18213db86aabSstevel cmn_err(CE_NOTE, "SOCKET_STATE = [0x%x]", 18223db86aabSstevel ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_PRESENT_STATE))); 18233db86aabSstevel cmn_err(CE_NOTE, "////////////////////////////////////////"); 18243db86aabSstevel 18253db86aabSstevel ddi_regs_map_free(&iohandle); 18263db86aabSstevel 18273db86aabSstevel } 1828