11708Sstevel /* 21708Sstevel * CDDL HEADER START 31708Sstevel * 41708Sstevel * The contents of this file are subject to the terms of the 51708Sstevel * Common Development and Distribution License (the "License"). 61708Sstevel * You may not use this file except in compliance with the License. 71708Sstevel * 81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91708Sstevel * or http://www.opensolaris.org/os/licensing. 101708Sstevel * See the License for the specific language governing permissions 111708Sstevel * and limitations under the License. 121708Sstevel * 131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each 141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151708Sstevel * If applicable, add the following below this CDDL HEADER, with the 161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 181708Sstevel * 191708Sstevel * CDDL HEADER END 201708Sstevel */ 211708Sstevel 221708Sstevel /* 23*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241708Sstevel * Use is subject to license terms. 251708Sstevel */ 261708Sstevel 271708Sstevel 281708Sstevel /* 291708Sstevel * Starcat IOSRAM/Tunnel PCI Hot Plug Controller Driver 301708Sstevel */ 311708Sstevel 321708Sstevel #define CPCI_ENUM 331708Sstevel 341708Sstevel #include <sys/note.h> 351708Sstevel #include <sys/types.h> 361708Sstevel #include <sys/cmn_err.h> 371708Sstevel #include <sys/kmem.h> 381708Sstevel #include <sys/errno.h> 391708Sstevel #include <sys/open.h> 401708Sstevel #include <sys/stat.h> 411708Sstevel #include <sys/conf.h> 421708Sstevel #include <sys/ddi.h> 431708Sstevel #include <sys/cmn_err.h> 441708Sstevel #include <sys/sunddi.h> 451708Sstevel #include <sys/sunndi.h> 461708Sstevel #include <sys/ddi_impldefs.h> 471708Sstevel #include <sys/ndi_impldefs.h> 481708Sstevel #include <sys/modctl.h> 491708Sstevel #include <sys/disp.h> 501708Sstevel #include <sys/async.h> 511708Sstevel #include <sys/hotplug/hpcsvc.h> 521708Sstevel #include <sys/mboxsc.h> 531708Sstevel #include <sys/schpc_msg.h> 541708Sstevel #include <sys/schpc.h> 551708Sstevel #include <post/scat_dcd.h> 561708Sstevel #include <sys/taskq.h> 571708Sstevel 581708Sstevel #ifdef DEBUG 591708Sstevel int schpc_dump_save_regs = 0; 601708Sstevel static uint_t schpc_debug_flags = 0; 611708Sstevel #define SCHPC_DEBUG0(f, s) if ((f)& schpc_debug_flags) \ 621708Sstevel cmn_err(CE_CONT, "schpc: " s "\n") 631708Sstevel #define SCHPC_DEBUG1(f, s, a) if ((f)& schpc_debug_flags) \ 641708Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a) 651708Sstevel #define SCHPC_DEBUG2(f, s, a, b) if ((f)& schpc_debug_flags) \ 661708Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b) 671708Sstevel #define SCHPC_DEBUG3(f, s, a, b, c) if ((f)& schpc_debug_flags) \ 681708Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c) 691708Sstevel #define SCHPC_DEBUG4(f, s, a, b, c, d) if ((f)& schpc_debug_flags) \ 701708Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d) 711708Sstevel #define SCHPC_DEBUG5(f, s, a, b, c, d, e) if ((f)& schpc_debug_flags) \ 721708Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e) 731708Sstevel #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& schpc_debug_flags) \ 741708Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e, ff) 751708Sstevel #else 761708Sstevel 771708Sstevel #define SCHPC_DEBUG0(f, s) 781708Sstevel #define SCHPC_DEBUG1(f, s, a) 791708Sstevel #define SCHPC_DEBUG2(f, s, a, b) 801708Sstevel #define SCHPC_DEBUG3(f, s, a, b, c) 811708Sstevel #define SCHPC_DEBUG4(f, s, a, b, c, d) 821708Sstevel #define SCHPC_DEBUG5(f, s, a, b, c, d, e) 831708Sstevel #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) 841708Sstevel 851708Sstevel #endif 861708Sstevel 871708Sstevel #define D_IDENTIFY 0x00000001 881708Sstevel #define D_ATTACH 0x00000002 891708Sstevel #define D_DETACH 0x00000004 901708Sstevel #define D_OPEN 0x00000008 911708Sstevel #define D_GETSLOTSTATUS 0x00000010 921708Sstevel #define D_SETSLOTSTATUS 0x00000020 931708Sstevel #define D_IOCTL 0x00010000 941708Sstevel #define D_IOC_CONNECT 0x00020000 951708Sstevel #define D_IOC_CONTROL 0x00040000 961708Sstevel #define D_IOC_CONFIG 0x00080000 971708Sstevel #define D_IOC_STATUS 0x00100000 981708Sstevel #define D_IOC_MSG 0x00200000 991708Sstevel #define D_IOC_TEST 0x00400000 1001708Sstevel #define D_IOC_LED 0x00800000 1011708Sstevel #define D_EVENT 0x01000000 1021708Sstevel #define D_THREAD 0x02000000 1031708Sstevel #define D_TRANSID 0x04000000 1041708Sstevel #define D_SLOTTABLE 0x08000000 1051708Sstevel #define D_FREQCHG 0x10000000 1061708Sstevel #define D_APID 0x20000000 1071708Sstevel 1081708Sstevel /* 1091708Sstevel * driver global data: 1101708Sstevel */ 1111708Sstevel static void *per_schpc_state; /* soft state head */ 1121708Sstevel dev_info_t *schpc_devi; 1131708Sstevel static schpc_t *schpc_p; 1141708Sstevel 1151708Sstevel clock_t schpc_timeout_putmsg = 60 * 1000; /* 60 seconds */ 1161708Sstevel clock_t schpc_timeout_getmsg = 60 * 1000; /* 60 seconds */ 1171708Sstevel clock_t schpc_timeout_event = 60 * 5 * 1000; /* 5 minutes */ 1181708Sstevel 1191708Sstevel int schpc_use_legacy_apid = 0; 1201708Sstevel 1211708Sstevel static mboxsc_timeout_range_t schpc_putmsg_timeout_range; 1221708Sstevel static mboxsc_timeout_range_t schpc_getmsg_timeout_range; 1231708Sstevel 1241708Sstevel static taskq_t *schpc_event_taskq = NULL; 1251708Sstevel 1261708Sstevel /* 1271708Sstevel * replies to mboxsc_getmsg() are handled asynchronously by the 1281708Sstevel * schpc_msg_thread using a linked list of schpc_replylist_t 1291708Sstevel * elements 1301708Sstevel */ 1311708Sstevel typedef struct schpc_replylist { 1321708Sstevel struct schpc_replylist *prev; /* link to previous entry */ 1331708Sstevel struct schpc_replylist *next; /* link to next entry */ 1341708Sstevel kcondvar_t reply_cv; /* condvar for getting reply */ 1351708Sstevel kmutex_t reply_lock; /* mutex for getting reply */ 1361708Sstevel uint32_t type; /* mboxsc_xxxmsg() msg type */ 1371708Sstevel uint32_t cmd; /* mboxsc_xxxmsg() cmd */ 1381708Sstevel uint64_t transid; /* mboxsc_xxxmsg() trans id */ 1391708Sstevel uint32_t length; /* mboxsc_xxxmsg() length */ 1401708Sstevel pcimsg_t reply; /* mboxsc_xxxmsg() reply msg */ 1411708Sstevel boolean_t reply_recvd; /* msg reply received */ 1421708Sstevel boolean_t reply_cexit; /* client early exit */ 1431708Sstevel } schpc_replylist_t; 1441708Sstevel 1451708Sstevel static kmutex_t schpc_replylist_mutex; /* replylist mutex */ 1461708Sstevel static uint32_t schpc_replylist_count; /* replylist size */ 1471708Sstevel static schpc_replylist_t *schpc_replylist_first; /* replylist 1st elem */ 1481708Sstevel static schpc_replylist_t *schpc_replylist_last; /* replylist last elem */ 1491708Sstevel static boolean_t slots_registered = B_FALSE; /* slots registered? */ 1501708Sstevel 1511708Sstevel typedef struct { 1521708Sstevel char *cname; 1531708Sstevel char *caddr; 1541708Sstevel char schizo; 1551708Sstevel char leaf; 1561708Sstevel dev_info_t *dip; 1571708Sstevel } find_dev_t; 1581708Sstevel 1591708Sstevel /* 1601708Sstevel * Function prototypes for local functions 1611708Sstevel */ 1621708Sstevel static int schpc_getexpander(dev_info_t *); 1631708Sstevel static int schpc_getboard(dev_info_t *); 1641708Sstevel static void schpc_event_handler(void *); 1651708Sstevel static void schpc_event_filter(pcimsg_t *msg); 1661708Sstevel static void schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd, 1671708Sstevel uint64_t transid, uint32_t length); 1681708Sstevel static uint64_t schpc_gettransid(schpc_t *, int); 1691708Sstevel static int schpc_slot_get_index(schpc_t *, hpc_slot_t); 1701708Sstevel static void schpc_register_all_slots(schpc_t *); 1711708Sstevel static void schpc_setslotled(int, int, int, uint32_t); 1721708Sstevel static void schpc_init_setslot_message(pci_setslot_t *); 1731708Sstevel static void schpc_test(caddr_t, int, void *, uint_t); 1741708Sstevel static int schpc_getslotstatus(uint32_t, uint32_t, uint32_t, pci_getslot_t *); 1751708Sstevel static int schpc_setslotstatus(uint32_t, uint32_t, uint32_t, pci_setslot_t *); 1761708Sstevel static int schpc_match_dip(dev_info_t *, void *); 1771708Sstevel static void schpc_buildapid(dev_info_t *, int, char *); 1781708Sstevel static int schpc_get_slot_status(uint_t, uint_t, uint_t); 1791708Sstevel static void schpc_replylist_unlink(schpc_replylist_t *entry); 1801708Sstevel static schpc_replylist_t *schpc_replylist_link(uint32_t cmd, uint64_t transid, 1811708Sstevel uint32_t length); 1821708Sstevel static void schpc_msg_thread(void); 1831708Sstevel static int schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, 1841708Sstevel uint64_t *transidp, uint32_t length, 1851708Sstevel void *datap, clock_t timeout, 1861708Sstevel schpc_replylist_t **entryp); 1871708Sstevel static int schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp, 1881708Sstevel uint64_t *transidp, uint32_t *lengthp, void *datap, 1891708Sstevel clock_t timeout, schpc_replylist_t *listp); 1901708Sstevel 1911708Sstevel static int schpc_slot_freq(pci_getslot_t *); 1921708Sstevel static int schpc_find_dip(dev_info_t *, void *); 1931708Sstevel 1941708Sstevel static int schpc_save_leaf(int slot); 1951708Sstevel static void schpc_restore_leaf(int slot); 1961708Sstevel static int schpc_is_leaf_reset_required(int slot); 1971708Sstevel static int schpc_is_freq_switchable(int slot); 1981708Sstevel static void schpc_save_entry(int slot, int list_entry, int save_entry); 1991708Sstevel static void schpc_restore_entry(int slot, int list_entry, int save_entry); 2001708Sstevel 2011708Sstevel /* 2021708Sstevel * Function prototype for Hot Plug Services 2031708Sstevel */ 2041708Sstevel static int schpc_connect(caddr_t, hpc_slot_t, void *, uint_t); 2051708Sstevel static int schpc_disconnect(caddr_t, hpc_slot_t, void *, uint_t); 2061708Sstevel static int schpc_cpci_control(caddr_t, hpc_slot_t, int, caddr_t); 2071708Sstevel static int schpc_pci_control(caddr_t, hpc_slot_t, int, caddr_t); 2081708Sstevel 2091708Sstevel extern int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t); 2101708Sstevel 2111708Sstevel /* 2121708Sstevel * cb_ops and dev_ops: 2131708Sstevel */ 2141708Sstevel static struct cb_ops schpc_cb_ops = { 2151708Sstevel nodev, /* open */ 2161708Sstevel nodev, /* close */ 2171708Sstevel nodev, /* strategy */ 2181708Sstevel nodev, /* print */ 2191708Sstevel nodev, /* dump */ 2201708Sstevel nodev, /* read */ 2211708Sstevel nodev, /* write */ 2221708Sstevel nodev, /* ioctl */ 2231708Sstevel nodev, /* devmap */ 2241708Sstevel nodev, /* mmap */ 2251708Sstevel nodev, /* segmap */ 2261708Sstevel nochpoll, /* poll */ 2271708Sstevel ddi_prop_op, /* prop_op */ 2281708Sstevel 0, /* streamtab */ 2291708Sstevel D_NEW | D_MP | D_HOTPLUG /* Driver compatibility flag */ 2301708Sstevel }; 2311708Sstevel 2321708Sstevel /* 2331708Sstevel * Function prototype for dev_ops 2341708Sstevel */ 2351708Sstevel static int schpc_attach(dev_info_t *, ddi_attach_cmd_t); 2361708Sstevel static int schpc_detach(dev_info_t *, ddi_detach_cmd_t); 2371708Sstevel static int schpc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 2381708Sstevel 2391708Sstevel static struct dev_ops schpc_dev_ops = { 240*7656SSherry.Moore@Sun.COM DEVO_REV, /* devo_rev, */ 241*7656SSherry.Moore@Sun.COM 0, /* refcnt */ 242*7656SSherry.Moore@Sun.COM schpc_info, /* get_dev_info */ 243*7656SSherry.Moore@Sun.COM nulldev, /* identify */ 244*7656SSherry.Moore@Sun.COM nulldev, /* probe */ 245*7656SSherry.Moore@Sun.COM schpc_attach, /* attach */ 246*7656SSherry.Moore@Sun.COM schpc_detach, /* detach */ 247*7656SSherry.Moore@Sun.COM nodev, /* reset */ 248*7656SSherry.Moore@Sun.COM &schpc_cb_ops, /* driver operations */ 249*7656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* no bus operations */ 250*7656SSherry.Moore@Sun.COM NULL, /* power */ 251*7656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 2521708Sstevel }; 2531708Sstevel 2541708Sstevel /* 2551708Sstevel * loadable module declarations: 2561708Sstevel */ 2571708Sstevel static struct modldrv modldrv = { 2581708Sstevel &mod_driverops, 259*7656SSherry.Moore@Sun.COM "PCI Hot Plug Controller Driver (schpc)", 2601708Sstevel &schpc_dev_ops, 2611708Sstevel }; 2621708Sstevel 2631708Sstevel static struct modlinkage modlinkage = { 2641708Sstevel MODREV_1, 2651708Sstevel (void *)&modldrv, 2661708Sstevel NULL 2671708Sstevel }; 2681708Sstevel 2691708Sstevel int 2701708Sstevel _init(void) 2711708Sstevel { 2721708Sstevel int ret; 2731708Sstevel int rv; 2741708Sstevel 2751708Sstevel SCHPC_DEBUG0(D_ATTACH, "_init() installing module"); 2761708Sstevel 2771708Sstevel ret = ddi_soft_state_init(&per_schpc_state, sizeof (schpc_t), 1); 2781708Sstevel if (ret != 0) { 2791708Sstevel return (ret); 2801708Sstevel } 2811708Sstevel 2821708Sstevel /* 2831708Sstevel * Initialize Outgoing Mailbox. 2841708Sstevel */ 2851708Sstevel ret = mboxsc_init(KEY_PCSC, MBOXSC_MBOX_OUT, NULL); 2861708Sstevel 2871708Sstevel if (ret != 0) { 2881708Sstevel ddi_soft_state_fini(&per_schpc_state); 2891708Sstevel return (ret); 2901708Sstevel } 2911708Sstevel 2921708Sstevel ret = mboxsc_ctrl(KEY_PCSC, MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE, 2931708Sstevel (void *) &schpc_putmsg_timeout_range); 2941708Sstevel 2951708Sstevel if (ret != 0) { 2961708Sstevel ddi_soft_state_fini(&per_schpc_state); 2971708Sstevel return (ret); 2981708Sstevel } 2991708Sstevel 3001708Sstevel if (schpc_timeout_putmsg < schpc_putmsg_timeout_range.min_timeout) { 3011708Sstevel schpc_timeout_putmsg = schpc_putmsg_timeout_range.min_timeout; 3021708Sstevel cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n", 303*7656SSherry.Moore@Sun.COM schpc_timeout_putmsg); 3041708Sstevel } 3051708Sstevel 3061708Sstevel if (schpc_timeout_putmsg > schpc_putmsg_timeout_range.max_timeout) { 3071708Sstevel schpc_timeout_putmsg = schpc_putmsg_timeout_range.max_timeout; 3081708Sstevel cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n", 309*7656SSherry.Moore@Sun.COM schpc_timeout_putmsg); 3101708Sstevel } 3111708Sstevel 3121708Sstevel /* 3131708Sstevel * Create the schpc_event_taskq for MBOXSC_MSG_EVENT processing. 3141708Sstevel */ 3151708Sstevel schpc_event_taskq = taskq_create("schpc_event_taskq", 2, 3161708Sstevel minclsyspri, 4, 4, TASKQ_PREPOPULATE); 3171708Sstevel 3181708Sstevel /* 3191708Sstevel * Initialize Incoming Mailbox. 3201708Sstevel * NOTE: the callback is null because the schpc_msg_thread will 3211708Sstevel * handle all incoming MBOXSC_MSG_EVENT and MBOXSC_MSG_REPLY 3221708Sstevel * messages. 3231708Sstevel */ 3241708Sstevel ret = mboxsc_init(KEY_SCPC, MBOXSC_MBOX_IN, NULL); 3251708Sstevel 3261708Sstevel if (ret != 0) { 3271708Sstevel cmn_err(CE_WARN, "schpc: can not initialize KEY_SCPC as " 3281708Sstevel "MBOXSC_MBOX_IN"); 3291708Sstevel ddi_soft_state_fini(&per_schpc_state); 3301708Sstevel return (ret); 3311708Sstevel } 3321708Sstevel 3331708Sstevel ret = mboxsc_ctrl(KEY_SCPC, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE, 3341708Sstevel (void *) &schpc_getmsg_timeout_range); 3351708Sstevel 3361708Sstevel if (ret != 0) { 3371708Sstevel ddi_soft_state_fini(&per_schpc_state); 3381708Sstevel return (ret); 3391708Sstevel } 3401708Sstevel 3411708Sstevel if (schpc_timeout_getmsg < schpc_getmsg_timeout_range.min_timeout) { 3421708Sstevel schpc_timeout_getmsg = schpc_getmsg_timeout_range.min_timeout; 3431708Sstevel cmn_err(CE_WARN, " schpc: resetting getmsg timeout to %ld\n", 344*7656SSherry.Moore@Sun.COM schpc_timeout_getmsg); 3451708Sstevel } 3461708Sstevel 3471708Sstevel if (schpc_timeout_getmsg > schpc_getmsg_timeout_range.max_timeout) { 3481708Sstevel schpc_timeout_getmsg = schpc_getmsg_timeout_range.max_timeout; 3491708Sstevel cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n", 350*7656SSherry.Moore@Sun.COM schpc_timeout_putmsg); 3511708Sstevel } 3521708Sstevel 3531708Sstevel if (schpc_timeout_event < schpc_getmsg_timeout_range.min_timeout) { 3541708Sstevel schpc_timeout_event = schpc_getmsg_timeout_range.min_timeout; 3551708Sstevel cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n", 356*7656SSherry.Moore@Sun.COM schpc_timeout_event); 3571708Sstevel } 3581708Sstevel 3591708Sstevel if (schpc_timeout_event > schpc_getmsg_timeout_range.max_timeout) { 3601708Sstevel schpc_timeout_event = schpc_getmsg_timeout_range.max_timeout; 3611708Sstevel cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n", 362*7656SSherry.Moore@Sun.COM schpc_timeout_event); 3631708Sstevel } 3641708Sstevel 3651708Sstevel ret = mod_install(&modlinkage); 3661708Sstevel if (ret != 0) { 3671708Sstevel if ((rv = mboxsc_fini(KEY_PCSC)) != 0) { 3681708Sstevel cmn_err(CE_WARN, "schpc: _init() - " 369*7656SSherry.Moore@Sun.COM "mboxsc_fini(KEY_PCSC) failed: 0x%x", rv); 3701708Sstevel } 3711708Sstevel if ((rv = mboxsc_fini(KEY_SCPC)) != 0) { 3721708Sstevel cmn_err(CE_WARN, "schpc: _init() - " 373*7656SSherry.Moore@Sun.COM "mboxsc_fini(KEY_SCPC) failed: 0x%x", rv); 3741708Sstevel } 3751708Sstevel taskq_destroy(schpc_event_taskq); 3761708Sstevel ddi_soft_state_fini(&per_schpc_state); 3771708Sstevel return (ret); 3781708Sstevel } 3791708Sstevel 3801708Sstevel SCHPC_DEBUG0(D_ATTACH, "_init() module installed"); 3811708Sstevel 3821708Sstevel /* 3831708Sstevel * Start the schpc_msg_thread to continuously monitor the 3841708Sstevel * MBOXSC_MBOX_IN mailbox for incoming MBOXSC_MSG_EVENTs and 3851708Sstevel * MBOXSC_MSG_REPLYs. 3861708Sstevel */ 3871708Sstevel mutex_init(&schpc_replylist_mutex, NULL, MUTEX_DRIVER, NULL); 3881708Sstevel (void) thread_create(NULL, 0, schpc_msg_thread, 389*7656SSherry.Moore@Sun.COM NULL, 0, &p0, TS_RUN, minclsyspri); 3901708Sstevel 3911708Sstevel SCHPC_DEBUG0(D_ATTACH, "_init() started schpc_msg_thread"); 3921708Sstevel 3931708Sstevel return (ret); 3941708Sstevel } 3951708Sstevel 3961708Sstevel int 3971708Sstevel _fini(void) 3981708Sstevel { 3991708Sstevel SCHPC_DEBUG0(D_ATTACH, "_fini()"); 4001708Sstevel 4011708Sstevel return (DDI_FAILURE); 4021708Sstevel } 4031708Sstevel 4041708Sstevel int 4051708Sstevel _info(struct modinfo *modinfop) 4061708Sstevel { 4071708Sstevel SCHPC_DEBUG0(D_ATTACH, "_info() called."); 4081708Sstevel 4091708Sstevel return (mod_info(&modlinkage, modinfop)); 4101708Sstevel } 4111708Sstevel 4121708Sstevel static int 4131708Sstevel schpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 4141708Sstevel { 4151708Sstevel int instance = ddi_get_instance(devi); 4161708Sstevel int rval; 4171708Sstevel 4181708Sstevel SCHPC_DEBUG1(D_ATTACH, "attach(%x) ATTACH", instance); 4191708Sstevel 4201708Sstevel switch (cmd) { 4211708Sstevel case DDI_ATTACH: 4221708Sstevel 4231708Sstevel /* 4241708Sstevel * Allocate the soft state structure for this instance. 4251708Sstevel */ 4261708Sstevel rval = ddi_soft_state_zalloc(per_schpc_state, instance); 4271708Sstevel 4281708Sstevel if (rval != DDI_SUCCESS) { 4291708Sstevel SCHPC_DEBUG1(D_ATTACH, 4301708Sstevel "schpc_attach(%x) Can not allocate " 4311708Sstevel "soft state structure", instance); 4321708Sstevel return (DDI_FAILURE); 4331708Sstevel } 4341708Sstevel 4351708Sstevel schpc_p = (schpc_t *)ddi_get_soft_state(per_schpc_state, 4361708Sstevel instance); 4371708Sstevel 4381708Sstevel if (schpc_p == NULL) { 4391708Sstevel return (DDI_FAILURE); 4401708Sstevel } 4411708Sstevel 4421708Sstevel mutex_init(&schpc_p->schpc_mutex, NULL, MUTEX_DRIVER, NULL); 4431708Sstevel cv_init(&schpc_p->schpc_cv, NULL, CV_DRIVER, NULL); 4441708Sstevel 4451708Sstevel /* 4461708Sstevel * Put schpc structure on global linked list. 4471708Sstevel */ 4481708Sstevel 4491708Sstevel /* 4501708Sstevel * Initialize starting transaction ID. 4511708Sstevel */ 4521708Sstevel schpc_p->schpc_transid = 0; 4531708Sstevel 4541708Sstevel schpc_p->schpc_number_of_slots = STARCAT_MAX_SLOTS; 4551708Sstevel 4561708Sstevel SCHPC_DEBUG2(D_ATTACH, "schpc_attach(%x) slot-table property " 4571708Sstevel "describes %d slots", instance, 4581708Sstevel schpc_p->schpc_number_of_slots); 4591708Sstevel 4601708Sstevel schpc_p->schpc_hotplugmodel = ddi_getprop(DDI_DEV_T_ANY, 4611708Sstevel devi, 0, "hot-plug-model", SCHPC_HOTPLUGTYPE_CPCIHOTPLUG); 4621708Sstevel 4631708Sstevel SCHPC_DEBUG2(D_ATTACH, "attach(%x) ATTACH - Hot Plug Model=%x", 4641708Sstevel instance, schpc_p->schpc_hotplugmodel); 4651708Sstevel 4661708Sstevel /* 4671708Sstevel * What type of hot plug do these slots support? The only 4681708Sstevel * types of slots we support is the cPCI Hot Plug Model 4691708Sstevel * and Not Hot Pluggable. 4701708Sstevel */ 4711708Sstevel if (schpc_p->schpc_hotplugmodel != 4721708Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) { 4731708Sstevel schpc_p->schpc_hotplugmodel = 4741708Sstevel SCHPC_HOTPLUGTYPE_NOTHOTPLUGGABLE; 4751708Sstevel } 4761708Sstevel 4771708Sstevel schpc_p->schpc_slot = (schpc_slot_t *)kmem_zalloc((size_t) 4781708Sstevel (schpc_p->schpc_number_of_slots * sizeof (schpc_slot_t)), 4791708Sstevel KM_SLEEP); 4801708Sstevel 4811708Sstevel schpc_p->schpc_devi = devi; 4821708Sstevel schpc_p->schpc_instance = instance; 4831708Sstevel 4841708Sstevel /* 4851708Sstevel * Start thread to search the device tree and register 4861708Sstevel * all found pci slots. 4871708Sstevel */ 4881708Sstevel (void) thread_create(NULL, 0, schpc_register_all_slots, 4891708Sstevel (void *)schpc_p, 0, &p0, TS_RUN, minclsyspri); 4901708Sstevel 4911708Sstevel break; 4921708Sstevel 4931708Sstevel case DDI_PM_RESUME: 4941708Sstevel case DDI_RESUME: 4951708Sstevel return (DDI_SUCCESS); 4961708Sstevel default: 4971708Sstevel cmn_err(CE_WARN, "schpc%d: Cmd != DDI_ATTACH/DDI_RESUME", 4981708Sstevel instance); 4991708Sstevel 5001708Sstevel return (DDI_FAILURE); 5011708Sstevel } 5021708Sstevel 5031708Sstevel SCHPC_DEBUG1(D_ATTACH, 5041708Sstevel "schpc_attach(%x) Attach - DDI_SUCCESS", instance); 5051708Sstevel 5061708Sstevel return (DDI_SUCCESS); 5071708Sstevel } 5081708Sstevel 5091708Sstevel /*ARGSUSED*/ 5101708Sstevel static int 5111708Sstevel schpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 5121708Sstevel { 5131708Sstevel int instance = ddi_get_instance(devi); 5141708Sstevel 5151708Sstevel SCHPC_DEBUG1(D_DETACH, "detach(%x) DETACH", instance); 5161708Sstevel 5171708Sstevel return (DDI_FAILURE); 5181708Sstevel } 5191708Sstevel 5201708Sstevel /*ARGSUSED*/ 5211708Sstevel static int 5221708Sstevel schpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 5231708Sstevel void **result) 5241708Sstevel { 5251708Sstevel int error; 5261708Sstevel 5271708Sstevel switch (infocmd) { 5281708Sstevel case DDI_INFO_DEVT2DEVINFO: 5291708Sstevel *result = (void *)schpc_devi; 5301708Sstevel error = DDI_SUCCESS; 5311708Sstevel break; 5321708Sstevel case DDI_INFO_DEVT2INSTANCE: 5331708Sstevel *result = (void *)0; 5341708Sstevel error = DDI_SUCCESS; 5351708Sstevel break; 5361708Sstevel default: 5371708Sstevel error = DDI_FAILURE; 5381708Sstevel } 5391708Sstevel return (error); 5401708Sstevel } 5411708Sstevel 5421708Sstevel /* 5431708Sstevel * schpc_connect() 5441708Sstevel * 5451708Sstevel * Called by Hot Plug Services to connect a slot to the bus. 5461708Sstevel */ 5471708Sstevel 5481708Sstevel /*ARGSUSED*/ 5491708Sstevel static int 5501708Sstevel schpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 5511708Sstevel { 5521708Sstevel int rval; 5531708Sstevel int expander, board; 5541708Sstevel pci_setslot_t setslot; 5551708Sstevel pci_getslot_t getslot; 5561708Sstevel int slot; 5571708Sstevel 5581708Sstevel SCHPC_DEBUG2(D_IOC_CONNECT, "schpc_connect( ops_arg=%p slot_hdl=%p)", 5591708Sstevel ops_arg, slot_hdl); 5601708Sstevel 5611708Sstevel mutex_enter(&schpc_p->schpc_mutex); 5621708Sstevel 5631708Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl); 5641708Sstevel 5651708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 5661708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect - HPC Not Inited"); 5671708Sstevel mutex_exit(&schpc_p->schpc_mutex); 5681708Sstevel return (HPC_ERR_FAILED); 5691708Sstevel } 5701708Sstevel 5711708Sstevel /* 5721708Sstevel * Check to see if the slot is already connected. 5731708Sstevel */ 5741708Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED) { 5751708Sstevel mutex_exit(&schpc_p->schpc_mutex); 5761708Sstevel return (0); 5771708Sstevel } 5781708Sstevel 5791708Sstevel /* 5801708Sstevel * Block if another thread is executing a HPC command. 5811708Sstevel */ 5821708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 5831708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 5841708Sstevel } 5851708Sstevel 5861708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 5871708Sstevel 5881708Sstevel mutex_exit(&schpc_p->schpc_mutex); 5891708Sstevel 5901708Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 5911708Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */ 5921708Sstevel 5931708Sstevel SCHPC_DEBUG3(D_IOC_CONNECT, 5941708Sstevel "schpc_connect Expander=%x Board=%x Slot=%x", 5951708Sstevel expander, board, SCHPC_SLOT_NUM(slot)); 5961708Sstevel 5971708Sstevel 5981708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_OCC_GOOD)) { 5991708Sstevel cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete " 6001708Sstevel "connection on Expander %d Board %d Slot %d - " 6011708Sstevel "Ap_Id=%s : Occupant is in failed state", 6021708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 6031708Sstevel schpc_p->schpc_slot[slot].ap_id); 6041708Sstevel 6051708Sstevel /* Fault LED should already be illuminated */ 6061708Sstevel 6071708Sstevel goto failed; 6081708Sstevel } 6091708Sstevel 6101708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD)) { 6111708Sstevel cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete " 6121708Sstevel "connection on Expander %d Board %d Slot %d - " 6131708Sstevel "Ap_Id=%s : Receptacle is in failed state", 6141708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 6151708Sstevel schpc_p->schpc_slot[slot].ap_id); 6161708Sstevel 6171708Sstevel /* Fault LED should already be illuminated */ 6181708Sstevel 6191708Sstevel goto failed; 6201708Sstevel } 6211708Sstevel 6221708Sstevel rval = schpc_getslotstatus(expander, board, slot, &getslot); 6231708Sstevel 6241708Sstevel if (rval) { 6251708Sstevel /* 6261708Sstevel * System Controller/Mailbox failure. 6271708Sstevel */ 6281708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 6291708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 6301708Sstevel "Communicate with System Controller", expander, board, 6311708Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 6321708Sstevel 6331708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 6341708Sstevel 6351708Sstevel goto failed; 6361708Sstevel } 6371708Sstevel 6381708Sstevel if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) { 6391708Sstevel 6401708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 6411708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 6421708Sstevel "Read Slot Status", expander, board, 6431708Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 6441708Sstevel 6451708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 6461708Sstevel 6471708Sstevel goto failed; 6481708Sstevel } 6491708Sstevel 6501708Sstevel if (getslot.slot_empty) { 6511708Sstevel /* 6521708Sstevel * If the slot is empty - fail the connection request. 6531708Sstevel */ 6541708Sstevel goto failed; 6551708Sstevel } 6561708Sstevel 6571708Sstevel SCHPC_DEBUG3(D_FREQCHG, "Slot %d - slot_freq_setting %d " 6581708Sstevel "slot_freq_cap %d", slot, getslot.slot_freq_setting, 6591708Sstevel getslot.slot_freq_cap); 6601708Sstevel 6611708Sstevel if (!schpc_is_freq_switchable(slot) && 6621708Sstevel (getslot.slot_freq_setting > getslot.slot_freq_cap)) { 6631708Sstevel 6641708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 6651708Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 6661708Sstevel "Bus Speed Mismatch", expander, 6671708Sstevel board, SCHPC_SLOT_NUM(slot), 6681708Sstevel schpc_p->schpc_slot[slot].ap_id); 6691708Sstevel 6701708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 6711708Sstevel 6721708Sstevel goto failed; 6731708Sstevel } 6741708Sstevel 6751708Sstevel if (schpc_is_leaf_reset_required(slot) && 6761708Sstevel (schpc_p->schpc_slot[slot].saved_regs == NULL)) { 6771708Sstevel 6781708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Save Regs before connect", 6791708Sstevel slot); 6801708Sstevel 6811708Sstevel /* 6821708Sstevel * A prior disconnect had not saved off the leaf so lets 6831708Sstevel * save it now. This is probably due to the domain being 6841708Sstevel * booted with a slot with no cassette. 6851708Sstevel */ 6861708Sstevel if (schpc_save_leaf(slot) != 0) { 6871708Sstevel cmn_err(CE_WARN, "schpc - Unable to save leaf regs on " 6881708Sstevel 6891708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ", 6901708Sstevel expander, board, slot & 3, 6911708Sstevel schpc_p->schpc_slot[slot].ap_id); 6921708Sstevel 6931708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 6941708Sstevel 6951708Sstevel goto failed; 6961708Sstevel } 6971708Sstevel } 6981708Sstevel 6991708Sstevel /* 7001708Sstevel * Initialize Set Slot Command. 7011708Sstevel */ 7021708Sstevel schpc_init_setslot_message(&setslot); 7031708Sstevel 7041708Sstevel setslot.slot_power_on = PCIMSG_ON; /* Turn slot power on */ 7051708Sstevel 7061708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash Fault LED */ 7071708Sstevel 7081708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot); 7091708Sstevel 7101708Sstevel if (rval != 0) { 7111708Sstevel /* 7121708Sstevel * System Controller/Mailbox failure. 7131708Sstevel */ 7141708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 7151708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 7161708Sstevel "Communicate with System Controller", expander, board, 7171708Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 7181708Sstevel 7191708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 7201708Sstevel 7211708Sstevel goto failed; 7221708Sstevel } 7231708Sstevel 7241708Sstevel if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) { 7251708Sstevel 7261708Sstevel /* 7271708Sstevel * The Request was successfully completed. 7281708Sstevel */ 7291708Sstevel 7301708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect() - setslotstatus " 7311708Sstevel "succeeded"); 7321708Sstevel 7331708Sstevel /* 7341708Sstevel * Need to check HEALTHY# signal. 7351708Sstevel */ 7361708Sstevel rval = schpc_getslotstatus(expander, board, slot, &getslot); 7371708Sstevel 7381708Sstevel if (rval) { 7391708Sstevel /* 7401708Sstevel * System Controller/Mailbox failure. 7411708Sstevel */ 7421708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 7431708Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 7441708Sstevel "Unable to Communicate with System Controller", 7451708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 7461708Sstevel schpc_p->schpc_slot[slot].ap_id); 7471708Sstevel 7481708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 7491708Sstevel 7501708Sstevel goto failed; 7511708Sstevel } 7521708Sstevel 7531708Sstevel if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) { 7541708Sstevel 7551708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 7561708Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 7571708Sstevel "Unable to Read Slot Status", expander, board, 7581708Sstevel SCHPC_SLOT_NUM(slot), 7591708Sstevel schpc_p->schpc_slot[slot].ap_id); 7601708Sstevel 7611708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 7621708Sstevel 7631708Sstevel goto failed; 7641708Sstevel } 7651708Sstevel 7661708Sstevel if ((getslot.slot_powergood != PCIMSG_ON) || 7671708Sstevel (getslot.slot_powerfault == PCIMSG_ON)) { 7681708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 7691708Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 7701708Sstevel "Power failure detected", expander, board, 7711708Sstevel SCHPC_SLOT_NUM(slot), 7721708Sstevel schpc_p->schpc_slot[slot].ap_id); 7731708Sstevel 7741708Sstevel /* 7751708Sstevel * Initialize Set Slot Command. 7761708Sstevel */ 7771708Sstevel schpc_init_setslot_message(&setslot); 7781708Sstevel 7791708Sstevel /* 7801708Sstevel * Turn slot power off. 7811708Sstevel */ 7821708Sstevel setslot.slot_power_off = PCIMSG_ON; 7831708Sstevel 7841708Sstevel (void) schpc_setslotstatus(expander, board, 7851708Sstevel slot, &setslot); 7861708Sstevel 7871708Sstevel schpc_setslotled(expander, board, slot, 7881708Sstevel (SERVICE_LED_ON | FAULT_LED_ON)); 7891708Sstevel 7901708Sstevel goto failed; 7911708Sstevel } 7921708Sstevel 7931708Sstevel if (!getslot.slot_HEALTHY) { 7941708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 7951708Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 7961708Sstevel "Adapter did not assert HEALTHY#", expander, board, 7971708Sstevel SCHPC_SLOT_NUM(slot), 7981708Sstevel schpc_p->schpc_slot[slot].ap_id); 7991708Sstevel 8001708Sstevel /* 8011708Sstevel * Initialize Set Slot Command. 8021708Sstevel */ 8031708Sstevel schpc_init_setslot_message(&setslot); 8041708Sstevel 8051708Sstevel /* 8061708Sstevel * Turn slot power off. 8071708Sstevel */ 8081708Sstevel setslot.slot_power_off = PCIMSG_ON; 8091708Sstevel 8101708Sstevel (void) schpc_setslotstatus(expander, board, slot, 8111708Sstevel &setslot); 8121708Sstevel 8131708Sstevel schpc_setslotled(expander, board, slot, 8141708Sstevel (SERVICE_LED_ON | FAULT_LED_ON)); 8151708Sstevel 8161708Sstevel goto failed; 8171708Sstevel } 8181708Sstevel 8191708Sstevel /* 8201708Sstevel * Initialize Set Slot Command. 8211708Sstevel */ 8221708Sstevel schpc_init_setslot_message(&setslot); 8231708Sstevel 8241708Sstevel /* 8251708Sstevel * Start monitoring ENUM# and HEALTHY# 8261708Sstevel */ 8271708Sstevel setslot.slot_enable_HEALTHY = PCIMSG_ON; 8281708Sstevel setslot.slot_enable_ENUM = PCIMSG_ON; 8291708Sstevel 8301708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot); 8311708Sstevel 8321708Sstevel if (rval != 0) { 8331708Sstevel /* 8341708Sstevel * System Controller/Mailbox failure. 8351708Sstevel */ 8361708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 8371708Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 8381708Sstevel "Unable to Communicate with System Controller", 8391708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 8401708Sstevel schpc_p->schpc_slot[slot].ap_id); 8411708Sstevel 8421708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 8431708Sstevel 8441708Sstevel goto failed; 8451708Sstevel } 8461708Sstevel if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) { 8471708Sstevel 8481708Sstevel int freq; 8491708Sstevel find_dev_t find_dev; 8501708Sstevel 8511708Sstevel /* 8521708Sstevel * The Request was successfully completed. 8531708Sstevel */ 8541708Sstevel 8551708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, 8561708Sstevel "schpc_connect() - setslotstatus succeeded"); 8571708Sstevel 8581708Sstevel schpc_p->schpc_slot[slot].state |= 8591708Sstevel SCHPC_SLOTSTATE_CONNECTED; 8601708Sstevel 8611708Sstevel schpc_setslotled(expander, board, slot, 8621708Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_OFF)); 8631708Sstevel 8641708Sstevel find_dev.cname = schpc_p->schpc_slot[slot].nexus_path; 8651708Sstevel find_dev.caddr = (char *)kmem_alloc(MAXPATHLEN, 866*7656SSherry.Moore@Sun.COM KM_SLEEP); 8671708Sstevel find_dev.dip = NULL; 8681708Sstevel 8691708Sstevel /* root node doesn't have to be held */ 8701708Sstevel ddi_walk_devs(ddi_root_node(), schpc_find_dip, 8711708Sstevel &find_dev); 8721708Sstevel if (find_dev.dip != NULL) { 8731708Sstevel /* 8741708Sstevel * Update the clock-frequency property to 8751708Sstevel * reflect the new slot-frequency. 8761708Sstevel */ 8771708Sstevel freq = schpc_slot_freq(&getslot); 8781708Sstevel SCHPC_DEBUG2(D_FREQCHG, 8791708Sstevel "schpc_connect: updating dip=%p freq=%dHZ", 8801708Sstevel find_dev.dip, freq); 8811708Sstevel if (ndi_prop_update_int(DDI_DEV_T_NONE, 8821708Sstevel find_dev.dip, "clock-frequency", freq) 8831708Sstevel != DDI_SUCCESS) { 8841708Sstevel cmn_err(CE_WARN, 8851708Sstevel "schpc: - failed to update " 8861708Sstevel "clock-frequency property for %s", 8871708Sstevel find_dev.cname); 8881708Sstevel } 8891708Sstevel ndi_rele_devi(find_dev.dip); 8901708Sstevel } else { 8911708Sstevel cmn_err(CE_WARN, 8921708Sstevel "schpc: couldn't find dip for %s ", 8931708Sstevel find_dev.cname); 8941708Sstevel } 8951708Sstevel kmem_free(find_dev.caddr, MAXPATHLEN); 8961708Sstevel 8971708Sstevel mutex_enter(&schpc_p->schpc_mutex); 8981708Sstevel schpc_p->schpc_slot[slot].state &= 8991708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 9001708Sstevel 9011708Sstevel /* 9021708Sstevel * If leaf registers were saved off, then they 9031708Sstevel * need to be restored. 9041708Sstevel */ 9051708Sstevel schpc_restore_leaf(slot); 9061708Sstevel 9071708Sstevel /* 9081708Sstevel * Since the device saw a PCI Reset, we need to 9091708Sstevel * wait 2^25 clock cycles before the first 9101708Sstevel * Configuration access. The worst case is 33MHz, 9111708Sstevel * which is a 1 second wait. 9121708Sstevel */ 9131708Sstevel drv_usecwait(1000000); 9141708Sstevel 9151708Sstevel cv_signal(&schpc_p->schpc_cv); 9161708Sstevel mutex_exit(&schpc_p->schpc_mutex); 9171708Sstevel 9181708Sstevel return (0); 9191708Sstevel } else { 9201708Sstevel /* 9211708Sstevel * The System Controller Rejected the 9221708Sstevel * connection request. 9231708Sstevel */ 9241708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 9251708Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s :" 9261708Sstevel "System Controller failed connection request", 9271708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 9281708Sstevel schpc_p->schpc_slot[slot].ap_id); 9291708Sstevel 9301708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 9311708Sstevel 9321708Sstevel goto failed; 9331708Sstevel } 9341708Sstevel } 9351708Sstevel 9361708Sstevel /* 9371708Sstevel * The System Controller Rejected the connection request. 9381708Sstevel */ 9391708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 9401708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller " 9411708Sstevel "failed connection request", expander, board, SCHPC_SLOT_NUM(slot), 9421708Sstevel schpc_p->schpc_slot[slot].ap_id); 9431708Sstevel 9441708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 9451708Sstevel 9461708Sstevel failed: 9471708Sstevel mutex_enter(&schpc_p->schpc_mutex); 9481708Sstevel schpc_p->schpc_slot[slot].state &= 9491708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 9501708Sstevel cv_signal(&schpc_p->schpc_cv); 9511708Sstevel mutex_exit(&schpc_p->schpc_mutex); 9521708Sstevel 9531708Sstevel return (HPC_ERR_FAILED); 9541708Sstevel } 9551708Sstevel 9561708Sstevel /* 9571708Sstevel * schpc_disconnect() 9581708Sstevel * 9591708Sstevel * Called by Hot Plug Services to disconnect a slot to the bus. 9601708Sstevel */ 9611708Sstevel 9621708Sstevel /*ARGSUSED*/ 9631708Sstevel static int 9641708Sstevel schpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, 9651708Sstevel uint_t flags) 9661708Sstevel { 9671708Sstevel int rval; 9681708Sstevel int expander, board, slot; 9691708Sstevel pci_setslot_t setslot; 9701708Sstevel 9711708Sstevel SCHPC_DEBUG2(D_IOC_CONNECT, 9721708Sstevel "schpc_disconnect( ops_arg=%p slot_hdl=%p)", ops_arg, slot_hdl); 9731708Sstevel 9741708Sstevel mutex_enter(&schpc_p->schpc_mutex); 9751708Sstevel 9761708Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl); 9771708Sstevel 9781708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 9791708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, 9801708Sstevel "schpc_disconnect - HPC Not Inited"); 9811708Sstevel mutex_exit(&schpc_p->schpc_mutex); 9821708Sstevel return (HPC_ERR_FAILED); 9831708Sstevel } 9841708Sstevel 9851708Sstevel /* 9861708Sstevel * Check to see if we are already disconnected. 9871708Sstevel */ 9881708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) { 9891708Sstevel mutex_exit(&schpc_p->schpc_mutex); 9901708Sstevel return (0); 9911708Sstevel } 9921708Sstevel 9931708Sstevel /* 9941708Sstevel * Block if another thread is executing a HPC command. 9951708Sstevel */ 9961708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 9971708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 9981708Sstevel } 9991708Sstevel 10001708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 10011708Sstevel 10021708Sstevel mutex_exit(&schpc_p->schpc_mutex); 10031708Sstevel 10041708Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 10051708Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */ 10061708Sstevel 10071708Sstevel /* 10081708Sstevel * If a leaf reset is going to be asserted due to a mode/freq. 10091708Sstevel * change, then the leaf registers of the XMITS bridge will need 10101708Sstevel * to be saved off prior to the connect. 10111708Sstevel */ 10121708Sstevel if (schpc_is_leaf_reset_required(slot)) { 10131708Sstevel if (schpc_save_leaf(slot) != 0) { 10141708Sstevel 10151708Sstevel cmn_err(CE_WARN, "schpc - Unable to save leaf regs on " 10161708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ", 10171708Sstevel expander, board, slot & 3, 10181708Sstevel schpc_p->schpc_slot[slot].ap_id); 10191708Sstevel 10201708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 10211708Sstevel 10221708Sstevel goto failed; 10231708Sstevel } 10241708Sstevel } 10251708Sstevel 10261708Sstevel /* 10271708Sstevel * Initialize Set Slot Command. 10281708Sstevel */ 10291708Sstevel schpc_init_setslot_message(&setslot); 10301708Sstevel 10311708Sstevel setslot.slot_power_off = PCIMSG_ON; /* Turn Power Off */ 10321708Sstevel 10331708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */ 10341708Sstevel 10351708Sstevel setslot.slot_disable_ENUM = PCIMSG_ON; /* Mask the ENUM# signal */ 10361708Sstevel setslot.slot_disable_HEALTHY = PCIMSG_ON; /* Mask the HEALTHY# sig */ 10371708Sstevel 10381708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot); 10391708Sstevel 10401708Sstevel SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - " 10411708Sstevel "setslotstatus returned 0x%x", rval); 10421708Sstevel 10431708Sstevel if (rval != 0) { 10441708Sstevel /* 10451708Sstevel * System Controller/Mailbox failure. 10461708Sstevel */ 10471708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on " 10481708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 10491708Sstevel "Communicate with System Controller", expander, board, 10501708Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 10511708Sstevel 10521708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 10531708Sstevel 10541708Sstevel goto failed; 10551708Sstevel } 10561708Sstevel 10571708Sstevel SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - " 10581708Sstevel "slot_replystatus returned 0x%x", setslot.slot_replystatus); 10591708Sstevel 10601708Sstevel if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) { 10611708Sstevel 10621708Sstevel /* 10631708Sstevel * The Request was successfully completed. 10641708Sstevel */ 10651708Sstevel schpc_p->schpc_slot[slot].state &= 10661708Sstevel ~SCHPC_SLOTSTATE_CONNECTED; 10671708Sstevel 10681708Sstevel schpc_setslotled(expander, board, slot, 10691708Sstevel (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF)); 10701708Sstevel 10711708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, 10721708Sstevel "schpc_disconnect() - setslotstatus succeeded"); 10731708Sstevel 10741708Sstevel mutex_enter(&schpc_p->schpc_mutex); 10751708Sstevel schpc_p->schpc_slot[slot].state &= 10761708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 10771708Sstevel cv_signal(&schpc_p->schpc_cv); 10781708Sstevel mutex_exit(&schpc_p->schpc_mutex); 10791708Sstevel 10801708Sstevel return (0); 10811708Sstevel } 10821708Sstevel /* 10831708Sstevel * System Controller/Mailbox failure. 10841708Sstevel */ 10851708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on " 10861708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller " 10871708Sstevel "failed disconnection request", expander, board, 10881708Sstevel SCHPC_SLOT_NUM(slot), 10891708Sstevel schpc_p->schpc_slot[slot].ap_id); 10901708Sstevel 10911708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 10921708Sstevel 10931708Sstevel failed: 10941708Sstevel schpc_restore_leaf(slot); 10951708Sstevel mutex_enter(&schpc_p->schpc_mutex); 10961708Sstevel schpc_p->schpc_slot[slot].state &= 10971708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 10981708Sstevel cv_signal(&schpc_p->schpc_cv); 10991708Sstevel mutex_exit(&schpc_p->schpc_mutex); 11001708Sstevel 11011708Sstevel return (HPC_ERR_FAILED); 11021708Sstevel } 11031708Sstevel 11041708Sstevel /* 11051708Sstevel * schpc_cpci_control 11061708Sstevel * 11071708Sstevel * Called by Hot Plug Services to perform a attachment point specific 11081708Sstevel * on a Hot Pluggable Compact PCI Slot. 11091708Sstevel */ 11101708Sstevel /*ARGSUSED*/ 11111708Sstevel static int 11121708Sstevel schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 11131708Sstevel caddr_t arg) 11141708Sstevel { 11151708Sstevel int rval; 11161708Sstevel int expander, board, slot; 11171708Sstevel pci_setslot_t setslot; 11181708Sstevel pci_getslot_t slotstatus; 11191708Sstevel hpc_led_info_t *hpc_led_info; 11201708Sstevel 11211708Sstevel SCHPC_DEBUG3(D_IOC_CONTROL, 11221708Sstevel "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)", 11231708Sstevel ops_arg, slot_hdl, request); 11241708Sstevel 11251708Sstevel mutex_enter(&schpc_p->schpc_mutex); 11261708Sstevel 11271708Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl); 11281708Sstevel 11291708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 11301708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, 11311708Sstevel "schpc_disconnect - HPC Not Inited"); 11321708Sstevel mutex_exit(&schpc_p->schpc_mutex); 11331708Sstevel return (HPC_ERR_FAILED); 11341708Sstevel } 11351708Sstevel 11361708Sstevel /* 11371708Sstevel * Block if another thread is executing a HPC command. 11381708Sstevel */ 11391708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 11401708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 11411708Sstevel } 11421708Sstevel 11431708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 11441708Sstevel 11451708Sstevel mutex_exit(&schpc_p->schpc_mutex); 11461708Sstevel 11471708Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 11481708Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */ 11491708Sstevel 11501708Sstevel /* 11511708Sstevel * Initialize Set Slot Command. 11521708Sstevel */ 11531708Sstevel schpc_init_setslot_message(&setslot); 11541708Sstevel 11551708Sstevel /* 11561708Sstevel * Initialize LED to last know state. 11571708Sstevel */ 11581708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) { 11591708Sstevel case LED_ON: 11601708Sstevel setslot.slot_led_power = PCIMSG_LED_ON; 11611708Sstevel break; 11621708Sstevel case LED_OFF: 11631708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF; 11641708Sstevel break; 11651708Sstevel case LED_FLASH: 11661708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH; 11671708Sstevel break; 11681708Sstevel } 11691708Sstevel 11701708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) { 11711708Sstevel case LED_ON: 11721708Sstevel setslot.slot_led_service = PCIMSG_LED_ON; 11731708Sstevel break; 11741708Sstevel case LED_OFF: 11751708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF; 11761708Sstevel break; 11771708Sstevel case LED_FLASH: 11781708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH; 11791708Sstevel break; 11801708Sstevel } 11811708Sstevel 11821708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) { 11831708Sstevel case LED_ON: 11841708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON; 11851708Sstevel break; 11861708Sstevel case LED_OFF: 11871708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 11881708Sstevel break; 11891708Sstevel case LED_FLASH: 11901708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 11911708Sstevel break; 11921708Sstevel } 11931708Sstevel 11941708Sstevel switch (request) { 11951708Sstevel 11961708Sstevel case HPC_CTRL_GET_LED_STATE: 11971708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 11981708Sstevel "HPC_CTRL_GET_LED_STATE"); 11991708Sstevel hpc_led_info = (hpc_led_info_t *)arg; 12001708Sstevel 12011708Sstevel switch (hpc_led_info->led) { 12021708Sstevel case HPC_FAULT_LED: 12031708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) { 12041708Sstevel case LED_OFF: 12051708Sstevel hpc_led_info->state = HPC_LED_OFF; 12061708Sstevel break; 12071708Sstevel case LED_ON: 12081708Sstevel hpc_led_info->state = HPC_LED_ON; 12091708Sstevel break; 12101708Sstevel case LED_FLASH: 12111708Sstevel hpc_led_info->state = HPC_LED_BLINK; 12121708Sstevel break; 12131708Sstevel } 12141708Sstevel break; 12151708Sstevel 12161708Sstevel case HPC_POWER_LED: 12171708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) { 12181708Sstevel case LED_OFF: 12191708Sstevel hpc_led_info->state = HPC_LED_OFF; 12201708Sstevel break; 12211708Sstevel case LED_ON: 12221708Sstevel hpc_led_info->state = HPC_LED_ON; 12231708Sstevel break; 12241708Sstevel case LED_FLASH: 12251708Sstevel hpc_led_info->state = HPC_LED_BLINK; 12261708Sstevel break; 12271708Sstevel } 12281708Sstevel break; 12291708Sstevel case HPC_ATTN_LED: 12301708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) { 12311708Sstevel case LED_OFF: 12321708Sstevel hpc_led_info->state = HPC_LED_OFF; 12331708Sstevel break; 12341708Sstevel case LED_ON: 12351708Sstevel hpc_led_info->state = HPC_LED_OFF; 12361708Sstevel break; 12371708Sstevel case LED_FLASH: 12381708Sstevel hpc_led_info->state = HPC_LED_ON; 12391708Sstevel break; 12401708Sstevel } 12411708Sstevel break; 12421708Sstevel case HPC_ACTIVE_LED: 12431708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) { 12441708Sstevel case LED_OFF: 12451708Sstevel hpc_led_info->state = HPC_LED_OFF; 12461708Sstevel break; 12471708Sstevel case LED_ON: 12481708Sstevel hpc_led_info->state = HPC_LED_ON; 12491708Sstevel break; 12501708Sstevel case LED_FLASH: 12511708Sstevel hpc_led_info->state = HPC_LED_BLINK; 12521708Sstevel break; 12531708Sstevel } 12541708Sstevel break; 12551708Sstevel default: 12561708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 12571708Sstevel "Invalid LED %x", hpc_led_info->led); 12581708Sstevel 12591708Sstevel mutex_enter(&schpc_p->schpc_mutex); 12601708Sstevel schpc_p->schpc_slot[slot].state &= 12611708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 12621708Sstevel cv_signal(&schpc_p->schpc_cv); 12631708Sstevel mutex_exit(&schpc_p->schpc_mutex); 12641708Sstevel 12651708Sstevel return (HPC_ERR_FAILED); 12661708Sstevel } 12671708Sstevel 12681708Sstevel mutex_enter(&schpc_p->schpc_mutex); 12691708Sstevel schpc_p->schpc_slot[slot].state &= 12701708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 12711708Sstevel cv_signal(&schpc_p->schpc_cv); 12721708Sstevel mutex_exit(&schpc_p->schpc_mutex); 12731708Sstevel 12741708Sstevel return (0); 12751708Sstevel 12761708Sstevel case HPC_CTRL_SET_LED_STATE: 12771708Sstevel hpc_led_info = (hpc_led_info_t *)arg; 12781708Sstevel 12791708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 12801708Sstevel "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", hpc_led_info); 12811708Sstevel 12821708Sstevel switch (hpc_led_info->led) { 12831708Sstevel case HPC_FAULT_LED: 12841708Sstevel switch (hpc_led_info->state) { 12851708Sstevel case HPC_LED_OFF: 12861708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 12871708Sstevel LED_OFF; 12881708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 12891708Sstevel break; 12901708Sstevel case HPC_LED_ON: 12911708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 12921708Sstevel LED_ON; 12931708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON; 12941708Sstevel break; 12951708Sstevel case HPC_LED_BLINK: 12961708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 12971708Sstevel LED_FLASH; 12981708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 12991708Sstevel break; 13001708Sstevel } 13011708Sstevel break; 13021708Sstevel case HPC_POWER_LED: 13031708Sstevel switch (hpc_led_info->state) { 13041708Sstevel case HPC_LED_OFF: 13051708Sstevel schpc_p->schpc_slot[slot].led.led_power = 13061708Sstevel LED_OFF; 13071708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF; 13081708Sstevel break; 13091708Sstevel case HPC_LED_ON: 13101708Sstevel schpc_p->schpc_slot[slot].led.led_power = 13111708Sstevel LED_ON; 13121708Sstevel setslot.slot_led_power = PCIMSG_LED_ON; 13131708Sstevel break; 13141708Sstevel case HPC_LED_BLINK: 13151708Sstevel schpc_p->schpc_slot[slot].led.led_power = 13161708Sstevel LED_FLASH; 13171708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH; 13181708Sstevel break; 13191708Sstevel } 13201708Sstevel break; 13211708Sstevel case HPC_ATTN_LED: 13221708Sstevel switch (hpc_led_info->state) { 13231708Sstevel case HPC_LED_OFF: 13241708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 13251708Sstevel LED_OFF; 13261708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 13271708Sstevel break; 13281708Sstevel case HPC_LED_ON: 13291708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 13301708Sstevel LED_FLASH; 13311708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 13321708Sstevel break; 13331708Sstevel case HPC_LED_BLINK: 13341708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 13351708Sstevel LED_FLASH; 13361708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 13371708Sstevel break; 13381708Sstevel } 13391708Sstevel break; 13401708Sstevel case HPC_ACTIVE_LED: 13411708Sstevel switch (hpc_led_info->state) { 13421708Sstevel case HPC_LED_OFF: 13431708Sstevel schpc_p->schpc_slot[slot].led.led_service = 13441708Sstevel LED_OFF; 13451708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF; 13461708Sstevel break; 13471708Sstevel case HPC_LED_ON: 13481708Sstevel schpc_p->schpc_slot[slot].led.led_service = 13491708Sstevel LED_ON; 13501708Sstevel setslot.slot_led_service = PCIMSG_LED_ON; 13511708Sstevel break; 13521708Sstevel case HPC_LED_BLINK: 13531708Sstevel schpc_p->schpc_slot[slot].led.led_service = 13541708Sstevel LED_FLASH; 13551708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH; 13561708Sstevel break; 13571708Sstevel } 13581708Sstevel break; 13591708Sstevel default: 13601708Sstevel mutex_enter(&schpc_p->schpc_mutex); 13611708Sstevel schpc_p->schpc_slot[slot].state &= 13621708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 13631708Sstevel cv_signal(&schpc_p->schpc_cv); 13641708Sstevel mutex_exit(&schpc_p->schpc_mutex); 13651708Sstevel 13661708Sstevel return (0); 13671708Sstevel } 13681708Sstevel 13691708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot); 13701708Sstevel 13711708Sstevel mutex_enter(&schpc_p->schpc_mutex); 13721708Sstevel schpc_p->schpc_slot[slot].state &= 13731708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 13741708Sstevel cv_signal(&schpc_p->schpc_cv); 13751708Sstevel mutex_exit(&schpc_p->schpc_mutex); 13761708Sstevel 13771708Sstevel return (0); 13781708Sstevel 13791708Sstevel case HPC_CTRL_GET_SLOT_STATE: { 13801708Sstevel hpc_slot_state_t *hpc_slot_state; 13811708Sstevel 13821708Sstevel hpc_slot_state = (hpc_slot_state_t *)arg; 13831708Sstevel 13841708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 13851708Sstevel "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p", 13861708Sstevel hpc_slot_state); 13871708Sstevel 13881708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 13891708Sstevel 13901708Sstevel if (!rval) { 13911708Sstevel 13921708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 13931708Sstevel return (HPC_ERR_FAILED); 13941708Sstevel } 13951708Sstevel 13961708Sstevel if (slotstatus.slot_empty == PCIMSG_ON) { 13971708Sstevel *hpc_slot_state = HPC_SLOT_EMPTY; 13981708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty"); 13991708Sstevel } else if (slotstatus.slot_power_on == PCIMSG_ON) { 14001708Sstevel *hpc_slot_state = HPC_SLOT_CONNECTED; 14011708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected"); 14021708Sstevel schpc_p->schpc_slot[slot].state |= 14031708Sstevel SCHPC_SLOTSTATE_CONNECTED; 14041708Sstevel } else { 14051708Sstevel *hpc_slot_state = HPC_SLOT_DISCONNECTED; 14061708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, 14071708Sstevel "Slot Disconnected"); 14081708Sstevel schpc_p->schpc_slot[slot].state &= 14091708Sstevel ~SCHPC_SLOTSTATE_CONNECTED; 14101708Sstevel } 14111708Sstevel } else { 14121708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed"); 14131708Sstevel 14141708Sstevel mutex_enter(&schpc_p->schpc_mutex); 14151708Sstevel schpc_p->schpc_slot[slot].state &= 14161708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 14171708Sstevel cv_signal(&schpc_p->schpc_cv); 14181708Sstevel mutex_exit(&schpc_p->schpc_mutex); 14191708Sstevel 14201708Sstevel return (HPC_ERR_FAILED); 14211708Sstevel } 14221708Sstevel 14231708Sstevel mutex_enter(&schpc_p->schpc_mutex); 14241708Sstevel schpc_p->schpc_slot[slot].state &= 14251708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 14261708Sstevel cv_signal(&schpc_p->schpc_cv); 14271708Sstevel mutex_exit(&schpc_p->schpc_mutex); 14281708Sstevel 14291708Sstevel return (0); 14301708Sstevel } 14311708Sstevel case HPC_CTRL_GET_BOARD_TYPE: { 14321708Sstevel hpc_board_type_t *hpc_board_type; 14331708Sstevel 14341708Sstevel hpc_board_type = (hpc_board_type_t *)arg; 14351708Sstevel 14361708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 14371708Sstevel "HPC_CTRL_GET_BOARD_TYPE"); 14381708Sstevel 14391708Sstevel /* 14401708Sstevel * The HPC driver does not know what board type 14411708Sstevel * is plugged in. 14421708Sstevel */ 14431708Sstevel *hpc_board_type = HPC_BOARD_CPCI_HS; 14441708Sstevel 14451708Sstevel mutex_enter(&schpc_p->schpc_mutex); 14461708Sstevel schpc_p->schpc_slot[slot].state &= 14471708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 14481708Sstevel cv_signal(&schpc_p->schpc_cv); 14491708Sstevel mutex_exit(&schpc_p->schpc_mutex); 14501708Sstevel 14511708Sstevel return (0); 14521708Sstevel 14531708Sstevel } 14541708Sstevel case HPC_CTRL_DEV_CONFIGURED: 14551708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 14561708Sstevel "HPC_CTRL_DEV_CONFIGURED"); 14571708Sstevel 14581708Sstevel mutex_enter(&schpc_p->schpc_mutex); 14591708Sstevel schpc_p->schpc_slot[slot].state &= 14601708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 14611708Sstevel cv_signal(&schpc_p->schpc_cv); 14621708Sstevel mutex_exit(&schpc_p->schpc_mutex); 14631708Sstevel 14641708Sstevel return (0); 14651708Sstevel 14661708Sstevel case HPC_CTRL_DEV_UNCONFIGURED: 14671708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 14681708Sstevel "HPC_CTRL_DEV_UNCONFIGURED"); 14691708Sstevel 14701708Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) { 14711708Sstevel /* 14721708Sstevel * When the occupant is unconfigured, power 14731708Sstevel * down the slot. 14741708Sstevel */ 14751708Sstevel rval = schpc_disconnect((caddr_t)schpc_p, 14761708Sstevel schpc_p->schpc_slot[slot].slot_handle, 14771708Sstevel 0, 0); 14781708Sstevel 14791708Sstevel schpc_p->schpc_slot[slot].state &= 14801708Sstevel ~SCHPC_SLOTSTATE_ENUM; 14811708Sstevel } 14821708Sstevel 14831708Sstevel mutex_enter(&schpc_p->schpc_mutex); 14841708Sstevel schpc_p->schpc_slot[slot].state &= 14851708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 14861708Sstevel cv_signal(&schpc_p->schpc_cv); 14871708Sstevel mutex_exit(&schpc_p->schpc_mutex); 14881708Sstevel 14891708Sstevel return (0); 14901708Sstevel 14911708Sstevel case HPC_CTRL_ENABLE_AUTOCFG: 14921708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 14931708Sstevel "HPC_CTRL_ENABLE_AUTOCFG"); 14941708Sstevel 14951708Sstevel schpc_p->schpc_slot[slot].state |= 14961708Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 14971708Sstevel 14981708Sstevel mutex_enter(&schpc_p->schpc_mutex); 14991708Sstevel schpc_p->schpc_slot[slot].state &= 15001708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 15011708Sstevel cv_signal(&schpc_p->schpc_cv); 15021708Sstevel mutex_exit(&schpc_p->schpc_mutex); 15031708Sstevel 15041708Sstevel return (0); 15051708Sstevel 15061708Sstevel case HPC_CTRL_DISABLE_AUTOCFG: 15071708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 15081708Sstevel "HPC_CTRL_DISABLE_AUTOCFG"); 15091708Sstevel schpc_p->schpc_slot[slot].state &= 15101708Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 15111708Sstevel 15121708Sstevel mutex_enter(&schpc_p->schpc_mutex); 15131708Sstevel schpc_p->schpc_slot[slot].state &= 15141708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 15151708Sstevel cv_signal(&schpc_p->schpc_cv); 15161708Sstevel mutex_exit(&schpc_p->schpc_mutex); 15171708Sstevel 15181708Sstevel return (0); 15191708Sstevel 15201708Sstevel case HPC_CTRL_DISABLE_ENUM: 15211708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 15221708Sstevel "HPC_CTRL_DISABLE_ENUM"); 15231708Sstevel 15241708Sstevel setslot.slot_disable_ENUM = PCIMSG_ON; 15251708Sstevel 15261708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot); 15271708Sstevel 15281708Sstevel if (rval) 15291708Sstevel rval = HPC_ERR_FAILED; 15301708Sstevel 15311708Sstevel mutex_enter(&schpc_p->schpc_mutex); 15321708Sstevel schpc_p->schpc_slot[slot].state &= 15331708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 15341708Sstevel cv_signal(&schpc_p->schpc_cv); 15351708Sstevel mutex_exit(&schpc_p->schpc_mutex); 15361708Sstevel 15371708Sstevel return (rval); 15381708Sstevel 15391708Sstevel case HPC_CTRL_ENABLE_ENUM: 15401708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 15411708Sstevel "HPC_CTRL_ENABLE_ENUM"); 15421708Sstevel 15431708Sstevel setslot.slot_enable_ENUM = PCIMSG_ON; 15441708Sstevel 15451708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot); 15461708Sstevel 15471708Sstevel if (rval) 15481708Sstevel rval = HPC_ERR_FAILED; 15491708Sstevel 15501708Sstevel mutex_enter(&schpc_p->schpc_mutex); 15511708Sstevel schpc_p->schpc_slot[slot].state &= 15521708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 15531708Sstevel cv_signal(&schpc_p->schpc_cv); 15541708Sstevel mutex_exit(&schpc_p->schpc_mutex); 15551708Sstevel 15561708Sstevel return (rval); 15571708Sstevel 15581708Sstevel default: 15591708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 15601708Sstevel "****NOT SUPPORTED CONTROL CMD"); 15611708Sstevel 15621708Sstevel mutex_enter(&schpc_p->schpc_mutex); 15631708Sstevel schpc_p->schpc_slot[slot].state &= 15641708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 15651708Sstevel cv_signal(&schpc_p->schpc_cv); 15661708Sstevel mutex_exit(&schpc_p->schpc_mutex); 15671708Sstevel 15681708Sstevel return (HPC_ERR_NOTSUPPORTED); 15691708Sstevel } 15701708Sstevel } 15711708Sstevel 15721708Sstevel /* 15731708Sstevel * schpc_pci_control 15741708Sstevel * 15751708Sstevel * Called by Hot Plug Services to perform a attachment point specific 15761708Sstevel * on a Hot Pluggable Standard PCI Slot. 15771708Sstevel */ 15781708Sstevel /*ARGSUSED*/ 15791708Sstevel static int 15801708Sstevel schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 15811708Sstevel caddr_t arg) 15821708Sstevel { 15831708Sstevel int rval; 15841708Sstevel int expander, board, slot; 15851708Sstevel pci_setslot_t setslot; 15861708Sstevel pci_getslot_t slotstatus; 15871708Sstevel hpc_led_info_t *hpc_led_info; 15881708Sstevel 15891708Sstevel SCHPC_DEBUG3(D_IOC_CONTROL, 15901708Sstevel "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)", 15911708Sstevel ops_arg, slot_hdl, request); 15921708Sstevel 15931708Sstevel mutex_enter(&schpc_p->schpc_mutex); 15941708Sstevel 15951708Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl); 15961708Sstevel 15971708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 15981708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, 15991708Sstevel "schpc_disconnect - HPC Not Inited"); 16001708Sstevel mutex_exit(&schpc_p->schpc_mutex); 16011708Sstevel return (HPC_ERR_FAILED); 16021708Sstevel } 16031708Sstevel 16041708Sstevel /* 16051708Sstevel * Block if another thread is executing a HPC command. 16061708Sstevel */ 16071708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 16081708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 16091708Sstevel } 16101708Sstevel 16111708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 16121708Sstevel 16131708Sstevel mutex_exit(&schpc_p->schpc_mutex); 16141708Sstevel 16151708Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 16161708Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */ 16171708Sstevel 16181708Sstevel /* 16191708Sstevel * Initialize Set Slot Command. 16201708Sstevel */ 16211708Sstevel schpc_init_setslot_message(&setslot); 16221708Sstevel 16231708Sstevel /* 16241708Sstevel * Initialize LED to last know state. 16251708Sstevel */ 16261708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) { 16271708Sstevel case LED_ON: 16281708Sstevel setslot.slot_led_power = PCIMSG_LED_ON; 16291708Sstevel break; 16301708Sstevel case LED_OFF: 16311708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF; 16321708Sstevel break; 16331708Sstevel case LED_FLASH: 16341708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH; 16351708Sstevel break; 16361708Sstevel } 16371708Sstevel 16381708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) { 16391708Sstevel case LED_ON: 16401708Sstevel setslot.slot_led_service = PCIMSG_LED_ON; 16411708Sstevel break; 16421708Sstevel case LED_OFF: 16431708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF; 16441708Sstevel break; 16451708Sstevel case LED_FLASH: 16461708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH; 16471708Sstevel break; 16481708Sstevel } 16491708Sstevel 16501708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) { 16511708Sstevel case LED_ON: 16521708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON; 16531708Sstevel break; 16541708Sstevel case LED_OFF: 16551708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 16561708Sstevel break; 16571708Sstevel case LED_FLASH: 16581708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 16591708Sstevel break; 16601708Sstevel } 16611708Sstevel 16621708Sstevel switch (request) { 16631708Sstevel 16641708Sstevel 16651708Sstevel case HPC_CTRL_GET_SLOT_STATE: { 16661708Sstevel hpc_slot_state_t *hpc_slot_state; 16671708Sstevel 16681708Sstevel hpc_slot_state = (hpc_slot_state_t *)arg; 16691708Sstevel 16701708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 16711708Sstevel "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p", 16721708Sstevel hpc_slot_state); 16731708Sstevel 16741708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 16751708Sstevel 16761708Sstevel if (!rval) { 16771708Sstevel 16781708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 16791708Sstevel 16801708Sstevel mutex_enter(&schpc_p->schpc_mutex); 16811708Sstevel schpc_p->schpc_slot[slot].state &= 16821708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 16831708Sstevel cv_signal(&schpc_p->schpc_cv); 16841708Sstevel mutex_exit(&schpc_p->schpc_mutex); 16851708Sstevel 16861708Sstevel return (HPC_ERR_FAILED); 16871708Sstevel } 16881708Sstevel 16891708Sstevel if (slotstatus.slot_empty == PCIMSG_ON) { 16901708Sstevel *hpc_slot_state = HPC_SLOT_EMPTY; 16911708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty"); 16921708Sstevel } else if (slotstatus.slot_power_on == PCIMSG_ON) { 16931708Sstevel *hpc_slot_state = HPC_SLOT_CONNECTED; 16941708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected"); 16951708Sstevel schpc_p->schpc_slot[slot].state |= 16961708Sstevel SCHPC_SLOTSTATE_CONNECTED; 16971708Sstevel } else { 16981708Sstevel *hpc_slot_state = HPC_SLOT_DISCONNECTED; 16991708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, 17001708Sstevel "Slot Disconnected"); 17011708Sstevel schpc_p->schpc_slot[slot].state &= 17021708Sstevel ~SCHPC_SLOTSTATE_CONNECTED; 17031708Sstevel } 17041708Sstevel } else { 17051708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed"); 17061708Sstevel 17071708Sstevel mutex_enter(&schpc_p->schpc_mutex); 17081708Sstevel schpc_p->schpc_slot[slot].state &= 17091708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 17101708Sstevel cv_signal(&schpc_p->schpc_cv); 17111708Sstevel mutex_exit(&schpc_p->schpc_mutex); 17121708Sstevel 17131708Sstevel return (HPC_ERR_FAILED); 17141708Sstevel } 17151708Sstevel 17161708Sstevel mutex_enter(&schpc_p->schpc_mutex); 17171708Sstevel schpc_p->schpc_slot[slot].state &= 17181708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 17191708Sstevel cv_signal(&schpc_p->schpc_cv); 17201708Sstevel mutex_exit(&schpc_p->schpc_mutex); 17211708Sstevel 17221708Sstevel return (0); 17231708Sstevel } 17241708Sstevel case HPC_CTRL_GET_BOARD_TYPE: { 17251708Sstevel hpc_board_type_t *hpc_board_type; 17261708Sstevel 17271708Sstevel hpc_board_type = (hpc_board_type_t *)arg; 17281708Sstevel 17291708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 17301708Sstevel "HPC_CTRL_GET_BOARD_TYPE"); 17311708Sstevel 17321708Sstevel 17331708Sstevel /* 17341708Sstevel * The HPC driver does not know what board type 17351708Sstevel * is plugged in. 17361708Sstevel */ 17371708Sstevel *hpc_board_type = HPC_BOARD_PCI_HOTPLUG; 17381708Sstevel 17391708Sstevel mutex_enter(&schpc_p->schpc_mutex); 17401708Sstevel schpc_p->schpc_slot[slot].state &= 17411708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 17421708Sstevel cv_signal(&schpc_p->schpc_cv); 17431708Sstevel mutex_exit(&schpc_p->schpc_mutex); 17441708Sstevel 17451708Sstevel return (0); 17461708Sstevel 17471708Sstevel } 17481708Sstevel case HPC_CTRL_DEV_UNCONFIG_START: 17491708Sstevel case HPC_CTRL_DEV_CONFIG_START: 17501708Sstevel case HPC_CTRL_DEV_CONFIGURED: 17511708Sstevel case HPC_CTRL_DEV_UNCONFIGURED: 17521708Sstevel mutex_enter(&schpc_p->schpc_mutex); 17531708Sstevel schpc_p->schpc_slot[slot].state &= 17541708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 17551708Sstevel cv_signal(&schpc_p->schpc_cv); 17561708Sstevel mutex_exit(&schpc_p->schpc_mutex); 17571708Sstevel 17581708Sstevel return (0); 17591708Sstevel 17601708Sstevel case HPC_CTRL_GET_LED_STATE: 17611708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 17621708Sstevel "HPC_CTRL_GET_LED_STATE"); 17631708Sstevel hpc_led_info = (hpc_led_info_t *)arg; 17641708Sstevel 17651708Sstevel switch (hpc_led_info->led) { 17661708Sstevel case HPC_FAULT_LED: 17671708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) { 17681708Sstevel case LED_OFF: 17691708Sstevel hpc_led_info->state = HPC_LED_OFF; 17701708Sstevel break; 17711708Sstevel case LED_ON: 17721708Sstevel hpc_led_info->state = HPC_LED_ON; 17731708Sstevel break; 17741708Sstevel case LED_FLASH: 17751708Sstevel hpc_led_info->state = HPC_LED_BLINK; 17761708Sstevel break; 17771708Sstevel } 17781708Sstevel break; 17791708Sstevel 17801708Sstevel case HPC_POWER_LED: 17811708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) { 17821708Sstevel case LED_OFF: 17831708Sstevel hpc_led_info->state = HPC_LED_OFF; 17841708Sstevel break; 17851708Sstevel case LED_ON: 17861708Sstevel hpc_led_info->state = HPC_LED_ON; 17871708Sstevel break; 17881708Sstevel case LED_FLASH: 17891708Sstevel hpc_led_info->state = HPC_LED_BLINK; 17901708Sstevel break; 17911708Sstevel } 17921708Sstevel break; 17931708Sstevel case HPC_ATTN_LED: 17941708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) { 17951708Sstevel case LED_OFF: 17961708Sstevel hpc_led_info->state = HPC_LED_OFF; 17971708Sstevel break; 17981708Sstevel case LED_ON: 17991708Sstevel hpc_led_info->state = HPC_LED_OFF; 18001708Sstevel break; 18011708Sstevel case LED_FLASH: 18021708Sstevel hpc_led_info->state = HPC_LED_ON; 18031708Sstevel break; 18041708Sstevel } 18051708Sstevel break; 18061708Sstevel case HPC_ACTIVE_LED: 18071708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) { 18081708Sstevel case LED_OFF: 18091708Sstevel hpc_led_info->state = HPC_LED_OFF; 18101708Sstevel break; 18111708Sstevel case LED_ON: 18121708Sstevel hpc_led_info->state = HPC_LED_ON; 18131708Sstevel break; 18141708Sstevel case LED_FLASH: 18151708Sstevel hpc_led_info->state = HPC_LED_BLINK; 18161708Sstevel break; 18171708Sstevel } 18181708Sstevel break; 18191708Sstevel default: 18201708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 18211708Sstevel "Invalid LED %x", hpc_led_info->led); 18221708Sstevel 18231708Sstevel mutex_enter(&schpc_p->schpc_mutex); 18241708Sstevel schpc_p->schpc_slot[slot].state &= 18251708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 18261708Sstevel cv_signal(&schpc_p->schpc_cv); 18271708Sstevel mutex_exit(&schpc_p->schpc_mutex); 18281708Sstevel 18291708Sstevel return (HPC_ERR_FAILED); 18301708Sstevel } 18311708Sstevel 18321708Sstevel mutex_enter(&schpc_p->schpc_mutex); 18331708Sstevel schpc_p->schpc_slot[slot].state &= 18341708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 18351708Sstevel cv_signal(&schpc_p->schpc_cv); 18361708Sstevel mutex_exit(&schpc_p->schpc_mutex); 18371708Sstevel 18381708Sstevel return (0); 18391708Sstevel 18401708Sstevel case HPC_CTRL_SET_LED_STATE: 18411708Sstevel hpc_led_info = (hpc_led_info_t *)arg; 18421708Sstevel 18431708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 18441708Sstevel "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", hpc_led_info); 18451708Sstevel 18461708Sstevel switch (hpc_led_info->led) { 18471708Sstevel case HPC_FAULT_LED: 18481708Sstevel switch (hpc_led_info->state) { 18491708Sstevel case HPC_LED_OFF: 18501708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 18511708Sstevel LED_OFF; 18521708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 18531708Sstevel break; 18541708Sstevel case HPC_LED_ON: 18551708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 18561708Sstevel LED_ON; 18571708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON; 18581708Sstevel break; 18591708Sstevel case HPC_LED_BLINK: 18601708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 18611708Sstevel LED_FLASH; 18621708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 18631708Sstevel break; 18641708Sstevel } 18651708Sstevel break; 18661708Sstevel case HPC_POWER_LED: 18671708Sstevel switch (hpc_led_info->state) { 18681708Sstevel case HPC_LED_OFF: 18691708Sstevel schpc_p->schpc_slot[slot].led.led_power = 18701708Sstevel LED_OFF; 18711708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF; 18721708Sstevel break; 18731708Sstevel case HPC_LED_ON: 18741708Sstevel schpc_p->schpc_slot[slot].led.led_power = 18751708Sstevel LED_ON; 18761708Sstevel setslot.slot_led_power = PCIMSG_LED_ON; 18771708Sstevel break; 18781708Sstevel case HPC_LED_BLINK: 18791708Sstevel schpc_p->schpc_slot[slot].led.led_power = 18801708Sstevel LED_FLASH; 18811708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH; 18821708Sstevel break; 18831708Sstevel } 18841708Sstevel break; 18851708Sstevel case HPC_ATTN_LED: 18861708Sstevel switch (hpc_led_info->state) { 18871708Sstevel case HPC_LED_OFF: 18881708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 18891708Sstevel LED_OFF; 18901708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 18911708Sstevel break; 18921708Sstevel case HPC_LED_ON: 18931708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 18941708Sstevel LED_FLASH; 18951708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 18961708Sstevel break; 18971708Sstevel case HPC_LED_BLINK: 18981708Sstevel schpc_p->schpc_slot[slot].led.led_fault = 18991708Sstevel LED_FLASH; 19001708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 19011708Sstevel break; 19021708Sstevel } 19031708Sstevel break; 19041708Sstevel case HPC_ACTIVE_LED: 19051708Sstevel switch (hpc_led_info->state) { 19061708Sstevel case HPC_LED_OFF: 19071708Sstevel schpc_p->schpc_slot[slot].led.led_service = 19081708Sstevel LED_OFF; 19091708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF; 19101708Sstevel break; 19111708Sstevel case HPC_LED_ON: 19121708Sstevel schpc_p->schpc_slot[slot].led.led_service = 19131708Sstevel LED_ON; 19141708Sstevel setslot.slot_led_service = PCIMSG_LED_ON; 19151708Sstevel break; 19161708Sstevel case HPC_LED_BLINK: 19171708Sstevel schpc_p->schpc_slot[slot].led.led_service = 19181708Sstevel LED_FLASH; 19191708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH; 19201708Sstevel break; 19211708Sstevel } 19221708Sstevel break; 19231708Sstevel default: 19241708Sstevel mutex_enter(&schpc_p->schpc_mutex); 19251708Sstevel schpc_p->schpc_slot[slot].state &= 19261708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 19271708Sstevel cv_signal(&schpc_p->schpc_cv); 19281708Sstevel mutex_exit(&schpc_p->schpc_mutex); 19291708Sstevel 19301708Sstevel return (0); 19311708Sstevel } 19321708Sstevel 19331708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot); 19341708Sstevel 19351708Sstevel mutex_enter(&schpc_p->schpc_mutex); 19361708Sstevel schpc_p->schpc_slot[slot].state &= 19371708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 19381708Sstevel cv_signal(&schpc_p->schpc_cv); 19391708Sstevel mutex_exit(&schpc_p->schpc_mutex); 19401708Sstevel 19411708Sstevel return (0); 19421708Sstevel 19431708Sstevel case HPC_CTRL_ENABLE_AUTOCFG: 19441708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 19451708Sstevel "HPC_CTRL_ENABLE_AUTOCFG"); 19461708Sstevel 19471708Sstevel schpc_p->schpc_slot[slot].state |= 19481708Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 19491708Sstevel 19501708Sstevel mutex_enter(&schpc_p->schpc_mutex); 19511708Sstevel schpc_p->schpc_slot[slot].state &= 19521708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 19531708Sstevel cv_signal(&schpc_p->schpc_cv); 19541708Sstevel mutex_exit(&schpc_p->schpc_mutex); 19551708Sstevel 19561708Sstevel return (0); 19571708Sstevel 19581708Sstevel case HPC_CTRL_DISABLE_AUTOCFG: 19591708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 19601708Sstevel "HPC_CTRL_DISABLE_AUTOCFG"); 19611708Sstevel schpc_p->schpc_slot[slot].state &= 19621708Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 19631708Sstevel 19641708Sstevel mutex_enter(&schpc_p->schpc_mutex); 19651708Sstevel schpc_p->schpc_slot[slot].state &= 19661708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 19671708Sstevel cv_signal(&schpc_p->schpc_cv); 19681708Sstevel mutex_exit(&schpc_p->schpc_mutex); 19691708Sstevel 19701708Sstevel return (0); 19711708Sstevel 19721708Sstevel case HPC_CTRL_DISABLE_ENUM: 19731708Sstevel case HPC_CTRL_ENABLE_ENUM: 19741708Sstevel default: 19751708Sstevel mutex_enter(&schpc_p->schpc_mutex); 19761708Sstevel schpc_p->schpc_slot[slot].state &= 19771708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 19781708Sstevel cv_signal(&schpc_p->schpc_cv); 19791708Sstevel mutex_exit(&schpc_p->schpc_mutex); 19801708Sstevel 19811708Sstevel return (HPC_ERR_NOTSUPPORTED); 19821708Sstevel } 19831708Sstevel } 19841708Sstevel 19851708Sstevel /* 19861708Sstevel * schpc_test 19871708Sstevel * 19881708Sstevel * Tests the slot. 19891708Sstevel */ 19901708Sstevel /*ARGSUSED*/ 19911708Sstevel static void 19921708Sstevel schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags) 19931708Sstevel { 19941708Sstevel pci_getslot_t slotstatus; 19951708Sstevel pci_setslot_t setslot; 19961708Sstevel int expander, board; 19971708Sstevel int rval; 19981708Sstevel int retry = 1; 19991708Sstevel 20001708Sstevel SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)", 20011708Sstevel ops_arg, SCHPC_SLOT_NUM(slot)); 20021708Sstevel 20031708Sstevel SCHPC_DEBUG3(D_IOC_TEST, 20041708Sstevel " schpc_test() Expander=%d Board=%d Slot=%d", 20051708Sstevel schpc_p->schpc_slot[slot].expander, 20061708Sstevel schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot)); 20071708Sstevel 20081708Sstevel expander = schpc_p->schpc_slot[slot].expander; 20091708Sstevel board = schpc_p->schpc_slot[slot].board; 20101708Sstevel 20111708Sstevel restart_test: 20121708Sstevel /* 20131708Sstevel * Initial the slot with its occupant and receptacle in good condition. 20141708Sstevel */ 20151708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_REC_GOOD; 20161708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_OCC_GOOD; 20171708Sstevel 20181708Sstevel 20191708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 20201708Sstevel 20211708Sstevel if (rval) { 20221708Sstevel /* 20231708Sstevel * System Controller/Mailbox failure. 20241708Sstevel */ 20251708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 20261708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 20271708Sstevel "Communicate with System Controller", expander, board, 20281708Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 20291708Sstevel 20301708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 20311708Sstevel return; 20321708Sstevel } 20331708Sstevel 20341708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 20351708Sstevel 20361708Sstevel cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d " 20371708Sstevel "is not hot pluggable\n", expander, board, 20381708Sstevel SCHPC_SLOT_NUM(slot)); 20391708Sstevel 20401708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 20411708Sstevel return; 20421708Sstevel } 20431708Sstevel 20441708Sstevel switch (slotstatus.slot_condition) { 20451708Sstevel case PCIMSG_SLOTCOND_OCC_FAIL: 20461708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 20471708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 20481708Sstevel "System Controller/Occupant Failed", 20491708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 20501708Sstevel schpc_p->schpc_slot[slot].ap_id); 20511708Sstevel 20521708Sstevel schpc_setslotled(expander, board, slot, 20531708Sstevel (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON)); 20541708Sstevel 20551708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_OCC_GOOD; 20561708Sstevel return; 20571708Sstevel case PCIMSG_SLOTCOND_REC_FAIL: 20581708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 20591708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 20601708Sstevel "System Controller/Receptacle Failed", 20611708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 20621708Sstevel schpc_p->schpc_slot[slot].ap_id); 20631708Sstevel 20641708Sstevel schpc_setslotled(expander, board, slot, 20651708Sstevel (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON)); 20661708Sstevel 20671708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 20681708Sstevel return; 20691708Sstevel case PCIMSG_SLOTCOND_NOHOTPLUG: 20701708Sstevel cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d " 20711708Sstevel "is not hot pluggable\n", expander, board, 20721708Sstevel SCHPC_SLOT_NUM(slot)); 20731708Sstevel 20741708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 20751708Sstevel return; 20761708Sstevel } 20771708Sstevel 20781708Sstevel if (slotstatus.slot_power_on) { 20791708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON; 20801708Sstevel 20811708Sstevel if (!slotstatus.slot_HEALTHY) { 20821708Sstevel /* 20831708Sstevel * cPCI Adapter is not asserting HEALTHY#. 20841708Sstevel */ 20851708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 20861708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 20871708Sstevel "PCI adapter not HEALTHY", expander, board, 20881708Sstevel SCHPC_SLOT_NUM(slot), 20891708Sstevel schpc_p->schpc_slot[slot].ap_id); 20901708Sstevel 20911708Sstevel schpc_setslotled(expander, board, slot, 20921708Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 20931708Sstevel 20941708Sstevel schpc_p->schpc_slot[slot].state &= 20951708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD; 20961708Sstevel 20971708Sstevel return; 20981708Sstevel } 20991708Sstevel 21001708Sstevel if (!slotstatus.slot_powergood) { 21011708Sstevel /* 21021708Sstevel * PCI Power Input is not good. 21031708Sstevel */ 21041708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 21051708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 21061708Sstevel "System Controller PCI Power Input Not Good", 21071708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 21081708Sstevel schpc_p->schpc_slot[slot].ap_id); 21091708Sstevel 21101708Sstevel schpc_setslotled(expander, board, slot, 21111708Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 21121708Sstevel 21131708Sstevel schpc_p->schpc_slot[slot].state &= 21141708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD; 21151708Sstevel 21161708Sstevel return; 21171708Sstevel } 21181708Sstevel 21191708Sstevel if (slotstatus.slot_powerfault) { 21201708Sstevel /* 21211708Sstevel * PCI Power Fault. 21221708Sstevel */ 21231708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 21241708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 21251708Sstevel "System Controller PCI Power Fault", 21261708Sstevel expander, board, SCHPC_SLOT_NUM(slot), 21271708Sstevel schpc_p->schpc_slot[slot].ap_id); 21281708Sstevel 21291708Sstevel schpc_setslotled(expander, board, slot, 21301708Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 21311708Sstevel 21321708Sstevel schpc_p->schpc_slot[slot].state &= 21331708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD; 21341708Sstevel 21351708Sstevel return; 21361708Sstevel } 21371708Sstevel } 21381708Sstevel 21391708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0"); 21401708Sstevel 21411708Sstevel /* 21421708Sstevel * Is the slot empty? 21431708Sstevel */ 21441708Sstevel if (slotstatus.slot_empty) { 21451708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty"); 21461708Sstevel 21471708Sstevel schpc_p->schpc_slot[slot].state &= 21481708Sstevel ~SCHPC_SLOTSTATE_PRESENT; 21491708Sstevel 21501708Sstevel if (slotstatus.slot_power_on) { 21511708Sstevel 21521708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot " 21531708Sstevel "is powered ON"); 21541708Sstevel 21551708Sstevel /* 21561708Sstevel * Tests will be retried once after powering off 21571708Sstevel * an empty slot. 21581708Sstevel */ 21591708Sstevel if (retry) { 21601708Sstevel 21611708Sstevel /* 21621708Sstevel * Turn off the slot and restart test. 21631708Sstevel */ 21641708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() " 21651708Sstevel "Turning Empty Slot OFF"); 21661708Sstevel 21671708Sstevel schpc_init_setslot_message(&setslot); 21681708Sstevel setslot.slot_power_off = PCIMSG_ON; 21691708Sstevel (void) schpc_setslotstatus( 21701708Sstevel expander, board, slot, &setslot); 21711708Sstevel 21721708Sstevel retry = 0; 21731708Sstevel 21741708Sstevel goto restart_test; 21751708Sstevel } 21761708Sstevel } 21771708Sstevel } else { 21781708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present"); 21791708Sstevel 21801708Sstevel if (!slotstatus.slot_power_on) { 21811708Sstevel if (retry) { 21821708Sstevel /* 21831708Sstevel * If there is a cassette present and the 21841708Sstevel * power is off, try turning the power on and 21851708Sstevel * restart the test. This allows access to 21861708Sstevel * the FRUID when an empty cassette is 21871708Sstevel * installed. 21881708Sstevel */ 21891708Sstevel SCHPC_DEBUG0(D_IOC_TEST, 21901708Sstevel "schpc_test() Power On Adapter"); 21911708Sstevel schpc_init_setslot_message(&setslot); 21921708Sstevel setslot.slot_power_on = PCIMSG_ON; 21931708Sstevel (void) schpc_setslotstatus( 21941708Sstevel expander, board, slot, &setslot); 21951708Sstevel retry = 0; 21961708Sstevel goto restart_test; 21971708Sstevel } 21981708Sstevel } 21991708Sstevel 22001708Sstevel schpc_p->schpc_slot[slot].state |= 22011708Sstevel SCHPC_SLOTSTATE_PRESENT; 22021708Sstevel } 22031708Sstevel 22041708Sstevel /* 22051708Sstevel * Is the slot powered up? 22061708Sstevel */ 22071708Sstevel schpc_init_setslot_message(&setslot); 22081708Sstevel 22091708Sstevel if (slotstatus.slot_power_on) { 22101708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On"); 22111708Sstevel 22121708Sstevel schpc_p->schpc_slot[slot].state |= 22131708Sstevel SCHPC_SLOTSTATE_CONNECTED; 22141708Sstevel 22151708Sstevel setslot.slot_led_power = PCIMSG_LED_ON; 22161708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF; 22171708Sstevel setslot.slot_enable_ENUM = PCIMSG_ON; 22181708Sstevel setslot.slot_enable_HEALTHY = PCIMSG_ON; 22191708Sstevel } else { 22201708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off"); 22211708Sstevel 22221708Sstevel schpc_p->schpc_slot[slot].state &= 22231708Sstevel ~SCHPC_SLOTSTATE_CONNECTED; 22241708Sstevel 22251708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF; 22261708Sstevel setslot.slot_led_service = PCIMSG_LED_ON; 22271708Sstevel setslot.slot_disable_ENUM = PCIMSG_ON; 22281708Sstevel setslot.slot_disable_HEALTHY = PCIMSG_ON; 22291708Sstevel } 22301708Sstevel 22311708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 22321708Sstevel 22331708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot); 22341708Sstevel 22351708Sstevel /* 22361708Sstevel * Save LED State. 22371708Sstevel */ 22381708Sstevel switch (setslot.slot_led_power) { 22391708Sstevel case PCIMSG_LED_ON: 22401708Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_ON; 22411708Sstevel break; 22421708Sstevel case PCIMSG_LED_OFF: 22431708Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_OFF; 22441708Sstevel break; 22451708Sstevel case PCIMSG_LED_FLASH: 22461708Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_FLASH; 22471708Sstevel break; 22481708Sstevel } 22491708Sstevel switch (setslot.slot_led_service) { 22501708Sstevel case PCIMSG_LED_ON: 22511708Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_ON; 22521708Sstevel break; 22531708Sstevel case PCIMSG_LED_OFF: 22541708Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_OFF; 22551708Sstevel break; 22561708Sstevel case PCIMSG_LED_FLASH: 22571708Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_FLASH; 22581708Sstevel break; 22591708Sstevel } 22601708Sstevel switch (setslot.slot_led_fault) { 22611708Sstevel case PCIMSG_LED_ON: 22621708Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_ON; 22631708Sstevel break; 22641708Sstevel case PCIMSG_LED_OFF: 22651708Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_OFF; 22661708Sstevel break; 22671708Sstevel case PCIMSG_LED_FLASH: 22681708Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH; 22691708Sstevel break; 22701708Sstevel } 22711708Sstevel } 22721708Sstevel 22731708Sstevel 22741708Sstevel /* 22751708Sstevel * schpc_event_handler 22761708Sstevel * 22771708Sstevel * Placed on the schpc_event_taskq by schpc_event_filter when an 22781708Sstevel * unsolicited MBOXSC_MSG_EVENT is received from the SC. It handles 22791708Sstevel * things like power insertion/removal, ENUM#, etc. 22801708Sstevel */ 22811708Sstevel static void 22821708Sstevel schpc_event_handler(void *arg) 22831708Sstevel { 22841708Sstevel pci_getslot_t slotstatus; 22851708Sstevel uint8_t expander, board, slot; 22861708Sstevel int rval; 22871708Sstevel pcimsg_t *event = (pcimsg_t *)arg; 22881708Sstevel 22891708Sstevel /* 22901708Sstevel * OK, we got an event message. Since the event message only tells 22911708Sstevel * us something has changed and not changed to what, we need to get 22921708Sstevel * the current slot status to find how WHAT was change to WHAT. 22931708Sstevel */ 22941708Sstevel 22951708Sstevel slot = event->pcimsg_slot; 22961708Sstevel expander = event->pcimsg_node; /* get expander */ 22971708Sstevel board = event->pcimsg_board; /* get board */ 22981708Sstevel 22991708Sstevel SCHPC_DEBUG3(D_EVENT, 23001708Sstevel "schpc_event_handler() - exp=%d board=%d slot=%d", 23011708Sstevel expander, board, slot); 23021708Sstevel 23031708Sstevel /* create a slot table index */ 23041708Sstevel slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot); 23051708Sstevel 23061708Sstevel SCHPC_DEBUG1(D_EVENT, 23071708Sstevel "schpc_event_handler() - expanded slot %d", slot); 23081708Sstevel 23091708Sstevel if (schpc_p == NULL) { 23101708Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc"); 23111708Sstevel kmem_free(event, sizeof (pcimsg_t)); 23121708Sstevel return; 23131708Sstevel } 23141708Sstevel 23151708Sstevel mutex_enter(&schpc_p->schpc_mutex); 23161708Sstevel 23171708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 23181708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited"); 23191708Sstevel mutex_exit(&schpc_p->schpc_mutex); 23201708Sstevel kmem_free(event, sizeof (pcimsg_t)); 23211708Sstevel return; 23221708Sstevel } 23231708Sstevel /* 23241708Sstevel * Block if another thread is executing a HPC command. 23251708Sstevel */ 23261708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 23271708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy"); 23281708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 23291708Sstevel } 23301708Sstevel 23311708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 23321708Sstevel 23331708Sstevel mutex_exit(&schpc_p->schpc_mutex); 23341708Sstevel 23351708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 23361708Sstevel 23371708Sstevel if (rval) { 23381708Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not get status " 23391708Sstevel "for expander=%d board=%d slot=%d\n", 23401708Sstevel expander, board, SCHPC_SLOT_NUM(slot)); 23411708Sstevel 23421708Sstevel mutex_enter(&schpc_p->schpc_mutex); 23431708Sstevel schpc_p->schpc_slot[slot].state &= 23441708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 23451708Sstevel cv_signal(&schpc_p->schpc_cv); 23461708Sstevel mutex_exit(&schpc_p->schpc_mutex); 23471708Sstevel kmem_free(event, sizeof (pcimsg_t)); 23481708Sstevel return; 23491708Sstevel } 23501708Sstevel 23511708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 23521708Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not get good " 23531708Sstevel "status for expander=%d board=%d slot=%d\n", 23541708Sstevel expander, board, SCHPC_SLOT_NUM(slot)); 23551708Sstevel 23561708Sstevel mutex_enter(&schpc_p->schpc_mutex); 23571708Sstevel schpc_p->schpc_slot[slot].state &= 23581708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 23591708Sstevel cv_signal(&schpc_p->schpc_cv); 23601708Sstevel mutex_exit(&schpc_p->schpc_mutex); 23611708Sstevel 23621708Sstevel kmem_free(event, sizeof (pcimsg_t)); 23631708Sstevel return; 23641708Sstevel } 23651708Sstevel 23661708Sstevel SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d", 23671708Sstevel expander, board, SCHPC_SLOT_NUM(slot)); 23681708Sstevel 23691708Sstevel if (schpc_p->schpc_slot[slot].slot_ops == NULL) { 23701708Sstevel SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event " 23711708Sstevel "for unregistered slot for expander=%d board=%d slot=%d", 23721708Sstevel expander, board, SCHPC_SLOT_NUM(slot)); 23731708Sstevel 23741708Sstevel mutex_enter(&schpc_p->schpc_mutex); 23751708Sstevel schpc_p->schpc_slot[slot].state &= 23761708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 23771708Sstevel cv_signal(&schpc_p->schpc_cv); 23781708Sstevel mutex_exit(&schpc_p->schpc_mutex); 23791708Sstevel 23801708Sstevel kmem_free(event, sizeof (pcimsg_t)); 23811708Sstevel return; 23821708Sstevel } 23831708Sstevel 23841708Sstevel /* Slot Power Event */ 23851708Sstevel 23861708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_power) { 23871708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event"); 23881708Sstevel /* 23891708Sstevel * The SC may have changed to slot power status. 23901708Sstevel */ 23911708Sstevel if (slotstatus.slot_power_on) { 23921708Sstevel schpc_p->schpc_slot[slot].state |= 23931708Sstevel SCHPC_SLOTSTATE_CONNECTED; 23941708Sstevel 23951708Sstevel hpc_slot_event_notify( 23961708Sstevel schpc_p->schpc_slot[slot].slot_handle, 23971708Sstevel HPC_EVENT_SLOT_POWER_ON, 0); 23981708Sstevel } else { 23991708Sstevel schpc_p->schpc_slot[slot].state &= 24001708Sstevel ~SCHPC_SLOTSTATE_CONNECTED; 24011708Sstevel 24021708Sstevel hpc_slot_event_notify( 24031708Sstevel schpc_p->schpc_slot[slot].slot_handle, 24041708Sstevel HPC_EVENT_SLOT_POWER_OFF, 0); 24051708Sstevel } 24061708Sstevel } 24071708Sstevel 24081708Sstevel /* Adapter Insertion/Removal Event */ 24091708Sstevel 24101708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_presence) { 24111708Sstevel if (slotstatus.slot_empty == PCIMSG_ON) { 24121708Sstevel 24131708Sstevel /* Adapter Removed */ 24141708Sstevel 24151708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed"); 24161708Sstevel 24171708Sstevel if (schpc_p->schpc_slot[slot].state & 24181708Sstevel SCHPC_SLOTSTATE_CONNECTED) { 24191708Sstevel /* 24201708Sstevel * If the adapter has been removed while 24211708Sstevel * there the slot is connected, it could be 24221708Sstevel * due to a ENUM handling. 24231708Sstevel */ 24241708Sstevel cmn_err(CE_WARN, "Card removed from " 24251708Sstevel "powered on slot at " 24261708Sstevel "expander=%d board=%d slot=%d\n", 24271708Sstevel expander, board, SCHPC_SLOT_NUM(slot)); 24281708Sstevel 24291708Sstevel schpc_p->schpc_slot[slot].state &= 24301708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 24311708Sstevel rval = schpc_disconnect((caddr_t)schpc_p, 24321708Sstevel schpc_p->schpc_slot[slot].slot_handle, 24331708Sstevel 0, 0); 24341708Sstevel mutex_enter(&schpc_p->schpc_mutex); 24351708Sstevel while (schpc_p->schpc_slot[slot].state & 24361708Sstevel SCHPC_SLOTSTATE_EXECUTING) { 24371708Sstevel SCHPC_DEBUG0(D_EVENT, 24381708Sstevel "schpc_event_handler - " 24391708Sstevel "Slot is busy"); 24401708Sstevel cv_wait(&schpc_p->schpc_cv, 24411708Sstevel &schpc_p->schpc_mutex); 24421708Sstevel } 24431708Sstevel 24441708Sstevel schpc_p->schpc_slot[slot].state |= 24451708Sstevel SCHPC_SLOTSTATE_EXECUTING; 24461708Sstevel 24471708Sstevel mutex_exit(&schpc_p->schpc_mutex); 24481708Sstevel } 24491708Sstevel schpc_p->schpc_slot[slot].state |= 24501708Sstevel SCHPC_SLOTSTATE_OCC_GOOD; 24511708Sstevel 24521708Sstevel schpc_p->schpc_slot[slot].state &= 2453*7656SSherry.Moore@Sun.COM ~SCHPC_SLOTSTATE_PRESENT; 24541708Sstevel 24551708Sstevel hpc_slot_event_notify( 24561708Sstevel schpc_p->schpc_slot[slot].slot_handle, 24571708Sstevel HPC_EVENT_SLOT_REMOVAL, 0); 24581708Sstevel } else { 24591708Sstevel 24601708Sstevel /* Adapter Inserted */ 24611708Sstevel 24621708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted"); 24631708Sstevel 24641708Sstevel if (schpc_p->schpc_slot[slot].state & 24651708Sstevel SCHPC_SLOTSTATE_PRESENT) { 24661708Sstevel /* 24671708Sstevel * If the adapter is already present 24681708Sstevel * throw the this event away. 24691708Sstevel */ 24701708Sstevel 24711708Sstevel SCHPC_DEBUG0(D_EVENT, 24721708Sstevel "Adapter is already present"); 24731708Sstevel 24741708Sstevel mutex_enter(&schpc_p->schpc_mutex); 24751708Sstevel schpc_p->schpc_slot[slot].state &= 24761708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 24771708Sstevel cv_signal(&schpc_p->schpc_cv); 24781708Sstevel mutex_exit(&schpc_p->schpc_mutex); 24791708Sstevel 24801708Sstevel kmem_free(event, sizeof (pcimsg_t)); 24811708Sstevel return; 24821708Sstevel } 24831708Sstevel 24841708Sstevel schpc_p->schpc_slot[slot].state |= 24851708Sstevel SCHPC_SLOTSTATE_PRESENT; 24861708Sstevel 24871708Sstevel schpc_p->schpc_slot[slot].state &= 24881708Sstevel ~SCHPC_SLOTSTATE_CONNECTED; 24891708Sstevel 24901708Sstevel hpc_slot_event_notify( 24911708Sstevel schpc_p->schpc_slot[slot].slot_handle, 24921708Sstevel HPC_EVENT_SLOT_INSERTION, 0); 24931708Sstevel 24941708Sstevel if (schpc_p->schpc_slot[slot].state & 24951708Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE) { 24961708Sstevel SCHPC_DEBUG0(D_EVENT, "Auto Configuration " 24971708Sstevel "(Connect/Configure) Started"); 24981708Sstevel 24991708Sstevel schpc_p->schpc_slot[slot].state &= 25001708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 25011708Sstevel 25021708Sstevel rval = schpc_connect((caddr_t)schpc_p, 25031708Sstevel schpc_p->schpc_slot[slot].slot_handle, 25041708Sstevel 0, 0); 25051708Sstevel 25061708Sstevel if (rval) { 25071708Sstevel cmn_err(CE_WARN, "schpc/Event Handler -" 25081708Sstevel " Can not connect"); 25091708Sstevel 25101708Sstevel mutex_enter(&schpc_p->schpc_mutex); 25111708Sstevel schpc_p->schpc_slot[slot].state &= 25121708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 25131708Sstevel cv_signal(&schpc_p->schpc_cv); 25141708Sstevel mutex_exit(&schpc_p->schpc_mutex); 25151708Sstevel 25161708Sstevel kmem_free(event, sizeof (pcimsg_t)); 25171708Sstevel return; 25181708Sstevel } 25191708Sstevel mutex_enter(&schpc_p->schpc_mutex); 25201708Sstevel while (schpc_p->schpc_slot[slot].state & 25211708Sstevel SCHPC_SLOTSTATE_EXECUTING) { 25221708Sstevel SCHPC_DEBUG0(D_EVENT, 25231708Sstevel "schpc_event_handler - " 25241708Sstevel "Slot is busy"); 25251708Sstevel cv_wait(&schpc_p->schpc_cv, 25261708Sstevel &schpc_p->schpc_mutex); 25271708Sstevel } 25281708Sstevel 25291708Sstevel schpc_p->schpc_slot[slot].state |= 25301708Sstevel SCHPC_SLOTSTATE_EXECUTING; 25311708Sstevel 25321708Sstevel mutex_exit(&schpc_p->schpc_mutex); 25331708Sstevel 25341708Sstevel hpc_slot_event_notify( 25351708Sstevel schpc_p->schpc_slot[slot].slot_handle, 25361708Sstevel HPC_EVENT_SLOT_CONFIGURE, 0); 25371708Sstevel } else { 25381708Sstevel schpc_setslotled(expander, board, slot, 25391708Sstevel SERVICE_LED_ON); 25401708Sstevel } 25411708Sstevel } 25421708Sstevel } 25431708Sstevel 25441708Sstevel /* ENUM# signal change event */ 25451708Sstevel 25461708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) { 25471708Sstevel /* 25481708Sstevel * ENUM should only be received to the adapter remove 25491708Sstevel * procedure. 25501708Sstevel */ 25511708Sstevel 25521708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted"); 25531708Sstevel 25541708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_FLASH); 25551708Sstevel 25561708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM; 25571708Sstevel 25581708Sstevel hpc_slot_event_notify( 25591708Sstevel schpc_p->schpc_slot[slot].slot_handle, 25601708Sstevel HPC_EVENT_SLOT_ENUM, 0); 25611708Sstevel } 25621708Sstevel 25631708Sstevel /* HEALTHY# signal change event */ 25641708Sstevel 25651708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) { 25661708Sstevel 25671708Sstevel if (!slotstatus.slot_HEALTHY) { 25681708Sstevel 25691708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED"); 25701708Sstevel 25711708Sstevel schpc_p->schpc_slot[slot].state &= 25721708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD; 25731708Sstevel 25741708Sstevel hpc_slot_event_notify( 25751708Sstevel schpc_p->schpc_slot[slot].slot_handle, 25761708Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0); 25771708Sstevel 25781708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 25791708Sstevel } else { 25801708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK"); 25811708Sstevel 25821708Sstevel schpc_p->schpc_slot[slot].state |= 25831708Sstevel SCHPC_SLOTSTATE_OCC_GOOD; 25841708Sstevel 25851708Sstevel hpc_slot_event_notify( 25861708Sstevel schpc_p->schpc_slot[slot].slot_handle, 25871708Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0); 25881708Sstevel 25891708Sstevel schpc_setslotled(expander, board, slot, 25901708Sstevel FAULT_LED_OFF); 25911708Sstevel } 25921708Sstevel } 25931708Sstevel 25941708Sstevel /* Good Power change event */ 25951708Sstevel 25961708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) { 25971708Sstevel if (slotstatus.slot_powergood == PCIMSG_ON) { 25981708Sstevel 25991708Sstevel SCHPC_DEBUG0(D_EVENT, 26001708Sstevel "Event Type: Slot Power Good Detected"); 26011708Sstevel 26021708Sstevel schpc_p->schpc_slot[slot].state |= 26031708Sstevel SCHPC_SLOTSTATE_OCC_GOOD; 26041708Sstevel 26051708Sstevel hpc_slot_event_notify( 26061708Sstevel schpc_p->schpc_slot[slot].slot_handle, 26071708Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0); 26081708Sstevel 26091708Sstevel schpc_setslotled(expander, board, slot, 26101708Sstevel FAULT_LED_OFF); 26111708Sstevel } else { 26121708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good " 26131708Sstevel "Detected"); 26141708Sstevel 26151708Sstevel if (schpc_p->schpc_slot[slot].state & 26161708Sstevel SCHPC_SLOTSTATE_CONNECTED) { 26171708Sstevel 26181708Sstevel SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: " 26191708Sstevel "power failed"); 26201708Sstevel 26211708Sstevel schpc_p->schpc_slot[slot].state &= 26221708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD; 26231708Sstevel 26241708Sstevel hpc_slot_event_notify( 26251708Sstevel schpc_p->schpc_slot[slot].slot_handle, 26261708Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0); 26271708Sstevel 26281708Sstevel schpc_setslotled(expander, board, slot, 26291708Sstevel FAULT_LED_ON); 26301708Sstevel } 26311708Sstevel } 26321708Sstevel } 26331708Sstevel 26341708Sstevel /* Power Fault change event */ 26351708Sstevel 26361708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) { 26371708Sstevel if (slotstatus.slot_powerfault == PCIMSG_ON) { 26381708Sstevel 26391708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault " 26401708Sstevel "Detected"); 26411708Sstevel 26421708Sstevel schpc_p->schpc_slot[slot].state &= 26431708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD; 26441708Sstevel 26451708Sstevel hpc_slot_event_notify( 26461708Sstevel schpc_p->schpc_slot[slot].slot_handle, 26471708Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0); 26481708Sstevel 26491708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON); 26501708Sstevel } else { 26511708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault " 26521708Sstevel "Cleared"); 26531708Sstevel 26541708Sstevel schpc_p->schpc_slot[slot].state |= 26551708Sstevel SCHPC_SLOTSTATE_OCC_GOOD; 26561708Sstevel 26571708Sstevel hpc_slot_event_notify( 26581708Sstevel schpc_p->schpc_slot[slot].slot_handle, 26591708Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0); 26601708Sstevel 26611708Sstevel schpc_setslotled(expander, board, slot, 26621708Sstevel FAULT_LED_OFF); 26631708Sstevel } 26641708Sstevel } 26651708Sstevel mutex_enter(&schpc_p->schpc_mutex); 26661708Sstevel schpc_p->schpc_slot[slot].state &= 26671708Sstevel ~SCHPC_SLOTSTATE_EXECUTING; 26681708Sstevel cv_signal(&schpc_p->schpc_cv); 26691708Sstevel mutex_exit(&schpc_p->schpc_mutex); 26701708Sstevel 26711708Sstevel kmem_free(event, sizeof (pcimsg_t)); 26721708Sstevel } 26731708Sstevel 26741708Sstevel 26751708Sstevel /* 26761708Sstevel * schpc_event_filter 26771708Sstevel * 26781708Sstevel * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the 26791708Sstevel * schpc_event_taskq for processing by the schpc_event_handler _if_ 26801708Sstevel * hotpluggable pci slots have been registered; otherwise, the 26811708Sstevel * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox 26821708Sstevel * open for future messages. 26831708Sstevel */ 26841708Sstevel static void 26851708Sstevel schpc_event_filter(pcimsg_t *pmsg) 26861708Sstevel { 26871708Sstevel if (slots_registered == B_TRUE) { 26881708Sstevel 26891708Sstevel pcimsg_t *pevent; 26901708Sstevel 26911708Sstevel /* 26921708Sstevel * If hotpluggable pci slots have been registered then enqueue 26931708Sstevel * the event onto the schpc_event_taskq for processing. 26941708Sstevel */ 26951708Sstevel 26961708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 26971708Sstevel "slots_registered = B_TRUE"); 26981708Sstevel 26991708Sstevel pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP); 27001708Sstevel bcopy(pmsg, pevent, sizeof (pcimsg_t)); 27011708Sstevel 27021708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 27031708Sstevel "event alloc'd"); 27041708Sstevel 27051708Sstevel if (taskq_dispatch(schpc_event_taskq, schpc_event_handler, 27061708Sstevel (void *)pevent, TQ_SLEEP) == NULL) { 27071708Sstevel cmn_err(CE_WARN, "schpc: schpc_event_filter - " 27081708Sstevel "taskq_dispatch failed to enqueue event"); 27091708Sstevel kmem_free(pevent, sizeof (pcimsg_t)); 27101708Sstevel return; 27111708Sstevel } 27121708Sstevel 27131708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 27141708Sstevel "event was taskq_dispatch'ed to schpc_event_handler"); 27151708Sstevel } else { 27161708Sstevel /* 27171708Sstevel * Oops, schpc received an event _before_ the slots have been 27181708Sstevel * registered. In that case there is no choice but to toss 27191708Sstevel * the event. 27201708Sstevel */ 27211708Sstevel cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding " 27221708Sstevel "premature event"); 27231708Sstevel } 27241708Sstevel } 27251708Sstevel 27261708Sstevel 27271708Sstevel /* 27281708Sstevel * schpc_msg_thread 27291708Sstevel * A stand-alone thread that monitors the incoming mailbox for 27301708Sstevel * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from 27311708Sstevel * the mailbox for processing. 27321708Sstevel * 27331708Sstevel * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the 27341708Sstevel * schpc_replylist, and the waiting thread is notified that its REPLY 27351708Sstevel * message has arrived; otherwise, if no REPLY match is found, then it is 27361708Sstevel * discarded. 27371708Sstevel * 27381708Sstevel * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed 27391708Sstevel * by the schpc_event_handler. 27401708Sstevel * 27411708Sstevel * The schpc_msg_thread is started in _init(). 27421708Sstevel */ 27431708Sstevel void 27441708Sstevel schpc_msg_thread(void) 27451708Sstevel { 27461708Sstevel int err; 27471708Sstevel uint32_t type; 27481708Sstevel uint32_t cmd; 27491708Sstevel uint64_t transid; 27501708Sstevel uint32_t length; 27511708Sstevel pcimsg_t msg; 27521708Sstevel 27531708Sstevel SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running"); 27541708Sstevel 27551708Sstevel /* CONSTCOND */ 27561708Sstevel while (1) { 27571708Sstevel 27581708Sstevel /* setup wildcard arguments */ 27591708Sstevel type = 0; 27601708Sstevel cmd = 0; 27611708Sstevel transid = 0; 27621708Sstevel length = sizeof (pcimsg_t); 27631708Sstevel bzero(&msg, sizeof (pcimsg_t)); 27641708Sstevel 27651708Sstevel err = mboxsc_getmsg(KEY_SCPC, &type, &cmd, 2766*7656SSherry.Moore@Sun.COM &transid, &length, (void *)&msg, 2767*7656SSherry.Moore@Sun.COM schpc_timeout_getmsg); 27681708Sstevel 27691708Sstevel if (err) { 27701708Sstevel switch (err) { 27711708Sstevel 27721708Sstevel /*FALLTHROUGH*/ 27731708Sstevel case ETIMEDOUT: 27741708Sstevel case EAGAIN: 27751708Sstevel continue; 27761708Sstevel 27771708Sstevel default: 27781708Sstevel /* 27791708Sstevel * unfortunately, we can't do very much here 27801708Sstevel * because we're wildcarding mboxsc_getmsg 27811708Sstevel * so if it encounters an error, we can't 27821708Sstevel * identify which transid it belongs to. 27831708Sstevel */ 27841708Sstevel cmn_err(CE_WARN, 27851708Sstevel "schpc - mboxsc_getmsg failed, err=0x%x", err); 27861708Sstevel delay(drv_usectohz(100000)); 27871708Sstevel continue; 27881708Sstevel } 27891708Sstevel } 27901708Sstevel 27911708Sstevel if (msg.pcimsg_revision != PCIMSG_REVISION) { 27921708Sstevel /* 27931708Sstevel * This version of the schpc driver only understands 27941708Sstevel * version 1.0 of the PCI Hot Plug Message format. 27951708Sstevel */ 27961708Sstevel cmn_err(CE_WARN, " schpc: schpc_msg_thread - " 27971708Sstevel "discarding event w/ unknown message version %x", 27981708Sstevel msg.pcimsg_revision); 27991708Sstevel continue; 28001708Sstevel } 28011708Sstevel 28021708Sstevel switch (type) { 28031708Sstevel 28041708Sstevel case MBOXSC_MSG_EVENT: 28051708Sstevel schpc_event_filter(&msg); 28061708Sstevel break; 28071708Sstevel 28081708Sstevel case MBOXSC_MSG_REPLY: 28091708Sstevel schpc_reply_handler(&msg, type, cmd, transid, length); 28101708Sstevel break; 28111708Sstevel 28121708Sstevel default: 28131708Sstevel cmn_err(CE_WARN, 28141708Sstevel "schpc - mboxsc_getmsg unknown msg" 28151708Sstevel " type=0x%x", type); 28161708Sstevel break; 28171708Sstevel } 28181708Sstevel } 28191708Sstevel /* this thread never exits */ 28201708Sstevel } 28211708Sstevel 28221708Sstevel 28231708Sstevel void 28241708Sstevel schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd, 28251708Sstevel uint64_t transid, uint32_t length) 28261708Sstevel { 28271708Sstevel schpc_replylist_t *entry; 28281708Sstevel 28291708Sstevel mutex_enter(&schpc_replylist_mutex); 28301708Sstevel entry = schpc_replylist_first; 28311708Sstevel while (entry != NULL) { 28321708Sstevel if (entry->transid == transid) { 28331708Sstevel break; 28341708Sstevel } else 28351708Sstevel entry = entry->next; 28361708Sstevel } 28371708Sstevel if (entry) { 28381708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 28391708Sstevel "schpc_reply_handler() - 0x%lx transid reply " 28401708Sstevel "received", transid); 28411708Sstevel 28421708Sstevel mutex_enter(&entry->reply_lock); 28431708Sstevel if (entry->reply_cexit == B_FALSE) { 28441708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 28451708Sstevel "schpc_reply_handler() - 0x%lx transid" 28461708Sstevel " cv_signal waiting thread", transid); 28471708Sstevel 28481708Sstevel /* 28491708Sstevel * emulate mboxsc_getmsg by copying the reply 28501708Sstevel */ 28511708Sstevel entry->type = type; 28521708Sstevel entry->cmd = cmd; 28531708Sstevel entry->transid = transid; 28541708Sstevel entry->length = length; 28551708Sstevel bcopy((caddr_t)pmsg, &entry->reply, length); 28561708Sstevel 28571708Sstevel /* reply was received */ 28581708Sstevel entry->reply_recvd = B_TRUE; 28591708Sstevel 28601708Sstevel /* 28611708Sstevel * wake up thread waiting for reply with transid 28621708Sstevel */ 28631708Sstevel cv_signal(&entry->reply_cv); 28641708Sstevel } 28651708Sstevel mutex_exit(&entry->reply_lock); 28661708Sstevel } else { 28671708Sstevel cmn_err(CE_WARN, "schpc - no match for transid 0x%lx", 28681708Sstevel transid); 28691708Sstevel } 28701708Sstevel mutex_exit(&schpc_replylist_mutex); 28711708Sstevel } 28721708Sstevel 28731708Sstevel 28741708Sstevel /* 28751708Sstevel * schpc_putrequest 28761708Sstevel * 28771708Sstevel * A wrapper around the synchronous call mboxsc_putmsg(). 28781708Sstevel */ 28791708Sstevel int 28801708Sstevel schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp, 28811708Sstevel uint32_t length, void *datap, clock_t timeout, 28821708Sstevel schpc_replylist_t **entryp) 28831708Sstevel { 28841708Sstevel int rval; 28851708Sstevel 28861708Sstevel /* add the request to replylist to keep track of outstanding requests */ 28871708Sstevel *entryp = schpc_replylist_link(cmd, *transidp, length); 28881708Sstevel 28891708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - " 28901708Sstevel "0x%lx transid mboxsc_putmsg called", *transidp); 28911708Sstevel 28921708Sstevel /* wait synchronously for request to be sent */ 28931708Sstevel rval = mboxsc_putmsg(key, type, cmd, transidp, length, 2894*7656SSherry.Moore@Sun.COM (void *)datap, timeout); 28951708Sstevel 28961708Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - " 28971708Sstevel "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval); 28981708Sstevel 28991708Sstevel /* if problem is encountered then remove the request from replylist */ 29001708Sstevel if (rval) 29011708Sstevel schpc_replylist_unlink(*entryp); 29021708Sstevel 29031708Sstevel return (rval); 29041708Sstevel } 29051708Sstevel 29061708Sstevel 29071708Sstevel /* 29081708Sstevel * schpc_getreply 29091708Sstevel * 29101708Sstevel * Wait for the schpc_msg_thread to respond that a matching reply has 29111708Sstevel * arrived; otherwise, timeout and remove the entry from the schpc_replylist. 29121708Sstevel */ 29131708Sstevel /*ARGSUSED*/ 29141708Sstevel int 29151708Sstevel schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp, 29161708Sstevel uint64_t *transidp, uint32_t *lengthp, void *datap, 29171708Sstevel clock_t timeout, schpc_replylist_t *listp) 29181708Sstevel { 29191708Sstevel int rc = 0; 29201708Sstevel 29211708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 29221708Sstevel "schpc_getreply() - 0x%lx transid waiting for reply", 29231708Sstevel *transidp); 29241708Sstevel 29251708Sstevel /* 29261708Sstevel * wait here until schpc_msg_thread because it's always 29271708Sstevel * looking for reply messages 29281708Sstevel */ 29291708Sstevel mutex_enter(&listp->reply_lock); 29301708Sstevel 29311708Sstevel while (listp->reply_recvd == B_FALSE) { 29321708Sstevel /* 29331708Sstevel * wait for reply or timeout 29341708Sstevel */ 29351708Sstevel rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock, 2936*7656SSherry.Moore@Sun.COM ddi_get_lbolt() + drv_usectohz(timeout * 1000)); 29371708Sstevel switch (rc) { 29381708Sstevel case -1: /* most likely a timeout, but check anyway */ 29391708Sstevel 29401708Sstevel /* message was received after all */ 29411708Sstevel if (listp->reply_recvd == B_TRUE) 29421708Sstevel break; 29431708Sstevel 29441708Sstevel /* no, it's really a timeout */ 29451708Sstevel listp->reply_cexit = B_TRUE; 29461708Sstevel mutex_exit(&listp->reply_lock); 29471708Sstevel cmn_err(CE_WARN, 29481708Sstevel "schpc - 0x%lx transid reply timed out", *transidp); 29491708Sstevel schpc_replylist_unlink(listp); 29501708Sstevel return (ETIMEDOUT); 29511708Sstevel 29521708Sstevel default: 29531708Sstevel break; 29541708Sstevel } 29551708Sstevel } 29561708Sstevel 29571708Sstevel *typep = listp->type; 29581708Sstevel *cmdp = listp->cmd; 29591708Sstevel *transidp = listp->transid; 29601708Sstevel *lengthp = listp->length; 29611708Sstevel bcopy((caddr_t)&listp->reply, datap, *lengthp); 29621708Sstevel mutex_exit(&listp->reply_lock); 29631708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 29641708Sstevel "schpc_getreply() - 0x%lx transid received", *transidp); 29651708Sstevel schpc_replylist_unlink(listp); 29661708Sstevel return (0); 29671708Sstevel } 29681708Sstevel 29691708Sstevel 29701708Sstevel /* 29711708Sstevel * schpc_replylist_unlink 29721708Sstevel * 29731708Sstevel * Deallocate a schpc_replylist_t element. 29741708Sstevel */ 29751708Sstevel void 29761708Sstevel schpc_replylist_unlink(schpc_replylist_t *entry) 29771708Sstevel { 29781708Sstevel #if DEBUG 29791708Sstevel schpc_replylist_t *dbg_entry; 29801708Sstevel #endif /* DEBUG */ 29811708Sstevel 29821708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 29831708Sstevel "schpc_replylist_unlink() - 0x%lx transid deleted from replylist", 29841708Sstevel entry->transid); 29851708Sstevel 29861708Sstevel mutex_enter(&schpc_replylist_mutex); 29871708Sstevel if (entry->prev) { 29881708Sstevel entry->prev->next = entry->next; 29891708Sstevel if (entry->next) 29901708Sstevel entry->next->prev = entry->prev; 29911708Sstevel } else { 29921708Sstevel schpc_replylist_first = entry->next; 29931708Sstevel if (entry->next) 29941708Sstevel entry->next->prev = NULL; 29951708Sstevel } 29961708Sstevel if (entry == schpc_replylist_last) { 29971708Sstevel schpc_replylist_last = entry->prev; 29981708Sstevel } 29991708Sstevel kmem_free(entry, sizeof (schpc_replylist_t)); 30001708Sstevel schpc_replylist_count--; 30011708Sstevel 30021708Sstevel #if DEBUG 30031708Sstevel if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) { 30041708Sstevel dbg_entry = schpc_replylist_first; 30051708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist " 30061708Sstevel "count = %d\n", schpc_replylist_count); 30071708Sstevel while (dbg_entry != NULL) { 30081708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - " 30091708Sstevel "0x%lx transid\n", dbg_entry->transid); 30101708Sstevel dbg_entry = dbg_entry->next; 30111708Sstevel } 30121708Sstevel } 30131708Sstevel #endif /* DEBUG */ 30141708Sstevel 30151708Sstevel mutex_exit(&schpc_replylist_mutex); 30161708Sstevel } 30171708Sstevel 30181708Sstevel 30191708Sstevel /* 30201708Sstevel * schpc_replylist_link 30211708Sstevel * 30221708Sstevel * Allocate and initialize a schpc_replylist_t element. 30231708Sstevel */ 30241708Sstevel schpc_replylist_t * 30251708Sstevel schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length) 30261708Sstevel { 30271708Sstevel schpc_replylist_t *entry; 30281708Sstevel #if DEBUG 30291708Sstevel schpc_replylist_t *dbg_entry; 30301708Sstevel #endif /* DEBUG */ 30311708Sstevel 30321708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 30331708Sstevel "schpc_replylist_link() - 0x%lx transid inserting into replylist", 30341708Sstevel transid); 30351708Sstevel 30361708Sstevel entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP); 30371708Sstevel mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL); 30381708Sstevel cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL); 30391708Sstevel entry->type = MBOXSC_MSG_REPLY; 30401708Sstevel entry->cmd = cmd; 30411708Sstevel entry->transid = transid; 30421708Sstevel entry->length = length; 30431708Sstevel entry->reply_recvd = B_FALSE; 30441708Sstevel entry->reply_cexit = B_FALSE; 30451708Sstevel 30461708Sstevel mutex_enter(&schpc_replylist_mutex); 30471708Sstevel if (schpc_replylist_last) { 30481708Sstevel entry->prev = schpc_replylist_last; 30491708Sstevel schpc_replylist_last->next = entry; 30501708Sstevel schpc_replylist_last = entry; 30511708Sstevel } else { 30521708Sstevel schpc_replylist_last = schpc_replylist_first = entry; 30531708Sstevel } 30541708Sstevel 30551708Sstevel schpc_replylist_count++; 30561708Sstevel 30571708Sstevel #if DEBUG 30581708Sstevel if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) { 30591708Sstevel dbg_entry = schpc_replylist_first; 30601708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist " 30611708Sstevel "count = %d\n", schpc_replylist_count); 30621708Sstevel while (dbg_entry != NULL) { 30631708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_link() - " 30641708Sstevel "0x%lx transid\n", dbg_entry->transid); 30651708Sstevel dbg_entry = dbg_entry->next; 30661708Sstevel } 30671708Sstevel } 30681708Sstevel #endif /* DEBUG */ 30691708Sstevel 30701708Sstevel mutex_exit(&schpc_replylist_mutex); 30711708Sstevel 30721708Sstevel return (entry); 30731708Sstevel } 30741708Sstevel 30751708Sstevel 30761708Sstevel /* 30771708Sstevel * schpc_getslotstatus 30781708Sstevel * 30791708Sstevel * Issues a Get Slot Status command to the System Controller 30801708Sstevel * for a specific slot. 30811708Sstevel */ 30821708Sstevel static int 30831708Sstevel schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot, 30841708Sstevel pci_getslot_t *slotstatus) 30851708Sstevel { 30861708Sstevel pcimsg_t request; 30871708Sstevel pcimsg_t reply; 30881708Sstevel int rval; 30891708Sstevel uint32_t type, cmd, length; 30901708Sstevel uint64_t transid; 30911708Sstevel schpc_replylist_t *entry; 30921708Sstevel 30931708Sstevel SCHPC_DEBUG4(D_GETSLOTSTATUS, 30941708Sstevel "schpc_getslotstatus(expander=%d board=%d " 30951708Sstevel "slot=%d slotstatus=0x%p", expander, board, 30961708Sstevel SCHPC_SLOT_NUM(slot), slotstatus); 30971708Sstevel 30981708Sstevel if (schpc_p == NULL) { 30991708Sstevel return (1); 31001708Sstevel } 31011708Sstevel 31021708Sstevel bzero(&request, sizeof (pcimsg_t)); 31031708Sstevel 31041708Sstevel request.pcimsg_node = expander; 31051708Sstevel request.pcimsg_board = board; 31061708Sstevel request.pcimsg_slot = SCHPC_SLOT_NUM(slot); 31071708Sstevel request.pcimsg_revision = PCIMSG_REVISION; 31081708Sstevel request.pcimsg_command = PCIMSG_GETSLOTSTATUS; 31091708Sstevel 31101708Sstevel type = MBOXSC_MSG_REQUEST; 31111708Sstevel cmd = PCIMSG_GETSLOTSTATUS; 31121708Sstevel transid = schpc_gettransid(schpc_p, slot); 31131708Sstevel length = sizeof (pcimsg_t); 31141708Sstevel 31151708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 31161708Sstevel "0x%lx transid schpc_putrequest called", transid); 31171708Sstevel 31181708Sstevel rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length, 31191708Sstevel (void *)&request, schpc_timeout_putmsg, &entry); 31201708Sstevel 31211708Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 31221708Sstevel "0x%lx transid schpc_putrequest returned 0x%x", transid, rval); 31231708Sstevel 31241708Sstevel if (rval) { 31251708Sstevel return (rval); 31261708Sstevel } 31271708Sstevel 31281708Sstevel bzero(&reply, sizeof (pcimsg_t)); 31291708Sstevel type = MBOXSC_MSG_REPLY; 31301708Sstevel 31311708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 31321708Sstevel "0x%lx transid schpc_getreply called", transid); 31331708Sstevel 31341708Sstevel rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length, 3135*7656SSherry.Moore@Sun.COM (void *)&reply, schpc_timeout_getmsg, entry); 31361708Sstevel 31371708Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 31381708Sstevel "0x%lx transid schpc_getreply returned 0x%x", transid, rval); 31391708Sstevel 31401708Sstevel if (rval == 0) { 31411708Sstevel *slotstatus = reply.pcimsg_type.pcimsg_getslot; 31421708Sstevel 31431708Sstevel SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()"); 31441708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_power_on %x", 31451708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_power_on); 31461708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powergood %x", 31471708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_powergood); 31481708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powerfault %x", 31491708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_powerfault); 31501708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_empty %x", 31511708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_empty); 31521708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_cap %x", 31531708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_freq_cap); 31541708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_setting %x", 31551708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_freq_setting); 31561708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_condition %x", 31571708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_condition); 31581708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_HEALTHY %x", 31591708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY); 31601708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_ENUM %x", 31611708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_ENUM); 31621708Sstevel } 31631708Sstevel 31641708Sstevel return (rval); 31651708Sstevel } 31661708Sstevel 31671708Sstevel 31681708Sstevel /* 31691708Sstevel * schpc_setslotstatus 31701708Sstevel * 31711708Sstevel * Issues a Set Slot Status command to the System Controller 31721708Sstevel * for a specific slot. 31731708Sstevel */ 31741708Sstevel static int 31751708Sstevel schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot, 31761708Sstevel pci_setslot_t *slotstatus) 31771708Sstevel { 31781708Sstevel pcimsg_t request; 31791708Sstevel pcimsg_t reply; 31801708Sstevel int rval; 31811708Sstevel uint32_t type, cmd, length; 31821708Sstevel uint64_t transid; 31831708Sstevel schpc_replylist_t *entry; 31841708Sstevel 31851708Sstevel SCHPC_DEBUG4(D_SETSLOTSTATUS, 31861708Sstevel "schpc_setslotstatus(expander=%d board=%d " 31871708Sstevel "slot=%d slotstatus=0x%p", expander, board, 31881708Sstevel SCHPC_SLOT_NUM(slot), slotstatus); 31891708Sstevel 31901708Sstevel bzero(&request, sizeof (pcimsg_t)); 31911708Sstevel 31921708Sstevel if (schpc_p == NULL) { 31931708Sstevel return (1); 31941708Sstevel } 31951708Sstevel 31961708Sstevel request.pcimsg_node = expander; 31971708Sstevel request.pcimsg_board = board; 31981708Sstevel request.pcimsg_slot = SCHPC_SLOT_NUM(slot); 31991708Sstevel request.pcimsg_revision = PCIMSG_REVISION; 32001708Sstevel request.pcimsg_command = PCIMSG_SETSLOTSTATUS; 32011708Sstevel 32021708Sstevel request.pcimsg_type.pcimsg_setslot = *slotstatus; 32031708Sstevel 32041708Sstevel SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change"); 32051708Sstevel SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d", 32061708Sstevel slotstatus->slot_led_power, 32071708Sstevel slotstatus->slot_led_service, 32081708Sstevel slotstatus->slot_led_fault); 32091708Sstevel 32101708Sstevel type = MBOXSC_MSG_REQUEST; 32111708Sstevel cmd = PCIMSG_SETSLOTSTATUS; 32121708Sstevel transid = schpc_gettransid(schpc_p, slot); 32131708Sstevel length = sizeof (pcimsg_t); 32141708Sstevel 32151708Sstevel SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 32161708Sstevel "0x%lx transid schpc_putrequest called", transid); 32171708Sstevel 32181708Sstevel rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length, 32191708Sstevel (void *)&request, schpc_timeout_putmsg, &entry); 32201708Sstevel 32211708Sstevel SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 32221708Sstevel "0x%lx transid schpc_putrequest returned 0x%x", transid, rval); 32231708Sstevel 32241708Sstevel if (rval) { 32251708Sstevel return (rval); 32261708Sstevel } 32271708Sstevel 32281708Sstevel bzero(&reply, sizeof (pcimsg_t)); 32291708Sstevel type = MBOXSC_MSG_REPLY; 32301708Sstevel 32311708Sstevel SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 32321708Sstevel "0x%lx transid schpc_getreply called", transid); 32331708Sstevel 32341708Sstevel rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length, 3235*7656SSherry.Moore@Sun.COM (void *)&reply, schpc_timeout_getmsg, entry); 32361708Sstevel 32371708Sstevel SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 32381708Sstevel "0x%lx transid schpc_getreply returned 0x%x", transid, rval); 32391708Sstevel 32401708Sstevel if (rval == 0) { 32411708Sstevel slotstatus->slot_replystatus = 32421708Sstevel reply.pcimsg_type.pcimsg_setslot.slot_replystatus; 32431708Sstevel } 32441708Sstevel 32451708Sstevel return (rval); 32461708Sstevel } 32471708Sstevel 32481708Sstevel /* 32491708Sstevel * schpc_setslotled 32501708Sstevel * 32511708Sstevel * Changes the attention indicators for a given slot. 32521708Sstevel */ 32531708Sstevel static void 32541708Sstevel schpc_setslotled(int expander, int board, int slot, uint32_t led_state) 32551708Sstevel { 32561708Sstevel 32571708Sstevel pci_setslot_t setslot; 32581708Sstevel 32591708Sstevel if (schpc_p == NULL) { 32601708Sstevel return; 32611708Sstevel } 32621708Sstevel 32631708Sstevel schpc_init_setslot_message(&setslot); 32641708Sstevel 32651708Sstevel if (led_state & POWER_LED_ON) { 32661708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON; 32671708Sstevel } 32681708Sstevel if (led_state & POWER_LED_OFF) { 32691708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF; 32701708Sstevel } 32711708Sstevel if (led_state & POWER_LED_FLASH) { 32721708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH; 32731708Sstevel } 32741708Sstevel if (led_state & SERVICE_LED_ON) { 32751708Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON; 32761708Sstevel } 32771708Sstevel if (led_state & SERVICE_LED_OFF) { 32781708Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF; 32791708Sstevel } 32801708Sstevel if (led_state & SERVICE_LED_FLASH) { 32811708Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH; 32821708Sstevel } 32831708Sstevel if (led_state & FAULT_LED_ON) { 32841708Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON; 32851708Sstevel } 32861708Sstevel if (led_state & FAULT_LED_OFF) { 32871708Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF; 32881708Sstevel } 32891708Sstevel if (led_state & FAULT_LED_FLASH) { 32901708Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH; 32911708Sstevel } 32921708Sstevel 32931708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) { 32941708Sstevel case PCIMSG_LED_ON: 32951708Sstevel setslot.slot_led_power = PCIMSG_LED_ON; 32961708Sstevel break; 32971708Sstevel case PCIMSG_LED_OFF: 32981708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF; 32991708Sstevel break; 33001708Sstevel case PCIMSG_LED_FLASH: 33011708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH; 33021708Sstevel break; 33031708Sstevel } 33041708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) { 33051708Sstevel case PCIMSG_LED_ON: 33061708Sstevel setslot.slot_led_service = PCIMSG_LED_ON; 33071708Sstevel break; 33081708Sstevel case PCIMSG_LED_OFF: 33091708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF; 33101708Sstevel break; 33111708Sstevel case PCIMSG_LED_FLASH: 33121708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH; 33131708Sstevel break; 33141708Sstevel } 33151708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) { 33161708Sstevel case PCIMSG_LED_ON: 33171708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON; 33181708Sstevel break; 33191708Sstevel case PCIMSG_LED_OFF: 33201708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF; 33211708Sstevel break; 33221708Sstevel case PCIMSG_LED_FLASH: 33231708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; 33241708Sstevel break; 33251708Sstevel } 33261708Sstevel 33271708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot); 33281708Sstevel } 33291708Sstevel 33301708Sstevel /* 33311708Sstevel * schpc_init_setslot_message 33321708Sstevel * 33331708Sstevel * Initialize Set Slot Message before using it. 33341708Sstevel */ 33351708Sstevel static void 33361708Sstevel schpc_init_setslot_message(pci_setslot_t *setslot) 33371708Sstevel { 33381708Sstevel /* 33391708Sstevel * Initialize Set Slot Command. 33401708Sstevel */ 33411708Sstevel setslot->slot_power_on = PCIMSG_OFF; 33421708Sstevel setslot->slot_power_off = PCIMSG_OFF; 33431708Sstevel setslot->slot_led_power = PCIMSG_LED_OFF; 33441708Sstevel setslot->slot_led_service = PCIMSG_LED_OFF; 33451708Sstevel setslot->slot_led_fault = PCIMSG_LED_OFF; 33461708Sstevel setslot->slot_disable_ENUM = PCIMSG_OFF; 33471708Sstevel setslot->slot_enable_ENUM = PCIMSG_OFF; 33481708Sstevel setslot->slot_disable_HEALTHY = PCIMSG_OFF; 33491708Sstevel setslot->slot_enable_HEALTHY = PCIMSG_OFF; 33501708Sstevel } 33511708Sstevel 33521708Sstevel /* 33531708Sstevel * schpc_gettransid 33541708Sstevel * 33551708Sstevel * Builds a unique transaction ID. 33561708Sstevel */ 33571708Sstevel static uint64_t 33581708Sstevel schpc_gettransid(schpc_t *schpc_p, int slot) 33591708Sstevel { 33601708Sstevel uint64_t trans_id; 33611708Sstevel 33621708Sstevel mutex_enter(&schpc_p->schpc_mutex); 33631708Sstevel 33641708Sstevel if (++schpc_p->schpc_transid == 0) 33651708Sstevel schpc_p->schpc_transid = 1; 33661708Sstevel 33671708Sstevel trans_id = (schpc_p->schpc_slot[slot].expander<<24) | 33681708Sstevel (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid; 33691708Sstevel 33701708Sstevel mutex_exit(&schpc_p->schpc_mutex); 33711708Sstevel 33721708Sstevel SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning", 33731708Sstevel trans_id); 33741708Sstevel 33751708Sstevel return (trans_id); 33761708Sstevel } 33771708Sstevel 33781708Sstevel /* 33791708Sstevel * schpc_slot_get_index 33801708Sstevel * 33811708Sstevel * get slot table index from the slot handle 33821708Sstevel */ 33831708Sstevel static int 33841708Sstevel schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot) 33851708Sstevel { 33861708Sstevel int i; 33871708Sstevel int rval = -1; 33881708Sstevel 33891708Sstevel ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex)); 33901708Sstevel 33911708Sstevel for (i = 0; i < schpc_p->schpc_number_of_slots; i++) { 33921708Sstevel if (schpc_p->schpc_slot[i].slot_handle == slot) 33931708Sstevel return (i); 33941708Sstevel } 33951708Sstevel 33961708Sstevel return (rval); 33971708Sstevel } 33981708Sstevel 33991708Sstevel /* 34001708Sstevel * schpc_register_all_slots 34011708Sstevel * 34021708Sstevel * Search device tree for pci nodes and register attachment points 34031708Sstevel * for all hot pluggable slots. 34041708Sstevel */ 34051708Sstevel /*ARGSUSED*/ 34061708Sstevel static void 34071708Sstevel schpc_register_all_slots(schpc_t *schpc_p) 34081708Sstevel { 34091708Sstevel int slot = 0; 34101708Sstevel char caddr[64]; 34111708Sstevel dev_info_t *pci_dip = NULL; 34121708Sstevel find_dev_t find_dev; 34131708Sstevel int leaf, schizo, expander, portid, offset; 34141708Sstevel 34151708Sstevel SCHPC_DEBUG1(D_ATTACH, 34161708Sstevel "schpc_register_all_slots(schpc_p=%p)", schpc_p); 34171708Sstevel 34181708Sstevel /* 34191708Sstevel * Allow the event_handler to start processing unsolicited 34201708Sstevel * events now that slots are about to be registered. 34211708Sstevel */ 34221708Sstevel slots_registered = B_TRUE; 34231708Sstevel 34241708Sstevel for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) { 34251708Sstevel 34261708Sstevel leaf = SCHPC_SLOT_LEAF(slot); 34271708Sstevel schizo = SCHPC_SLOT_SCHIZO(slot); 34281708Sstevel expander = SCHPC_SLOT_EXPANDER(slot); 34291708Sstevel 34301708Sstevel if (schizo == 0) 34311708Sstevel portid = 0x1c; 34321708Sstevel else 34331708Sstevel portid = 0x1d; 34341708Sstevel 34351708Sstevel if (leaf == 0) 34361708Sstevel offset = 0x600000; 34371708Sstevel else 34381708Sstevel offset = 0x700000; 34391708Sstevel 34401708Sstevel portid = (expander << 5) | portid; 34411708Sstevel 34421708Sstevel (void) sprintf(caddr, "%x,%x", portid, offset); 34431708Sstevel 34441708Sstevel SCHPC_DEBUG3(D_ATTACH, 34451708Sstevel "schpc_register_all_slots: searching for pci@%s" 34461708Sstevel " schizo=%d, leaf=%d", caddr, schizo, leaf); 34471708Sstevel 34481708Sstevel find_dev.cname = "pci"; 34491708Sstevel find_dev.caddr = caddr; 34501708Sstevel find_dev.schizo = schizo; 34511708Sstevel find_dev.leaf = leaf; 34521708Sstevel find_dev.dip = NULL; 34531708Sstevel 34541708Sstevel /* root node doesn't have to be held */ 34551708Sstevel ddi_walk_devs(ddi_root_node(), schpc_match_dip, 34561708Sstevel &find_dev); 34571708Sstevel 34581708Sstevel pci_dip = find_dev.dip; 34591708Sstevel 34601708Sstevel if (pci_dip == NULL) { 34611708Sstevel 34621708Sstevel SCHPC_DEBUG1(D_ATTACH, 34631708Sstevel "schpc_register_all_slots: pci@%s NOT FOUND", 34641708Sstevel caddr); 34651708Sstevel 34661708Sstevel continue; 34671708Sstevel } 34681708Sstevel 34691708Sstevel SCHPC_DEBUG2(D_ATTACH, 34701708Sstevel "schpc_register_all_slots: pci@%s FOUND dip=0x%p", 34711708Sstevel caddr, pci_dip); 34721708Sstevel 34731708Sstevel (void) schpc_add_pci(pci_dip); 34741708Sstevel 34751708Sstevel /* 34761708Sstevel * Release hold acquired in schpc_match_dip() 34771708Sstevel */ 34781708Sstevel ndi_rele_devi(pci_dip); 34791708Sstevel } 34801708Sstevel 34811708Sstevel SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit"); 34821708Sstevel 34831708Sstevel thread_exit(); 34841708Sstevel } 34851708Sstevel 34861708Sstevel /* 34871708Sstevel * schpc_add_pci 34881708Sstevel * 34891708Sstevel * Routine to add attachments points associated with a pci node. 34901708Sstevel * Can be call externally by DR when configuring a PCI I/O Board. 34911708Sstevel */ 34921708Sstevel int 34931708Sstevel schpc_add_pci(dev_info_t *bdip) 34941708Sstevel { 34951708Sstevel int portid; 34961708Sstevel int expander, board, schizo, leaf, slot, status; 34971708Sstevel char ap_id[MAXNAMELEN]; 34981708Sstevel char caddr[64]; 34991708Sstevel char *naddr; 35001708Sstevel hpc_slot_info_t slot_info; 35011708Sstevel hpc_slot_ops_t *slot_ops; 35021708Sstevel dev_info_t *sdip = bdip; 35031708Sstevel 35041708Sstevel SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", sdip); 35051708Sstevel 35061708Sstevel if (schpc_p == NULL) { 35071708Sstevel /* 35081708Sstevel * The schpc driver has not been attached yet. 35091708Sstevel */ 35101708Sstevel return (DDI_SUCCESS); 35111708Sstevel } 35121708Sstevel 35131708Sstevel if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) { 35141708Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n", sdip); 35151708Sstevel return (DDI_FAILURE); 35161708Sstevel } 35171708Sstevel 35181708Sstevel expander = schpc_getexpander(sdip); 35191708Sstevel board = schpc_getboard(sdip); 35201708Sstevel 35211708Sstevel switch (portid & 0x1f) { 35221708Sstevel 35231708Sstevel case 0x1c: 35241708Sstevel schizo = 0; 35251708Sstevel break; 35261708Sstevel case 0x1d: 35271708Sstevel schizo = 1; 35281708Sstevel break; 35291708Sstevel default: 35301708Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 35311708Sstevel "Invalid pci portid 0x%x\n", sdip, portid); 35321708Sstevel return (DDI_FAILURE); 35331708Sstevel } 35341708Sstevel 35351708Sstevel naddr = ddi_get_name_addr(sdip); 35361708Sstevel if (naddr == NULL) { 35371708Sstevel SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr" 35381708Sstevel "(0x%p) returns null", sdip); 35391708Sstevel return (DDI_FAILURE); 35401708Sstevel } 35411708Sstevel 35421708Sstevel (void) sprintf(caddr, "%x,600000", portid); 35431708Sstevel 35441708Sstevel if (strcmp(caddr, naddr) == 0) { 35451708Sstevel leaf = 0; 35461708Sstevel } else { 35471708Sstevel (void) sprintf(caddr, "%x,700000", portid); 35481708Sstevel if (strcmp(caddr, naddr) == 0) { 35491708Sstevel char *name; 35501708Sstevel 35511708Sstevel leaf = 1; 35521708Sstevel name = ddi_binding_name(sdip); 35531708Sstevel if ((strcmp(name, "pci108e,8002") == 0) && 3554*7656SSherry.Moore@Sun.COM (schizo == 0)) { 35551708Sstevel int circ; 35561708Sstevel dev_info_t *cdip; 35571708Sstevel /* 35581708Sstevel * XMITS 0 Leaf B will have its hot 35591708Sstevel * pluggable slot off a PCI-PCI bridge, 35601708Sstevel * which is the only child. 35611708Sstevel */ 35621708Sstevel ndi_devi_enter(sdip, &circ); 35631708Sstevel cdip = ddi_get_child(sdip); 35641708Sstevel if (cdip == NULL) { 35651708Sstevel cmn_err(CE_WARN, 3566*7656SSherry.Moore@Sun.COM "schpc_add_pci(dip=0x%p) - " 3567*7656SSherry.Moore@Sun.COM "Invalid pci name addr %s\n", 3568*7656SSherry.Moore@Sun.COM sdip, naddr); 35691708Sstevel ndi_devi_exit(sdip, circ); 35701708Sstevel return (DDI_FAILURE); 35711708Sstevel } 35721708Sstevel ndi_devi_exit(sdip, circ); 35731708Sstevel sdip = cdip; 35741708Sstevel } 35751708Sstevel } else { 35761708Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 35771708Sstevel "Invalid pci name addr %s\n", sdip, naddr); 35781708Sstevel return (DDI_FAILURE); 35791708Sstevel } 35801708Sstevel } 35811708Sstevel 35821708Sstevel /* create a slot table index */ 35831708Sstevel slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf); 35841708Sstevel 35851708Sstevel if (schpc_p->schpc_slot[slot].devi) { 35861708Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 35871708Sstevel "pci node already registered\n", sdip); 35881708Sstevel return (DDI_FAILURE); 35891708Sstevel } 35901708Sstevel 35911708Sstevel /* 35921708Sstevel * There is no need to hold the dip while saving it in 35931708Sstevel * the devi field below. The dip is never dereferenced. 35941708Sstevel * (If that changes, this code should be modified). 35951708Sstevel * We want to avoid holding the dip here because it 35961708Sstevel * prevents DR. 35971708Sstevel * 35981708Sstevel * NOTE: Even though the slot on XMITS0 Leaf-B 35991708Sstevel * is connected to a pci_pci bridge, we will be saving 36001708Sstevel * the busdip in this datastructure. This will make 36011708Sstevel * it easier to identify the dip being removed in 36021708Sstevel * schpc_remove_pci(). 36031708Sstevel */ 36041708Sstevel schpc_p->schpc_slot[slot].devi = bdip; 36051708Sstevel 36061708Sstevel schpc_p->schpc_slot[slot].expander = expander; 36071708Sstevel schpc_p->schpc_slot[slot].board = board; 36081708Sstevel schpc_p->schpc_slot[slot].schizo = schizo; 36091708Sstevel schpc_p->schpc_slot[slot].leaf = leaf; 36101708Sstevel 36111708Sstevel /* 36121708Sstevel * Starcat PCI slots are always PCI device 1. 36131708Sstevel */ 36141708Sstevel schpc_p->schpc_slot[slot].pci_id = 1; 36151708Sstevel 36161708Sstevel schpc_buildapid(sdip, slot, (char *)&ap_id); 36171708Sstevel 36181708Sstevel (void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id); 36191708Sstevel 36201708Sstevel /* safe to call ddi_pathname(): bdip is held */ 36211708Sstevel (void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path); 36221708Sstevel 36231708Sstevel status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot)); 36241708Sstevel switch (status) { 36251708Sstevel case RSV_UNKNOWN: 36261708Sstevel case RSV_PRESENT: 36271708Sstevel case RSV_MISS: 36281708Sstevel case RSV_PASS: 36291708Sstevel case RSV_EMPTY_CASSETTE: 36301708Sstevel 36311708Sstevel /* 36321708Sstevel * Test the condition of the slot. 36331708Sstevel */ 36341708Sstevel schpc_test((caddr_t)schpc_p, slot, 0, 0); 36351708Sstevel break; 36361708Sstevel case RSV_BLACK: 36371708Sstevel schpc_p->schpc_slot[slot].state = 0; 36381708Sstevel cmn_err(CE_WARN, "schpc: PCI card blacklisted: " 36391708Sstevel "expander=%d board=%d slot=%d\n", expander, 36401708Sstevel board, SCHPC_SLOT_NUM(slot)); 36411708Sstevel break; 36421708Sstevel default: 36431708Sstevel schpc_p->schpc_slot[slot].state = 0; 36441708Sstevel cmn_err(CE_WARN, "schpc: PCI card failed by POST: " 36451708Sstevel "expander=%d board=%d slot=%d failure=0x%x\n", 36461708Sstevel expander, board, SCHPC_SLOT_NUM(slot), status); 36471708Sstevel break; 36481708Sstevel } 36491708Sstevel 36501708Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) { 36511708Sstevel 36521708Sstevel /* allocate slot ops */ 36531708Sstevel 36541708Sstevel slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 36551708Sstevel schpc_p->schpc_slot[slot].slot_ops = slot_ops; 36561708Sstevel 36571708Sstevel /* 36581708Sstevel * Default to Autoconfiguration disabled. 36591708Sstevel */ 36601708Sstevel schpc_p->schpc_slot[slot].state &= 36611708Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 36621708Sstevel 36631708Sstevel /* 36641708Sstevel * Fill in the slot information structure that 36651708Sstevel * describes the slot. 36661708Sstevel */ 36671708Sstevel slot_info.version = HPC_SLOT_OPS_VERSION; 36681708Sstevel 36691708Sstevel if (schpc_p->schpc_hotplugmodel == 36701708Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) 36711708Sstevel slot_info.slot_type = HPC_SLOT_TYPE_PCI; 36721708Sstevel else 36731708Sstevel slot_info.slot_type = HPC_SLOT_TYPE_CPCI; 36741708Sstevel 36751708Sstevel slot_info.slot.pci.device_number = 36761708Sstevel schpc_p->schpc_slot[slot].pci_id; 36771708Sstevel 36781708Sstevel slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS; 36791708Sstevel 36801708Sstevel if (schpc_use_legacy_apid) 36811708Sstevel slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE; 36821708Sstevel else 36831708Sstevel slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE | 36841708Sstevel HPC_SLOT_CREATE_DEVLINK; 36851708Sstevel 36861708Sstevel strcpy(slot_info.slot.pci.slot_logical_name, 36871708Sstevel schpc_p->schpc_slot[slot].ap_id); 36881708Sstevel 36891708Sstevel /* 36901708Sstevel * Fill in the slot ops structure that tells 36911708Sstevel * the Hot Plug Services what function we 36921708Sstevel * support. 36931708Sstevel */ 36941708Sstevel slot_ops->hpc_version = HPC_SLOT_OPS_VERSION; 36951708Sstevel if (schpc_p->schpc_hotplugmodel == 36961708Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) { 36971708Sstevel slot_ops->hpc_op_connect = schpc_connect; 36981708Sstevel slot_ops->hpc_op_disconnect = schpc_disconnect; 36991708Sstevel slot_ops->hpc_op_insert = NULL; 37001708Sstevel slot_ops->hpc_op_remove = NULL; 37011708Sstevel slot_ops->hpc_op_control = schpc_pci_control; 37021708Sstevel } else { 37031708Sstevel slot_ops->hpc_op_connect = NULL; 37041708Sstevel slot_ops->hpc_op_disconnect = NULL; 37051708Sstevel slot_ops->hpc_op_insert = NULL; 37061708Sstevel slot_ops->hpc_op_remove = NULL; 37071708Sstevel slot_ops->hpc_op_control = schpc_cpci_control; 37081708Sstevel } 37091708Sstevel 37101708Sstevel SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC " 37111708Sstevel "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s", 37121708Sstevel schpc_p->schpc_slot[slot].nexus_path, 37131708Sstevel schpc_p, SCHPC_SLOT_NUM(slot), 37141708Sstevel slot_info.slot.pci.device_number, 37151708Sstevel slot_info.slot.pci.slot_logical_name); 37161708Sstevel 37171708Sstevel if (hpc_slot_register(schpc_p->schpc_devi, 37181708Sstevel schpc_p->schpc_slot[slot].nexus_path, &slot_info, 37191708Sstevel &schpc_p->schpc_slot[slot].slot_handle, 37201708Sstevel slot_ops, (caddr_t)schpc_p, 0) != 0) { 37211708Sstevel 37221708Sstevel /* 37231708Sstevel * If the slot can not be registered, 37241708Sstevel * then the slot_ops need to be freed. 37251708Sstevel */ 37261708Sstevel cmn_err(CE_WARN, "schpc%d Unable to Register " 37271708Sstevel "Slot %s", schpc_p->schpc_instance, 37281708Sstevel slot_info.slot.pci.slot_logical_name); 37291708Sstevel 37301708Sstevel hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops); 37311708Sstevel 37321708Sstevel schpc_p->schpc_slot[slot].slot_ops = NULL; 37331708Sstevel 37341708Sstevel return (DDI_FAILURE); 37351708Sstevel } 37361708Sstevel 37371708Sstevel /* 37381708Sstevel * We are ready to take commands from the HPC Services. 37391708Sstevel */ 37401708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED; 37411708Sstevel } 37421708Sstevel 37431708Sstevel return (DDI_SUCCESS); 37441708Sstevel } 37451708Sstevel 37461708Sstevel /* 37471708Sstevel * schpc_remove_pci 37481708Sstevel * 37491708Sstevel * Routine to remove attachments points associated with a pci node. 37501708Sstevel * Can be call externally by DR when unconfiguring a PCI I/O Board. 37511708Sstevel */ 37521708Sstevel int 37531708Sstevel schpc_remove_pci(dev_info_t *dip) 37541708Sstevel { 37551708Sstevel int slot; 37561708Sstevel 37571708Sstevel SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", dip); 37581708Sstevel 37591708Sstevel if (schpc_p == NULL) { 37601708Sstevel /* 37611708Sstevel * The schpc driver has not been attached yet. 37621708Sstevel */ 37631708Sstevel return (DDI_SUCCESS); 37641708Sstevel } 37651708Sstevel 37661708Sstevel for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) { 37671708Sstevel if (schpc_p->schpc_slot[slot].devi == dip) { 37681708Sstevel 37691708Sstevel if (schpc_p->schpc_slot[slot].slot_ops) { 37701708Sstevel if (hpc_slot_unregister( 37711708Sstevel &schpc_p->schpc_slot[slot].slot_handle)) { 37721708Sstevel cmn_err(CE_WARN, 37731708Sstevel "schpc_remove_pci(dip=0x%p) - " 37741708Sstevel "unable to unregister pci slots\n", 37751708Sstevel dip); 37761708Sstevel return (DDI_FAILURE); 37771708Sstevel } else { 37781708Sstevel hpc_free_slot_ops( 37791708Sstevel schpc_p->schpc_slot[slot].slot_ops); 37801708Sstevel 37811708Sstevel schpc_p->schpc_slot[slot].slot_ops = 37821708Sstevel NULL; 37831708Sstevel 37841708Sstevel schpc_p->schpc_slot[slot].devi = NULL; 37851708Sstevel 37861708Sstevel return (DDI_SUCCESS); 37871708Sstevel } 37881708Sstevel } else { 37891708Sstevel schpc_p->schpc_slot[slot].devi = NULL; 37901708Sstevel 37911708Sstevel return (DDI_SUCCESS); 37921708Sstevel } 37931708Sstevel } 37941708Sstevel } 37951708Sstevel 37961708Sstevel cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) " 37971708Sstevel "dip not found\n", dip); 37981708Sstevel 37991708Sstevel return (DDI_SUCCESS); 38001708Sstevel } 38011708Sstevel 38021708Sstevel /* 38031708Sstevel * schpc_match_dip 38041708Sstevel * 38051708Sstevel * Used by ddi_walk_devs to find PCI Nexus nodes associated with 38061708Sstevel * Hot Plug Controllers. 38071708Sstevel */ 38081708Sstevel static int 38091708Sstevel schpc_match_dip(dev_info_t *dip, void *arg) 38101708Sstevel { 38111708Sstevel char *naddr; 38121708Sstevel find_dev_t *find_dev = (find_dev_t *)arg; 38131708Sstevel 38141708Sstevel if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 && 38151708Sstevel ((((naddr = ddi_get_name_addr(dip)) != NULL) && 38161708Sstevel (strcmp(find_dev->caddr, naddr) == 0)) || 38171708Sstevel ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) { 38181708Sstevel /* 38191708Sstevel * While ddi_walk_devs() holds dips when invoking this 38201708Sstevel * callback, this dip is being saved and will be accessible 38211708Sstevel * to the caller outside ddi_walk_devs(). Therefore it must be 38221708Sstevel * held. 38231708Sstevel */ 38241708Sstevel ndi_hold_devi(dip); 38251708Sstevel find_dev->dip = dip; 38261708Sstevel 38271708Sstevel SCHPC_DEBUG2(D_ATTACH, 38281708Sstevel "schpc_match_dip: pci@%s FOUND dip=0x%p", 38291708Sstevel find_dev->caddr, find_dev->dip); 38301708Sstevel 38311708Sstevel return (DDI_WALK_TERMINATE); 38321708Sstevel } 38331708Sstevel 38341708Sstevel ASSERT(find_dev->dip == NULL); 38351708Sstevel return (DDI_WALK_CONTINUE); 38361708Sstevel } 38371708Sstevel 38381708Sstevel /* 38391708Sstevel * schpc_buildapid 38401708Sstevel * 38411708Sstevel * Takes a component address and translates it into a ap_id prefix. 38421708Sstevel */ 38431708Sstevel static void 38441708Sstevel schpc_buildapid(dev_info_t *dip, int slot, char *ap_id) 38451708Sstevel { 38461708Sstevel int r, pci_id_cnt, pci_id_bit; 38471708Sstevel int slots_before, found; 38481708Sstevel unsigned char *slot_names_data, *s; 38491708Sstevel int slot_names_size; 38501708Sstevel int slot_num; 38511708Sstevel unsigned int bit_mask; 38521708Sstevel 38531708Sstevel slot_num = SCHPC_SLOT_NUM(slot); 38541708Sstevel 38551708Sstevel if (schpc_use_legacy_apid) { 38561708Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot); 38571708Sstevel 38581708Sstevel sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip), 38591708Sstevel schpc_getboard(dip), slot_num); 38601708Sstevel 38611708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id); 38621708Sstevel 38631708Sstevel return; 38641708Sstevel } 38651708Sstevel 38661708Sstevel r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 38671708Sstevel "slot-names", (caddr_t)&slot_names_data, 38681708Sstevel &slot_names_size); 38691708Sstevel 38701708Sstevel if (r == DDI_PROP_SUCCESS) { 38711708Sstevel 38721708Sstevel /* 38731708Sstevel * We can try to use the slot-names property to 38741708Sstevel * build our ap-id. 38751708Sstevel */ 38761708Sstevel bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) | 38771708Sstevel (slot_names_data[1] << 16) | (slot_names_data[0] << 24); 38781708Sstevel 38791708Sstevel pci_id_bit = 1; 38801708Sstevel pci_id_cnt = slots_before = found = 0; 38811708Sstevel 38821708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x", 38831708Sstevel slot, bit_mask); 38841708Sstevel 38851708Sstevel /* 38861708Sstevel * Walk the bit mask until we find the bit that corresponds 38871708Sstevel * to our slots device number. We count how many bits 38881708Sstevel * we find before we find our slot's bit. 38891708Sstevel */ 38901708Sstevel while (!found && (pci_id_cnt < 32)) { 38911708Sstevel 38921708Sstevel while (schpc_p->schpc_slot[slot].pci_id 38931708Sstevel != pci_id_cnt) { 38941708Sstevel 38951708Sstevel /* 38961708Sstevel * Find the next bit set. 38971708Sstevel */ 38981708Sstevel while (!(bit_mask & pci_id_bit) && 38991708Sstevel (pci_id_cnt < 32)) { 39001708Sstevel pci_id_bit = pci_id_bit << 1; 39011708Sstevel pci_id_cnt++; 39021708Sstevel } 39031708Sstevel 39041708Sstevel if (schpc_p->schpc_slot[slot].pci_id != 39051708Sstevel pci_id_cnt) 39061708Sstevel slots_before++; 39071708Sstevel else 39081708Sstevel found = 1; 39091708Sstevel } 39101708Sstevel } 39111708Sstevel 39121708Sstevel if (pci_id_cnt < 32) { 39131708Sstevel 39141708Sstevel /* 39151708Sstevel * Set ptr to first string. 39161708Sstevel */ 39171708Sstevel s = slot_names_data + 4; 39181708Sstevel 39191708Sstevel /* 39201708Sstevel * Increment past all the strings for the slots 39211708Sstevel * before ours. 39221708Sstevel */ 39231708Sstevel while (slots_before) { 39241708Sstevel while (*s != NULL) 39251708Sstevel s++; 39261708Sstevel s++; 39271708Sstevel slots_before--; 39281708Sstevel } 39291708Sstevel 39301708Sstevel /* 39311708Sstevel * We should be at our string. 39321708Sstevel */ 39331708Sstevel 39341708Sstevel sprintf(ap_id, "IO%d_%s", schpc_getexpander(dip), s); 39351708Sstevel 39361708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", 39371708Sstevel slot, ap_id); 39381708Sstevel 39391708Sstevel kmem_free(slot_names_data, slot_names_size); 39401708Sstevel return; 39411708Sstevel } 39421708Sstevel 39431708Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found", 39441708Sstevel slot); 39451708Sstevel 39461708Sstevel kmem_free(slot_names_data, slot_names_size); 39471708Sstevel } else 39481708Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found", 39491708Sstevel slot); 39501708Sstevel 39511708Sstevel /* 39521708Sstevel * Build the ap-id using the legacy naming scheme. 39531708Sstevel */ 39541708Sstevel sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip), 39551708Sstevel schpc_getboard(dip), slot_num); 39561708Sstevel 39571708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id); 39581708Sstevel } 39591708Sstevel 39601708Sstevel /* 39611708Sstevel * schpc_getexpander 39621708Sstevel * 39631708Sstevel * Returns the Expander Number (0-17) for the dip passed in. The Expander 39641708Sstevel * Number is extracted from the portid property of the pci node. Portid 39651708Sstevel * consists of <Expbrd#><1110x>, where x is the schizo number. 39661708Sstevel */ 39671708Sstevel static int 39681708Sstevel schpc_getexpander(dev_info_t *dip) 39691708Sstevel { 39701708Sstevel int id; 39711708Sstevel 39721708Sstevel id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1); 39731708Sstevel 39741708Sstevel if (id != -1) 39751708Sstevel return (id >> 5); 39761708Sstevel else { 39771708Sstevel id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1); 39781708Sstevel return (id); 39791708Sstevel } 39801708Sstevel } 39811708Sstevel 39821708Sstevel /* 39831708Sstevel * schpc_getboard 39841708Sstevel * 39851708Sstevel * Returns the board number (0 or 1) for the dip passed in. 39861708Sstevel */ 39871708Sstevel static int 39881708Sstevel schpc_getboard(dev_info_t *dip) 39891708Sstevel { 39901708Sstevel _NOTE(ARGUNUSED(dip)) 39911708Sstevel 39921708Sstevel /* 39931708Sstevel * Hot Pluggable PCI/cPCI slots are only available on 39941708Sstevel * Board 1 (half-bandwidth slot). 39951708Sstevel */ 39961708Sstevel return (1); 39971708Sstevel } 39981708Sstevel 39991708Sstevel /*ARGSUSED*/ 40001708Sstevel static int 40011708Sstevel schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot) 40021708Sstevel { 40031708Sstevel gdcd_t *gdcd; 40041708Sstevel int prd_slot, status, bus; 40051708Sstevel 40061708Sstevel SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() " 40071708Sstevel "exp=%d board=%d slot=%d", expander, board, slot); 40081708Sstevel 40091708Sstevel if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t), 40101708Sstevel KM_SLEEP)) == NULL) { 40111708Sstevel return (RSV_UNDEFINED); 40121708Sstevel } 40131708Sstevel 40141708Sstevel /* 40151708Sstevel * Get the Starcat Specific Global DCD Structure from the golden 40161708Sstevel * IOSRAM. 40171708Sstevel */ 40181708Sstevel if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) { 40191708Sstevel cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD " 40201708Sstevel "From IOSRAM\n"); 40211708Sstevel kmem_free(gdcd, sizeof (gdcd_t)); 40221708Sstevel return (RSV_UNDEFINED); 40231708Sstevel } 40241708Sstevel 40251708Sstevel if (gdcd->h.dcd_magic != GDCD_MAGIC) { 40261708Sstevel 40271708Sstevel cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n", 40281708Sstevel gdcd->h.dcd_magic); 40291708Sstevel 40301708Sstevel kmem_free(gdcd, sizeof (gdcd_t)); 40311708Sstevel return (RSV_UNDEFINED); 40321708Sstevel } 40331708Sstevel 40341708Sstevel if (gdcd->h.dcd_version != DCD_VERSION) { 40351708Sstevel cmn_err(CE_WARN, "schpc: GDCD Bad Version: " 40361708Sstevel "GDCD Version 0x%x Expecting 0x%x\n", 40371708Sstevel gdcd->h.dcd_version, DCD_VERSION); 40381708Sstevel 40391708Sstevel kmem_free(gdcd, sizeof (gdcd_t)); 40401708Sstevel return (RSV_UNDEFINED); 40411708Sstevel } 40421708Sstevel 40431708Sstevel if (slot < 2) 40441708Sstevel prd_slot = 4; 40451708Sstevel else 40461708Sstevel prd_slot = 5; 40471708Sstevel 40481708Sstevel bus = slot & 0x1; 40491708Sstevel 40501708Sstevel status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0]; 40511708Sstevel 40521708Sstevel kmem_free(gdcd, sizeof (gdcd_t)); 40531708Sstevel 40541708Sstevel SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() " 40551708Sstevel "prd_slot=%d bus=%d status=%d", prd_slot, bus, status); 40561708Sstevel 40571708Sstevel return (status); 40581708Sstevel } 40591708Sstevel 40601708Sstevel #define LEAF_SAVE_END 0xff 40611708Sstevel 40621708Sstevel typedef struct { 40631708Sstevel int reg; 40641708Sstevel int offset; 40651708Sstevel int access_size; 40661708Sstevel int number; 40671708Sstevel } save_reg_list_t; 40681708Sstevel 40691708Sstevel /* 40701708Sstevel * Save List Array. Describes the leaf registers that need to 40711708Sstevel * be restored after a leaf reset. 40721708Sstevel * 40731708Sstevel * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space 40741708Sstevel * Entry 2 - Offset Start 40751708Sstevel * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit 40761708Sstevel * Entry 4 - # of registers to be saved starting at offset, 40771708Sstevel */ 40781708Sstevel save_reg_list_t save_reg_list[] = { 0, 0x110, 8, 1, 40791708Sstevel 0, 0x200, 8, 2, 40801708Sstevel 0, 0x1000, 8, 0x18, 40811708Sstevel 0, 0x1a00, 8, 1, 40821708Sstevel 0, 0x2000, 8, 1, 40831708Sstevel 0, 0x2020, 8, 1, 40841708Sstevel 0, 0x2040, 8, 1, 40851708Sstevel 0, 0x2308, 8, 2, 40861708Sstevel 0, 0x2800, 8, 1, 40871708Sstevel 2, 0x04, 2, 1, /* Command */ 40881708Sstevel 2, 0x0d, 1, 1, /* Latency */ 40891708Sstevel 2, 0x40, 1, 1, /* Bus # */ 40901708Sstevel 2, 0x41, 1, 1, /* Sub. Bus # */ 40911708Sstevel LEAF_SAVE_END, 0, 0, 0}; 40921708Sstevel 40931708Sstevel static int 40941708Sstevel schpc_save_leaf(int slot) 40951708Sstevel { 40961708Sstevel int save_entry, list_entry, reg; 40971708Sstevel caddr_t leaf_regs; 40981708Sstevel ddi_device_acc_attr_t attr; 40991708Sstevel 41001708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot); 41011708Sstevel 41021708Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 41031708Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 41041708Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 41051708Sstevel 41061708Sstevel /* 41071708Sstevel * Map in the 3 addresses spaces defined for XMITS. 41081708Sstevel */ 41091708Sstevel for (reg = 0; reg < 3; reg++) { 41101708Sstevel if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg, 41111708Sstevel &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot]. 41121708Sstevel saved_handle[reg]) != DDI_SUCCESS) { 41131708Sstevel cmn_err(CE_WARN, "Mapin failed\n"); 41141708Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL; 41151708Sstevel return (1); 41161708Sstevel } 41171708Sstevel 41181708Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs; 41191708Sstevel } 41201708Sstevel 41211708Sstevel 41221708Sstevel /* 41231708Sstevel * Determine how many entries are in the list so we can 41241708Sstevel * allocate the save space. 41251708Sstevel */ 41261708Sstevel list_entry = 0; 41271708Sstevel save_entry = 0; 41281708Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 41291708Sstevel save_entry += save_reg_list[list_entry].number; 41301708Sstevel list_entry++; 41311708Sstevel } 41321708Sstevel 41331708Sstevel schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t)); 41341708Sstevel 41351708Sstevel if (schpc_p->schpc_slot[slot].saved_size == 0) 41361708Sstevel return (0); 41371708Sstevel 41381708Sstevel schpc_p->schpc_slot[slot].saved_regs = 41391708Sstevel (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size, 41401708Sstevel KM_SLEEP); 41411708Sstevel 41421708Sstevel /* 41431708Sstevel * Walk through the register list and save contents. 41441708Sstevel */ 41451708Sstevel list_entry = 0; 41461708Sstevel save_entry = 0; 41471708Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 41481708Sstevel schpc_save_entry(slot, list_entry, save_entry); 41491708Sstevel save_entry += save_reg_list[list_entry].number; 41501708Sstevel list_entry ++; 41511708Sstevel } 41521708Sstevel 41531708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot); 41541708Sstevel 41551708Sstevel return (0); 41561708Sstevel } 41571708Sstevel 41581708Sstevel static void 41591708Sstevel schpc_restore_leaf(int slot) 41601708Sstevel { 41611708Sstevel int save_entry, list_entry, reg; 41621708Sstevel 41631708Sstevel if (schpc_p->schpc_slot[slot].saved_regs == NULL) 41641708Sstevel return; 41651708Sstevel 41661708Sstevel /* 41671708Sstevel * Walk through the register list and restore contents. 41681708Sstevel */ 41691708Sstevel list_entry = 0; 41701708Sstevel save_entry = 0; 41711708Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 41721708Sstevel 41731708Sstevel schpc_restore_entry(slot, list_entry, save_entry); 41741708Sstevel 41751708Sstevel save_entry += save_reg_list[list_entry].number; 41761708Sstevel list_entry ++; 41771708Sstevel } 41781708Sstevel 41791708Sstevel /* 41801708Sstevel * Free the mapped in registers. 41811708Sstevel */ 41821708Sstevel for (reg = 0; reg < 3; reg++) { 41831708Sstevel if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) { 41841708Sstevel 41851708Sstevel ddi_regs_map_free( 41861708Sstevel &schpc_p->schpc_slot[slot].saved_handle[reg]); 41871708Sstevel 41881708Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL; 41891708Sstevel } 41901708Sstevel } 41911708Sstevel 41921708Sstevel kmem_free(schpc_p->schpc_slot[slot].saved_regs, 41931708Sstevel schpc_p->schpc_slot[slot].saved_size); 41941708Sstevel 41951708Sstevel schpc_p->schpc_slot[slot].saved_size = 0; 41961708Sstevel schpc_p->schpc_slot[slot].saved_regs = NULL; 41971708Sstevel 41981708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot); 41991708Sstevel } 42001708Sstevel 42011708Sstevel static void 42021708Sstevel schpc_save_entry(int slot, int list_entry, int save_entry) 42031708Sstevel { 42041708Sstevel int reg, reads = 0; 42051708Sstevel 42061708Sstevel reg = save_reg_list[list_entry].reg; 42071708Sstevel 42081708Sstevel while (reads < save_reg_list[list_entry].number) { 42091708Sstevel switch (save_reg_list[list_entry].access_size) { 42101708Sstevel case 8: 42111708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] = 42121708Sstevel ddi_get64( 42131708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg], 42141708Sstevel (uint64_t *)(schpc_p->schpc_slot[slot]. 42151708Sstevel saved_regs_va[reg] 42161708Sstevel + save_reg_list[list_entry].offset + 42171708Sstevel (reads * sizeof (uint64_t)))); 42181708Sstevel #ifdef DEBUG 42191708Sstevel if (schpc_dump_save_regs) 42201708Sstevel cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg, 42211708Sstevel save_reg_list[list_entry].offset + 42221708Sstevel (reads * sizeof (uint64_t)), 42231708Sstevel schpc_p->schpc_slot[slot]. 42241708Sstevel saved_regs[save_entry]); 42251708Sstevel #endif 42261708Sstevel 42271708Sstevel break; 42281708Sstevel case 4: 42291708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] = 42301708Sstevel ddi_get32( 42311708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg], 42321708Sstevel (uint32_t *)(schpc_p->schpc_slot[slot]. 42331708Sstevel saved_regs_va[reg] 42341708Sstevel + save_reg_list[list_entry].offset + 42351708Sstevel (reads * sizeof (uint32_t)))); 42361708Sstevel 42371708Sstevel #ifdef DEBUG 42381708Sstevel if (schpc_dump_save_regs) 42391708Sstevel cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg, 42401708Sstevel save_reg_list[list_entry].offset + 42411708Sstevel (reads * sizeof (uint32_t)), 42421708Sstevel schpc_p->schpc_slot[slot]. 42431708Sstevel saved_regs[save_entry]); 42441708Sstevel #endif 42451708Sstevel 42461708Sstevel break; 42471708Sstevel case 2: 42481708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] = 42491708Sstevel ddi_get16( 42501708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg], 42511708Sstevel (uint16_t *)(schpc_p->schpc_slot[slot]. 42521708Sstevel saved_regs_va[reg] 42531708Sstevel + save_reg_list[list_entry].offset + 42541708Sstevel (reads * sizeof (uint16_t)))); 42551708Sstevel 42561708Sstevel #ifdef DEBUG 42571708Sstevel if (schpc_dump_save_regs) 42581708Sstevel cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg, 42591708Sstevel save_reg_list[list_entry].offset + 42601708Sstevel (reads * sizeof (uint16_t)), 42611708Sstevel schpc_p->schpc_slot[slot]. 42621708Sstevel saved_regs[save_entry]); 42631708Sstevel #endif 42641708Sstevel 42651708Sstevel break; 42661708Sstevel case 1: 42671708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] = 42681708Sstevel ddi_get8( 42691708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg], 42701708Sstevel (uint8_t *)(schpc_p->schpc_slot[slot]. 42711708Sstevel saved_regs_va[reg] 42721708Sstevel + save_reg_list[list_entry].offset + 42731708Sstevel (reads * sizeof (uint8_t)))); 42741708Sstevel 42751708Sstevel #ifdef DEBUG 42761708Sstevel if (schpc_dump_save_regs) 42771708Sstevel cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg, 42781708Sstevel save_reg_list[list_entry].offset + 42791708Sstevel (reads * sizeof (uint8_t)), 42801708Sstevel schpc_p->schpc_slot[slot]. 42811708Sstevel saved_regs[save_entry]); 42821708Sstevel #endif 42831708Sstevel 42841708Sstevel break; 42851708Sstevel default: 42861708Sstevel cmn_err(CE_WARN, 42871708Sstevel "schpc: Illegal List Entry\n"); 42881708Sstevel } 42891708Sstevel reads++; 42901708Sstevel save_entry++; 42911708Sstevel } 42921708Sstevel } 42931708Sstevel 42941708Sstevel static void 42951708Sstevel schpc_restore_entry(int slot, int list_entry, int save_entry) 42961708Sstevel { 42971708Sstevel int reg, writes = 0; 42981708Sstevel 42991708Sstevel reg = save_reg_list[list_entry].reg; 43001708Sstevel 43011708Sstevel while (writes < save_reg_list[list_entry].number) { 43021708Sstevel switch (save_reg_list[list_entry].access_size) { 43031708Sstevel case 8: 43041708Sstevel #ifdef DEBUG 43051708Sstevel if (schpc_dump_save_regs) 43061708Sstevel cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg, 43071708Sstevel save_reg_list[list_entry].offset + 43081708Sstevel (writes * sizeof (uint64_t)), 43091708Sstevel schpc_p->schpc_slot[slot]. 43101708Sstevel saved_regs[save_entry]); 43111708Sstevel #endif 43121708Sstevel 43131708Sstevel ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg], 43141708Sstevel (uint64_t *)(schpc_p->schpc_slot[slot]. 43151708Sstevel saved_regs_va[reg] 43161708Sstevel + save_reg_list[list_entry].offset + 43171708Sstevel (writes * sizeof (uint64_t))), 43181708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]); 43191708Sstevel 43201708Sstevel break; 43211708Sstevel case 4: 43221708Sstevel #ifdef DEBUG 43231708Sstevel if (schpc_dump_save_regs) 43241708Sstevel cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg, 43251708Sstevel save_reg_list[list_entry].offset + 43261708Sstevel (writes * sizeof (uint32_t)), 43271708Sstevel schpc_p->schpc_slot[slot]. 43281708Sstevel saved_regs[save_entry]); 43291708Sstevel #endif 43301708Sstevel 43311708Sstevel ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg], 43321708Sstevel (uint32_t *)(schpc_p->schpc_slot[slot]. 43331708Sstevel saved_regs_va[reg] 43341708Sstevel + save_reg_list[list_entry].offset + 43351708Sstevel (writes * sizeof (uint32_t))), 43361708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]); 43371708Sstevel 43381708Sstevel break; 43391708Sstevel case 2: 43401708Sstevel #ifdef DEBUG 43411708Sstevel if (schpc_dump_save_regs) 43421708Sstevel cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg, 43431708Sstevel save_reg_list[list_entry].offset + 43441708Sstevel (writes * sizeof (uint16_t)), 43451708Sstevel schpc_p->schpc_slot[slot]. 43461708Sstevel saved_regs[save_entry]); 43471708Sstevel #endif 43481708Sstevel 43491708Sstevel ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg], 43501708Sstevel (uint16_t *)(schpc_p->schpc_slot[slot]. 43511708Sstevel saved_regs_va[reg] 43521708Sstevel + save_reg_list[list_entry].offset + 43531708Sstevel (writes * sizeof (uint16_t))), 43541708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]); 43551708Sstevel 43561708Sstevel break; 43571708Sstevel case 1: 43581708Sstevel #ifdef DEBUG 43591708Sstevel if (schpc_dump_save_regs) 43601708Sstevel cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg, 43611708Sstevel save_reg_list[list_entry].offset + 43621708Sstevel (writes * sizeof (uint8_t)), 43631708Sstevel schpc_p->schpc_slot[slot]. 43641708Sstevel saved_regs[save_entry]); 43651708Sstevel #endif 43661708Sstevel 43671708Sstevel ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg], 43681708Sstevel (uint8_t *)(schpc_p->schpc_slot[slot]. 43691708Sstevel saved_regs_va[reg] 43701708Sstevel + save_reg_list[list_entry].offset + 43711708Sstevel (writes * sizeof (uint8_t))), 43721708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]); 43731708Sstevel 43741708Sstevel break; 43751708Sstevel default: 43761708Sstevel cmn_err(CE_WARN, 43771708Sstevel "schpc: Illegal List Entry\n"); 43781708Sstevel } 43791708Sstevel writes++; 43801708Sstevel save_entry++; 43811708Sstevel } 43821708Sstevel } 43831708Sstevel 43841708Sstevel /* 43851708Sstevel * Returns TRUE if a leaf reset is required to change frequencies/mode. 43861708Sstevel */ 43871708Sstevel static int 43881708Sstevel schpc_is_leaf_reset_required(int slot) 43891708Sstevel { 43901708Sstevel char *name; 43911708Sstevel int32_t mod_rev; 43921708Sstevel 43931708Sstevel /* 43941708Sstevel * Only XMITS 3.0 and greater connected slots will require a 43951708Sstevel * reset to switch frequency and/or mode. 43961708Sstevel */ 43971708Sstevel name = ddi_binding_name(schpc_p->schpc_slot[slot].devi); 43981708Sstevel 43991708Sstevel if (strcmp(name, "pci108e,8002") == 0) { 44001708Sstevel mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY, 44011708Sstevel schpc_p->schpc_slot[slot].devi, 44021708Sstevel DDI_PROP_DONTPASS, "module-revision#", 0); 44031708Sstevel 44041708Sstevel SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev); 44051708Sstevel 44061708Sstevel /* 44071708Sstevel * Check for XMITS 3.0 or greater. 44081708Sstevel */ 44091708Sstevel if (mod_rev >= XMITS_30) { 44101708Sstevel 44111708Sstevel /* 44121708Sstevel * The leaf attached to C5V0 (slot 1) should 44131708Sstevel * not be reset. 44141708Sstevel */ 44151708Sstevel if ((slot & 3) == 1) { 44161708Sstevel 44171708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset " 44181708Sstevel "Not Required - C5V0", slot); 44191708Sstevel 44201708Sstevel return (0); 44211708Sstevel } 44221708Sstevel 44231708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset " 44241708Sstevel "Required", slot); 44251708Sstevel 44261708Sstevel return (1); 44271708Sstevel } 44281708Sstevel } 44291708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot); 44301708Sstevel 44311708Sstevel return (0); 44321708Sstevel } 44331708Sstevel 44341708Sstevel /* 44351708Sstevel * Returns TRUE if the bus can change frequencies. 44361708Sstevel */ 44371708Sstevel static int 44381708Sstevel schpc_is_freq_switchable(int slot) 44391708Sstevel { 44401708Sstevel char *name; 44411708Sstevel int32_t mod_rev; 44421708Sstevel 44431708Sstevel name = ddi_binding_name(schpc_p->schpc_slot[slot].devi); 44441708Sstevel 44451708Sstevel if (strcmp(name, "pci108e,8002") == 0) { 44461708Sstevel mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY, 44471708Sstevel schpc_p->schpc_slot[slot].devi, 44481708Sstevel DDI_PROP_DONTPASS, "module-revision#", 0); 44491708Sstevel 44501708Sstevel SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev); 44511708Sstevel 44521708Sstevel /* 44531708Sstevel * We will only report back that XMITS 2.0 (mod_rev = 2) 44541708Sstevel * or greater will have the ability to switch frequencies. 44551708Sstevel */ 44561708Sstevel if (mod_rev >= XMITS_20) { 44571708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - " 44581708Sstevel "Frequency is switchable", slot); 44591708Sstevel return (1); 44601708Sstevel } 44611708Sstevel } 44621708Sstevel 44631708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot); 44641708Sstevel return (0); 44651708Sstevel } 44661708Sstevel 44671708Sstevel /* 44681708Sstevel * schpc_slot_freq 44691708Sstevel * 44701708Sstevel * Convert the slot frequency setting to integer value. 44711708Sstevel */ 44721708Sstevel static int 44731708Sstevel schpc_slot_freq(pci_getslot_t *getslotp) 44741708Sstevel { 44751708Sstevel switch (getslotp->slot_freq_setting) { 44761708Sstevel case PCIMSG_FREQ_33MHZ: 44771708Sstevel return (SCHPC_33MHZ); 44781708Sstevel case PCIMSG_FREQ_66MHZ: 44791708Sstevel return (SCHPC_66MHZ); 44801708Sstevel case PCIMSG_FREQ_90MHZ: 44811708Sstevel return (SCHPC_90MHZ); 44821708Sstevel case PCIMSG_FREQ_133MHZ: 44831708Sstevel return (SCHPC_133MHZ); 44841708Sstevel default: 44851708Sstevel return (0); 44861708Sstevel } 44871708Sstevel } 44881708Sstevel 44891708Sstevel /* 44901708Sstevel * schpc_find_dip 44911708Sstevel * 44921708Sstevel * Used by ddi_walk_devs to find the dip which belongs 44931708Sstevel * to a certain slot. 44941708Sstevel * 44951708Sstevel * When this function returns, the dip is held. It is the 44961708Sstevel * responsibility of the caller to release the dip. 44971708Sstevel */ 44981708Sstevel static int 44991708Sstevel schpc_find_dip(dev_info_t *dip, void *arg) 45001708Sstevel { 45011708Sstevel find_dev_t *find_dev = (find_dev_t *)arg; 45021708Sstevel char *pathname = find_dev->caddr; 45031708Sstevel 45041708Sstevel (void) ddi_pathname(dip, pathname); 45051708Sstevel if (strcmp(find_dev->cname, pathname) == 0) { 45061708Sstevel ndi_hold_devi(dip); 45071708Sstevel find_dev->dip = dip; 45081708Sstevel return (DDI_WALK_TERMINATE); 45091708Sstevel } 45101708Sstevel return (DDI_WALK_CONTINUE); 45111708Sstevel } 4512