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*11311SSurya.Prakki@Sun.COM * Copyright 2009 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 = {
2407656SSherry.Moore@Sun.COM DEVO_REV, /* devo_rev, */
2417656SSherry.Moore@Sun.COM 0, /* refcnt */
2427656SSherry.Moore@Sun.COM schpc_info, /* get_dev_info */
2437656SSherry.Moore@Sun.COM nulldev, /* identify */
2447656SSherry.Moore@Sun.COM nulldev, /* probe */
2457656SSherry.Moore@Sun.COM schpc_attach, /* attach */
2467656SSherry.Moore@Sun.COM schpc_detach, /* detach */
2477656SSherry.Moore@Sun.COM nodev, /* reset */
2487656SSherry.Moore@Sun.COM &schpc_cb_ops, /* driver operations */
2497656SSherry.Moore@Sun.COM (struct bus_ops *)0, /* no bus operations */
2507656SSherry.Moore@Sun.COM NULL, /* power */
2517656SSherry.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,
2597656SSherry.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
_init(void)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",
3037656SSherry.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",
3097656SSherry.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",
3447656SSherry.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",
3507656SSherry.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",
3567656SSherry.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",
3627656SSherry.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() - "
3697656SSherry.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() - "
3737656SSherry.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,
3897656SSherry.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
_fini(void)3971708Sstevel _fini(void)
3981708Sstevel {
3991708Sstevel SCHPC_DEBUG0(D_ATTACH, "_fini()");
4001708Sstevel
4011708Sstevel return (DDI_FAILURE);
4021708Sstevel }
4031708Sstevel
4041708Sstevel int
_info(struct modinfo * modinfop)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
schpc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)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
schpc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)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
schpc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)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
schpc_connect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)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)",
559*11311SSurya.Prakki@Sun.COM (void *)ops_arg, (void *)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,
8667656SSherry.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",
880*11311SSurya.Prakki@Sun.COM (void *)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
schpc_disconnect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)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,
972*11311SSurya.Prakki@Sun.COM "schpc_disconnect( ops_arg=%p slot_hdl=%p)", (void *)ops_arg,
973*11311SSurya.Prakki@Sun.COM slot_hdl);
9741708Sstevel
9751708Sstevel mutex_enter(&schpc_p->schpc_mutex);
9761708Sstevel
9771708Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl);
9781708Sstevel
9791708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
9801708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
9811708Sstevel "schpc_disconnect - HPC Not Inited");
9821708Sstevel mutex_exit(&schpc_p->schpc_mutex);
9831708Sstevel return (HPC_ERR_FAILED);
9841708Sstevel }
9851708Sstevel
9861708Sstevel /*
9871708Sstevel * Check to see if we are already disconnected.
9881708Sstevel */
9891708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) {
9901708Sstevel mutex_exit(&schpc_p->schpc_mutex);
9911708Sstevel return (0);
9921708Sstevel }
9931708Sstevel
9941708Sstevel /*
9951708Sstevel * Block if another thread is executing a HPC command.
9961708Sstevel */
9971708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
9981708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
9991708Sstevel }
10001708Sstevel
10011708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
10021708Sstevel
10031708Sstevel mutex_exit(&schpc_p->schpc_mutex);
10041708Sstevel
10051708Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */
10061708Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */
10071708Sstevel
10081708Sstevel /*
10091708Sstevel * If a leaf reset is going to be asserted due to a mode/freq.
10101708Sstevel * change, then the leaf registers of the XMITS bridge will need
10111708Sstevel * to be saved off prior to the connect.
10121708Sstevel */
10131708Sstevel if (schpc_is_leaf_reset_required(slot)) {
10141708Sstevel if (schpc_save_leaf(slot) != 0) {
10151708Sstevel
10161708Sstevel cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
10171708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
10181708Sstevel expander, board, slot & 3,
10191708Sstevel schpc_p->schpc_slot[slot].ap_id);
10201708Sstevel
10211708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
10221708Sstevel
10231708Sstevel goto failed;
10241708Sstevel }
10251708Sstevel }
10261708Sstevel
10271708Sstevel /*
10281708Sstevel * Initialize Set Slot Command.
10291708Sstevel */
10301708Sstevel schpc_init_setslot_message(&setslot);
10311708Sstevel
10321708Sstevel setslot.slot_power_off = PCIMSG_ON; /* Turn Power Off */
10331708Sstevel
10341708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */
10351708Sstevel
10361708Sstevel setslot.slot_disable_ENUM = PCIMSG_ON; /* Mask the ENUM# signal */
10371708Sstevel setslot.slot_disable_HEALTHY = PCIMSG_ON; /* Mask the HEALTHY# sig */
10381708Sstevel
10391708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
10401708Sstevel
10411708Sstevel SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
10421708Sstevel "setslotstatus returned 0x%x", rval);
10431708Sstevel
10441708Sstevel if (rval != 0) {
10451708Sstevel /*
10461708Sstevel * System Controller/Mailbox failure.
10471708Sstevel */
10481708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
10491708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
10501708Sstevel "Communicate with System Controller", expander, board,
10511708Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
10521708Sstevel
10531708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
10541708Sstevel
10551708Sstevel goto failed;
10561708Sstevel }
10571708Sstevel
10581708Sstevel SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
10591708Sstevel "slot_replystatus returned 0x%x", setslot.slot_replystatus);
10601708Sstevel
10611708Sstevel if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
10621708Sstevel
10631708Sstevel /*
10641708Sstevel * The Request was successfully completed.
10651708Sstevel */
10661708Sstevel schpc_p->schpc_slot[slot].state &=
10671708Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
10681708Sstevel
10691708Sstevel schpc_setslotled(expander, board, slot,
10701708Sstevel (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF));
10711708Sstevel
10721708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
10731708Sstevel "schpc_disconnect() - setslotstatus succeeded");
10741708Sstevel
10751708Sstevel mutex_enter(&schpc_p->schpc_mutex);
10761708Sstevel schpc_p->schpc_slot[slot].state &=
10771708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
10781708Sstevel cv_signal(&schpc_p->schpc_cv);
10791708Sstevel mutex_exit(&schpc_p->schpc_mutex);
10801708Sstevel
10811708Sstevel return (0);
10821708Sstevel }
10831708Sstevel /*
10841708Sstevel * System Controller/Mailbox failure.
10851708Sstevel */
10861708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
10871708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
10881708Sstevel "failed disconnection request", expander, board,
10891708Sstevel SCHPC_SLOT_NUM(slot),
10901708Sstevel schpc_p->schpc_slot[slot].ap_id);
10911708Sstevel
10921708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
10931708Sstevel
10941708Sstevel failed:
10951708Sstevel schpc_restore_leaf(slot);
10961708Sstevel mutex_enter(&schpc_p->schpc_mutex);
10971708Sstevel schpc_p->schpc_slot[slot].state &=
10981708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
10991708Sstevel cv_signal(&schpc_p->schpc_cv);
11001708Sstevel mutex_exit(&schpc_p->schpc_mutex);
11011708Sstevel
11021708Sstevel return (HPC_ERR_FAILED);
11031708Sstevel }
11041708Sstevel
11051708Sstevel /*
11061708Sstevel * schpc_cpci_control
11071708Sstevel *
11081708Sstevel * Called by Hot Plug Services to perform a attachment point specific
11091708Sstevel * on a Hot Pluggable Compact PCI Slot.
11101708Sstevel */
11111708Sstevel /*ARGSUSED*/
11121708Sstevel static int
schpc_cpci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)11131708Sstevel schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
11141708Sstevel caddr_t arg)
11151708Sstevel {
11161708Sstevel int rval;
11171708Sstevel int expander, board, slot;
11181708Sstevel pci_setslot_t setslot;
11191708Sstevel pci_getslot_t slotstatus;
11201708Sstevel hpc_led_info_t *hpc_led_info;
11211708Sstevel
11221708Sstevel SCHPC_DEBUG3(D_IOC_CONTROL,
11231708Sstevel "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)",
1124*11311SSurya.Prakki@Sun.COM (void *)ops_arg, (void *)slot_hdl, request);
11251708Sstevel
11261708Sstevel mutex_enter(&schpc_p->schpc_mutex);
11271708Sstevel
11281708Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl);
11291708Sstevel
11301708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
11311708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
11321708Sstevel "schpc_disconnect - HPC Not Inited");
11331708Sstevel mutex_exit(&schpc_p->schpc_mutex);
11341708Sstevel return (HPC_ERR_FAILED);
11351708Sstevel }
11361708Sstevel
11371708Sstevel /*
11381708Sstevel * Block if another thread is executing a HPC command.
11391708Sstevel */
11401708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
11411708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
11421708Sstevel }
11431708Sstevel
11441708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
11451708Sstevel
11461708Sstevel mutex_exit(&schpc_p->schpc_mutex);
11471708Sstevel
11481708Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */
11491708Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */
11501708Sstevel
11511708Sstevel /*
11521708Sstevel * Initialize Set Slot Command.
11531708Sstevel */
11541708Sstevel schpc_init_setslot_message(&setslot);
11551708Sstevel
11561708Sstevel /*
11571708Sstevel * Initialize LED to last know state.
11581708Sstevel */
11591708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
11601708Sstevel case LED_ON:
11611708Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
11621708Sstevel break;
11631708Sstevel case LED_OFF:
11641708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
11651708Sstevel break;
11661708Sstevel case LED_FLASH:
11671708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
11681708Sstevel break;
11691708Sstevel }
11701708Sstevel
11711708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
11721708Sstevel case LED_ON:
11731708Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
11741708Sstevel break;
11751708Sstevel case LED_OFF:
11761708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
11771708Sstevel break;
11781708Sstevel case LED_FLASH:
11791708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
11801708Sstevel break;
11811708Sstevel }
11821708Sstevel
11831708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
11841708Sstevel case LED_ON:
11851708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
11861708Sstevel break;
11871708Sstevel case LED_OFF:
11881708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
11891708Sstevel break;
11901708Sstevel case LED_FLASH:
11911708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
11921708Sstevel break;
11931708Sstevel }
11941708Sstevel
11951708Sstevel switch (request) {
11961708Sstevel
11971708Sstevel case HPC_CTRL_GET_LED_STATE:
11981708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
11991708Sstevel "HPC_CTRL_GET_LED_STATE");
12001708Sstevel hpc_led_info = (hpc_led_info_t *)arg;
12011708Sstevel
12021708Sstevel switch (hpc_led_info->led) {
12031708Sstevel case HPC_FAULT_LED:
12041708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
12051708Sstevel case LED_OFF:
12061708Sstevel hpc_led_info->state = HPC_LED_OFF;
12071708Sstevel break;
12081708Sstevel case LED_ON:
12091708Sstevel hpc_led_info->state = HPC_LED_ON;
12101708Sstevel break;
12111708Sstevel case LED_FLASH:
12121708Sstevel hpc_led_info->state = HPC_LED_BLINK;
12131708Sstevel break;
12141708Sstevel }
12151708Sstevel break;
12161708Sstevel
12171708Sstevel case HPC_POWER_LED:
12181708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
12191708Sstevel case LED_OFF:
12201708Sstevel hpc_led_info->state = HPC_LED_OFF;
12211708Sstevel break;
12221708Sstevel case LED_ON:
12231708Sstevel hpc_led_info->state = HPC_LED_ON;
12241708Sstevel break;
12251708Sstevel case LED_FLASH:
12261708Sstevel hpc_led_info->state = HPC_LED_BLINK;
12271708Sstevel break;
12281708Sstevel }
12291708Sstevel break;
12301708Sstevel case HPC_ATTN_LED:
12311708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
12321708Sstevel case LED_OFF:
12331708Sstevel hpc_led_info->state = HPC_LED_OFF;
12341708Sstevel break;
12351708Sstevel case LED_ON:
12361708Sstevel hpc_led_info->state = HPC_LED_OFF;
12371708Sstevel break;
12381708Sstevel case LED_FLASH:
12391708Sstevel hpc_led_info->state = HPC_LED_ON;
12401708Sstevel break;
12411708Sstevel }
12421708Sstevel break;
12431708Sstevel case HPC_ACTIVE_LED:
12441708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
12451708Sstevel case LED_OFF:
12461708Sstevel hpc_led_info->state = HPC_LED_OFF;
12471708Sstevel break;
12481708Sstevel case LED_ON:
12491708Sstevel hpc_led_info->state = HPC_LED_ON;
12501708Sstevel break;
12511708Sstevel case LED_FLASH:
12521708Sstevel hpc_led_info->state = HPC_LED_BLINK;
12531708Sstevel break;
12541708Sstevel }
12551708Sstevel break;
12561708Sstevel default:
12571708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
12581708Sstevel "Invalid LED %x", hpc_led_info->led);
12591708Sstevel
12601708Sstevel mutex_enter(&schpc_p->schpc_mutex);
12611708Sstevel schpc_p->schpc_slot[slot].state &=
12621708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
12631708Sstevel cv_signal(&schpc_p->schpc_cv);
12641708Sstevel mutex_exit(&schpc_p->schpc_mutex);
12651708Sstevel
12661708Sstevel return (HPC_ERR_FAILED);
12671708Sstevel }
12681708Sstevel
12691708Sstevel mutex_enter(&schpc_p->schpc_mutex);
12701708Sstevel schpc_p->schpc_slot[slot].state &=
12711708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
12721708Sstevel cv_signal(&schpc_p->schpc_cv);
12731708Sstevel mutex_exit(&schpc_p->schpc_mutex);
12741708Sstevel
12751708Sstevel return (0);
12761708Sstevel
12771708Sstevel case HPC_CTRL_SET_LED_STATE:
12781708Sstevel hpc_led_info = (hpc_led_info_t *)arg;
12791708Sstevel
12801708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1281*11311SSurya.Prakki@Sun.COM "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1282*11311SSurya.Prakki@Sun.COM (void *)hpc_led_info);
12831708Sstevel
12841708Sstevel switch (hpc_led_info->led) {
12851708Sstevel case HPC_FAULT_LED:
12861708Sstevel switch (hpc_led_info->state) {
12871708Sstevel case HPC_LED_OFF:
12881708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
12891708Sstevel LED_OFF;
12901708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
12911708Sstevel break;
12921708Sstevel case HPC_LED_ON:
12931708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
12941708Sstevel LED_ON;
12951708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
12961708Sstevel break;
12971708Sstevel case HPC_LED_BLINK:
12981708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
12991708Sstevel LED_FLASH;
13001708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
13011708Sstevel break;
13021708Sstevel }
13031708Sstevel break;
13041708Sstevel case HPC_POWER_LED:
13051708Sstevel switch (hpc_led_info->state) {
13061708Sstevel case HPC_LED_OFF:
13071708Sstevel schpc_p->schpc_slot[slot].led.led_power =
13081708Sstevel LED_OFF;
13091708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
13101708Sstevel break;
13111708Sstevel case HPC_LED_ON:
13121708Sstevel schpc_p->schpc_slot[slot].led.led_power =
13131708Sstevel LED_ON;
13141708Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
13151708Sstevel break;
13161708Sstevel case HPC_LED_BLINK:
13171708Sstevel schpc_p->schpc_slot[slot].led.led_power =
13181708Sstevel LED_FLASH;
13191708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
13201708Sstevel break;
13211708Sstevel }
13221708Sstevel break;
13231708Sstevel case HPC_ATTN_LED:
13241708Sstevel switch (hpc_led_info->state) {
13251708Sstevel case HPC_LED_OFF:
13261708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
13271708Sstevel LED_OFF;
13281708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
13291708Sstevel break;
13301708Sstevel case HPC_LED_ON:
13311708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
13321708Sstevel LED_FLASH;
13331708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
13341708Sstevel break;
13351708Sstevel case HPC_LED_BLINK:
13361708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
13371708Sstevel LED_FLASH;
13381708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
13391708Sstevel break;
13401708Sstevel }
13411708Sstevel break;
13421708Sstevel case HPC_ACTIVE_LED:
13431708Sstevel switch (hpc_led_info->state) {
13441708Sstevel case HPC_LED_OFF:
13451708Sstevel schpc_p->schpc_slot[slot].led.led_service =
13461708Sstevel LED_OFF;
13471708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
13481708Sstevel break;
13491708Sstevel case HPC_LED_ON:
13501708Sstevel schpc_p->schpc_slot[slot].led.led_service =
13511708Sstevel LED_ON;
13521708Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
13531708Sstevel break;
13541708Sstevel case HPC_LED_BLINK:
13551708Sstevel schpc_p->schpc_slot[slot].led.led_service =
13561708Sstevel LED_FLASH;
13571708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
13581708Sstevel break;
13591708Sstevel }
13601708Sstevel break;
13611708Sstevel default:
13621708Sstevel mutex_enter(&schpc_p->schpc_mutex);
13631708Sstevel schpc_p->schpc_slot[slot].state &=
13641708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
13651708Sstevel cv_signal(&schpc_p->schpc_cv);
13661708Sstevel mutex_exit(&schpc_p->schpc_mutex);
13671708Sstevel
13681708Sstevel return (0);
13691708Sstevel }
13701708Sstevel
13711708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
13721708Sstevel
13731708Sstevel mutex_enter(&schpc_p->schpc_mutex);
13741708Sstevel schpc_p->schpc_slot[slot].state &=
13751708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
13761708Sstevel cv_signal(&schpc_p->schpc_cv);
13771708Sstevel mutex_exit(&schpc_p->schpc_mutex);
13781708Sstevel
13791708Sstevel return (0);
13801708Sstevel
13811708Sstevel case HPC_CTRL_GET_SLOT_STATE: {
13821708Sstevel hpc_slot_state_t *hpc_slot_state;
13831708Sstevel
13841708Sstevel hpc_slot_state = (hpc_slot_state_t *)arg;
13851708Sstevel
13861708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
13871708Sstevel "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1388*11311SSurya.Prakki@Sun.COM (void *)hpc_slot_state);
13891708Sstevel
13901708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
13911708Sstevel
13921708Sstevel if (!rval) {
13931708Sstevel
13941708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
13951708Sstevel return (HPC_ERR_FAILED);
13961708Sstevel }
13971708Sstevel
13981708Sstevel if (slotstatus.slot_empty == PCIMSG_ON) {
13991708Sstevel *hpc_slot_state = HPC_SLOT_EMPTY;
14001708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
14011708Sstevel } else if (slotstatus.slot_power_on == PCIMSG_ON) {
14021708Sstevel *hpc_slot_state = HPC_SLOT_CONNECTED;
14031708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
14041708Sstevel schpc_p->schpc_slot[slot].state |=
14051708Sstevel SCHPC_SLOTSTATE_CONNECTED;
14061708Sstevel } else {
14071708Sstevel *hpc_slot_state = HPC_SLOT_DISCONNECTED;
14081708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL,
14091708Sstevel "Slot Disconnected");
14101708Sstevel schpc_p->schpc_slot[slot].state &=
14111708Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
14121708Sstevel }
14131708Sstevel } else {
14141708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
14151708Sstevel
14161708Sstevel mutex_enter(&schpc_p->schpc_mutex);
14171708Sstevel schpc_p->schpc_slot[slot].state &=
14181708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
14191708Sstevel cv_signal(&schpc_p->schpc_cv);
14201708Sstevel mutex_exit(&schpc_p->schpc_mutex);
14211708Sstevel
14221708Sstevel return (HPC_ERR_FAILED);
14231708Sstevel }
14241708Sstevel
14251708Sstevel mutex_enter(&schpc_p->schpc_mutex);
14261708Sstevel schpc_p->schpc_slot[slot].state &=
14271708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
14281708Sstevel cv_signal(&schpc_p->schpc_cv);
14291708Sstevel mutex_exit(&schpc_p->schpc_mutex);
14301708Sstevel
14311708Sstevel return (0);
14321708Sstevel }
14331708Sstevel case HPC_CTRL_GET_BOARD_TYPE: {
14341708Sstevel hpc_board_type_t *hpc_board_type;
14351708Sstevel
14361708Sstevel hpc_board_type = (hpc_board_type_t *)arg;
14371708Sstevel
14381708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
14391708Sstevel "HPC_CTRL_GET_BOARD_TYPE");
14401708Sstevel
14411708Sstevel /*
14421708Sstevel * The HPC driver does not know what board type
14431708Sstevel * is plugged in.
14441708Sstevel */
14451708Sstevel *hpc_board_type = HPC_BOARD_CPCI_HS;
14461708Sstevel
14471708Sstevel mutex_enter(&schpc_p->schpc_mutex);
14481708Sstevel schpc_p->schpc_slot[slot].state &=
14491708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
14501708Sstevel cv_signal(&schpc_p->schpc_cv);
14511708Sstevel mutex_exit(&schpc_p->schpc_mutex);
14521708Sstevel
14531708Sstevel return (0);
14541708Sstevel
14551708Sstevel }
14561708Sstevel case HPC_CTRL_DEV_CONFIGURED:
14571708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
14581708Sstevel "HPC_CTRL_DEV_CONFIGURED");
14591708Sstevel
14601708Sstevel mutex_enter(&schpc_p->schpc_mutex);
14611708Sstevel schpc_p->schpc_slot[slot].state &=
14621708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
14631708Sstevel cv_signal(&schpc_p->schpc_cv);
14641708Sstevel mutex_exit(&schpc_p->schpc_mutex);
14651708Sstevel
14661708Sstevel return (0);
14671708Sstevel
14681708Sstevel case HPC_CTRL_DEV_UNCONFIGURED:
14691708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
14701708Sstevel "HPC_CTRL_DEV_UNCONFIGURED");
14711708Sstevel
14721708Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) {
14731708Sstevel /*
14741708Sstevel * When the occupant is unconfigured, power
14751708Sstevel * down the slot.
14761708Sstevel */
14771708Sstevel rval = schpc_disconnect((caddr_t)schpc_p,
14781708Sstevel schpc_p->schpc_slot[slot].slot_handle,
14791708Sstevel 0, 0);
14801708Sstevel
14811708Sstevel schpc_p->schpc_slot[slot].state &=
14821708Sstevel ~SCHPC_SLOTSTATE_ENUM;
14831708Sstevel }
14841708Sstevel
14851708Sstevel mutex_enter(&schpc_p->schpc_mutex);
14861708Sstevel schpc_p->schpc_slot[slot].state &=
14871708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
14881708Sstevel cv_signal(&schpc_p->schpc_cv);
14891708Sstevel mutex_exit(&schpc_p->schpc_mutex);
14901708Sstevel
14911708Sstevel return (0);
14921708Sstevel
14931708Sstevel case HPC_CTRL_ENABLE_AUTOCFG:
14941708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
14951708Sstevel "HPC_CTRL_ENABLE_AUTOCFG");
14961708Sstevel
14971708Sstevel schpc_p->schpc_slot[slot].state |=
14981708Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
14991708Sstevel
15001708Sstevel mutex_enter(&schpc_p->schpc_mutex);
15011708Sstevel schpc_p->schpc_slot[slot].state &=
15021708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
15031708Sstevel cv_signal(&schpc_p->schpc_cv);
15041708Sstevel mutex_exit(&schpc_p->schpc_mutex);
15051708Sstevel
15061708Sstevel return (0);
15071708Sstevel
15081708Sstevel case HPC_CTRL_DISABLE_AUTOCFG:
15091708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
15101708Sstevel "HPC_CTRL_DISABLE_AUTOCFG");
15111708Sstevel schpc_p->schpc_slot[slot].state &=
15121708Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
15131708Sstevel
15141708Sstevel mutex_enter(&schpc_p->schpc_mutex);
15151708Sstevel schpc_p->schpc_slot[slot].state &=
15161708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
15171708Sstevel cv_signal(&schpc_p->schpc_cv);
15181708Sstevel mutex_exit(&schpc_p->schpc_mutex);
15191708Sstevel
15201708Sstevel return (0);
15211708Sstevel
15221708Sstevel case HPC_CTRL_DISABLE_ENUM:
15231708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
15241708Sstevel "HPC_CTRL_DISABLE_ENUM");
15251708Sstevel
15261708Sstevel setslot.slot_disable_ENUM = PCIMSG_ON;
15271708Sstevel
15281708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
15291708Sstevel
15301708Sstevel if (rval)
15311708Sstevel rval = HPC_ERR_FAILED;
15321708Sstevel
15331708Sstevel mutex_enter(&schpc_p->schpc_mutex);
15341708Sstevel schpc_p->schpc_slot[slot].state &=
15351708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
15361708Sstevel cv_signal(&schpc_p->schpc_cv);
15371708Sstevel mutex_exit(&schpc_p->schpc_mutex);
15381708Sstevel
15391708Sstevel return (rval);
15401708Sstevel
15411708Sstevel case HPC_CTRL_ENABLE_ENUM:
15421708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
15431708Sstevel "HPC_CTRL_ENABLE_ENUM");
15441708Sstevel
15451708Sstevel setslot.slot_enable_ENUM = PCIMSG_ON;
15461708Sstevel
15471708Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
15481708Sstevel
15491708Sstevel if (rval)
15501708Sstevel rval = HPC_ERR_FAILED;
15511708Sstevel
15521708Sstevel mutex_enter(&schpc_p->schpc_mutex);
15531708Sstevel schpc_p->schpc_slot[slot].state &=
15541708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
15551708Sstevel cv_signal(&schpc_p->schpc_cv);
15561708Sstevel mutex_exit(&schpc_p->schpc_mutex);
15571708Sstevel
15581708Sstevel return (rval);
15591708Sstevel
15601708Sstevel default:
15611708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
15621708Sstevel "****NOT SUPPORTED CONTROL CMD");
15631708Sstevel
15641708Sstevel mutex_enter(&schpc_p->schpc_mutex);
15651708Sstevel schpc_p->schpc_slot[slot].state &=
15661708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
15671708Sstevel cv_signal(&schpc_p->schpc_cv);
15681708Sstevel mutex_exit(&schpc_p->schpc_mutex);
15691708Sstevel
15701708Sstevel return (HPC_ERR_NOTSUPPORTED);
15711708Sstevel }
15721708Sstevel }
15731708Sstevel
15741708Sstevel /*
15751708Sstevel * schpc_pci_control
15761708Sstevel *
15771708Sstevel * Called by Hot Plug Services to perform a attachment point specific
15781708Sstevel * on a Hot Pluggable Standard PCI Slot.
15791708Sstevel */
15801708Sstevel /*ARGSUSED*/
15811708Sstevel static int
schpc_pci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)15821708Sstevel schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
15831708Sstevel caddr_t arg)
15841708Sstevel {
15851708Sstevel int rval;
15861708Sstevel int expander, board, slot;
15871708Sstevel pci_setslot_t setslot;
15881708Sstevel pci_getslot_t slotstatus;
15891708Sstevel hpc_led_info_t *hpc_led_info;
15901708Sstevel
15911708Sstevel SCHPC_DEBUG3(D_IOC_CONTROL,
15921708Sstevel "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)",
1593*11311SSurya.Prakki@Sun.COM (void *)ops_arg, (void *)slot_hdl, request);
15941708Sstevel
15951708Sstevel mutex_enter(&schpc_p->schpc_mutex);
15961708Sstevel
15971708Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl);
15981708Sstevel
15991708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
16001708Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
16011708Sstevel "schpc_disconnect - HPC Not Inited");
16021708Sstevel mutex_exit(&schpc_p->schpc_mutex);
16031708Sstevel return (HPC_ERR_FAILED);
16041708Sstevel }
16051708Sstevel
16061708Sstevel /*
16071708Sstevel * Block if another thread is executing a HPC command.
16081708Sstevel */
16091708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
16101708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
16111708Sstevel }
16121708Sstevel
16131708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
16141708Sstevel
16151708Sstevel mutex_exit(&schpc_p->schpc_mutex);
16161708Sstevel
16171708Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */
16181708Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */
16191708Sstevel
16201708Sstevel /*
16211708Sstevel * Initialize Set Slot Command.
16221708Sstevel */
16231708Sstevel schpc_init_setslot_message(&setslot);
16241708Sstevel
16251708Sstevel /*
16261708Sstevel * Initialize LED to last know state.
16271708Sstevel */
16281708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
16291708Sstevel case LED_ON:
16301708Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
16311708Sstevel break;
16321708Sstevel case LED_OFF:
16331708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
16341708Sstevel break;
16351708Sstevel case LED_FLASH:
16361708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
16371708Sstevel break;
16381708Sstevel }
16391708Sstevel
16401708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
16411708Sstevel case LED_ON:
16421708Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
16431708Sstevel break;
16441708Sstevel case LED_OFF:
16451708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
16461708Sstevel break;
16471708Sstevel case LED_FLASH:
16481708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
16491708Sstevel break;
16501708Sstevel }
16511708Sstevel
16521708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
16531708Sstevel case LED_ON:
16541708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
16551708Sstevel break;
16561708Sstevel case LED_OFF:
16571708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
16581708Sstevel break;
16591708Sstevel case LED_FLASH:
16601708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
16611708Sstevel break;
16621708Sstevel }
16631708Sstevel
16641708Sstevel switch (request) {
16651708Sstevel
16661708Sstevel
16671708Sstevel case HPC_CTRL_GET_SLOT_STATE: {
16681708Sstevel hpc_slot_state_t *hpc_slot_state;
16691708Sstevel
16701708Sstevel hpc_slot_state = (hpc_slot_state_t *)arg;
16711708Sstevel
16721708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
16731708Sstevel "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1674*11311SSurya.Prakki@Sun.COM (void *)hpc_slot_state);
16751708Sstevel
16761708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
16771708Sstevel
16781708Sstevel if (!rval) {
16791708Sstevel
16801708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
16811708Sstevel
16821708Sstevel mutex_enter(&schpc_p->schpc_mutex);
16831708Sstevel schpc_p->schpc_slot[slot].state &=
16841708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
16851708Sstevel cv_signal(&schpc_p->schpc_cv);
16861708Sstevel mutex_exit(&schpc_p->schpc_mutex);
16871708Sstevel
16881708Sstevel return (HPC_ERR_FAILED);
16891708Sstevel }
16901708Sstevel
16911708Sstevel if (slotstatus.slot_empty == PCIMSG_ON) {
16921708Sstevel *hpc_slot_state = HPC_SLOT_EMPTY;
16931708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
16941708Sstevel } else if (slotstatus.slot_power_on == PCIMSG_ON) {
16951708Sstevel *hpc_slot_state = HPC_SLOT_CONNECTED;
16961708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
16971708Sstevel schpc_p->schpc_slot[slot].state |=
16981708Sstevel SCHPC_SLOTSTATE_CONNECTED;
16991708Sstevel } else {
17001708Sstevel *hpc_slot_state = HPC_SLOT_DISCONNECTED;
17011708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL,
17021708Sstevel "Slot Disconnected");
17031708Sstevel schpc_p->schpc_slot[slot].state &=
17041708Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
17051708Sstevel }
17061708Sstevel } else {
17071708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
17081708Sstevel
17091708Sstevel mutex_enter(&schpc_p->schpc_mutex);
17101708Sstevel schpc_p->schpc_slot[slot].state &=
17111708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
17121708Sstevel cv_signal(&schpc_p->schpc_cv);
17131708Sstevel mutex_exit(&schpc_p->schpc_mutex);
17141708Sstevel
17151708Sstevel return (HPC_ERR_FAILED);
17161708Sstevel }
17171708Sstevel
17181708Sstevel mutex_enter(&schpc_p->schpc_mutex);
17191708Sstevel schpc_p->schpc_slot[slot].state &=
17201708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
17211708Sstevel cv_signal(&schpc_p->schpc_cv);
17221708Sstevel mutex_exit(&schpc_p->schpc_mutex);
17231708Sstevel
17241708Sstevel return (0);
17251708Sstevel }
17261708Sstevel case HPC_CTRL_GET_BOARD_TYPE: {
17271708Sstevel hpc_board_type_t *hpc_board_type;
17281708Sstevel
17291708Sstevel hpc_board_type = (hpc_board_type_t *)arg;
17301708Sstevel
17311708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
17321708Sstevel "HPC_CTRL_GET_BOARD_TYPE");
17331708Sstevel
17341708Sstevel
17351708Sstevel /*
17361708Sstevel * The HPC driver does not know what board type
17371708Sstevel * is plugged in.
17381708Sstevel */
17391708Sstevel *hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
17401708Sstevel
17411708Sstevel mutex_enter(&schpc_p->schpc_mutex);
17421708Sstevel schpc_p->schpc_slot[slot].state &=
17431708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
17441708Sstevel cv_signal(&schpc_p->schpc_cv);
17451708Sstevel mutex_exit(&schpc_p->schpc_mutex);
17461708Sstevel
17471708Sstevel return (0);
17481708Sstevel
17491708Sstevel }
17501708Sstevel case HPC_CTRL_DEV_UNCONFIG_START:
17511708Sstevel case HPC_CTRL_DEV_CONFIG_START:
17521708Sstevel case HPC_CTRL_DEV_CONFIGURED:
17531708Sstevel case HPC_CTRL_DEV_UNCONFIGURED:
17541708Sstevel mutex_enter(&schpc_p->schpc_mutex);
17551708Sstevel schpc_p->schpc_slot[slot].state &=
17561708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
17571708Sstevel cv_signal(&schpc_p->schpc_cv);
17581708Sstevel mutex_exit(&schpc_p->schpc_mutex);
17591708Sstevel
17601708Sstevel return (0);
17611708Sstevel
17621708Sstevel case HPC_CTRL_GET_LED_STATE:
17631708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
17641708Sstevel "HPC_CTRL_GET_LED_STATE");
17651708Sstevel hpc_led_info = (hpc_led_info_t *)arg;
17661708Sstevel
17671708Sstevel switch (hpc_led_info->led) {
17681708Sstevel case HPC_FAULT_LED:
17691708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
17701708Sstevel case LED_OFF:
17711708Sstevel hpc_led_info->state = HPC_LED_OFF;
17721708Sstevel break;
17731708Sstevel case LED_ON:
17741708Sstevel hpc_led_info->state = HPC_LED_ON;
17751708Sstevel break;
17761708Sstevel case LED_FLASH:
17771708Sstevel hpc_led_info->state = HPC_LED_BLINK;
17781708Sstevel break;
17791708Sstevel }
17801708Sstevel break;
17811708Sstevel
17821708Sstevel case HPC_POWER_LED:
17831708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
17841708Sstevel case LED_OFF:
17851708Sstevel hpc_led_info->state = HPC_LED_OFF;
17861708Sstevel break;
17871708Sstevel case LED_ON:
17881708Sstevel hpc_led_info->state = HPC_LED_ON;
17891708Sstevel break;
17901708Sstevel case LED_FLASH:
17911708Sstevel hpc_led_info->state = HPC_LED_BLINK;
17921708Sstevel break;
17931708Sstevel }
17941708Sstevel break;
17951708Sstevel case HPC_ATTN_LED:
17961708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
17971708Sstevel case LED_OFF:
17981708Sstevel hpc_led_info->state = HPC_LED_OFF;
17991708Sstevel break;
18001708Sstevel case LED_ON:
18011708Sstevel hpc_led_info->state = HPC_LED_OFF;
18021708Sstevel break;
18031708Sstevel case LED_FLASH:
18041708Sstevel hpc_led_info->state = HPC_LED_ON;
18051708Sstevel break;
18061708Sstevel }
18071708Sstevel break;
18081708Sstevel case HPC_ACTIVE_LED:
18091708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
18101708Sstevel case LED_OFF:
18111708Sstevel hpc_led_info->state = HPC_LED_OFF;
18121708Sstevel break;
18131708Sstevel case LED_ON:
18141708Sstevel hpc_led_info->state = HPC_LED_ON;
18151708Sstevel break;
18161708Sstevel case LED_FLASH:
18171708Sstevel hpc_led_info->state = HPC_LED_BLINK;
18181708Sstevel break;
18191708Sstevel }
18201708Sstevel break;
18211708Sstevel default:
18221708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
18231708Sstevel "Invalid LED %x", hpc_led_info->led);
18241708Sstevel
18251708Sstevel mutex_enter(&schpc_p->schpc_mutex);
18261708Sstevel schpc_p->schpc_slot[slot].state &=
18271708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
18281708Sstevel cv_signal(&schpc_p->schpc_cv);
18291708Sstevel mutex_exit(&schpc_p->schpc_mutex);
18301708Sstevel
18311708Sstevel return (HPC_ERR_FAILED);
18321708Sstevel }
18331708Sstevel
18341708Sstevel mutex_enter(&schpc_p->schpc_mutex);
18351708Sstevel schpc_p->schpc_slot[slot].state &=
18361708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
18371708Sstevel cv_signal(&schpc_p->schpc_cv);
18381708Sstevel mutex_exit(&schpc_p->schpc_mutex);
18391708Sstevel
18401708Sstevel return (0);
18411708Sstevel
18421708Sstevel case HPC_CTRL_SET_LED_STATE:
18431708Sstevel hpc_led_info = (hpc_led_info_t *)arg;
18441708Sstevel
18451708Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1846*11311SSurya.Prakki@Sun.COM "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1847*11311SSurya.Prakki@Sun.COM (void *)hpc_led_info);
18481708Sstevel
18491708Sstevel switch (hpc_led_info->led) {
18501708Sstevel case HPC_FAULT_LED:
18511708Sstevel switch (hpc_led_info->state) {
18521708Sstevel case HPC_LED_OFF:
18531708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
18541708Sstevel LED_OFF;
18551708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
18561708Sstevel break;
18571708Sstevel case HPC_LED_ON:
18581708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
18591708Sstevel LED_ON;
18601708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
18611708Sstevel break;
18621708Sstevel case HPC_LED_BLINK:
18631708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
18641708Sstevel LED_FLASH;
18651708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
18661708Sstevel break;
18671708Sstevel }
18681708Sstevel break;
18691708Sstevel case HPC_POWER_LED:
18701708Sstevel switch (hpc_led_info->state) {
18711708Sstevel case HPC_LED_OFF:
18721708Sstevel schpc_p->schpc_slot[slot].led.led_power =
18731708Sstevel LED_OFF;
18741708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
18751708Sstevel break;
18761708Sstevel case HPC_LED_ON:
18771708Sstevel schpc_p->schpc_slot[slot].led.led_power =
18781708Sstevel LED_ON;
18791708Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
18801708Sstevel break;
18811708Sstevel case HPC_LED_BLINK:
18821708Sstevel schpc_p->schpc_slot[slot].led.led_power =
18831708Sstevel LED_FLASH;
18841708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
18851708Sstevel break;
18861708Sstevel }
18871708Sstevel break;
18881708Sstevel case HPC_ATTN_LED:
18891708Sstevel switch (hpc_led_info->state) {
18901708Sstevel case HPC_LED_OFF:
18911708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
18921708Sstevel LED_OFF;
18931708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
18941708Sstevel break;
18951708Sstevel case HPC_LED_ON:
18961708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
18971708Sstevel LED_FLASH;
18981708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
18991708Sstevel break;
19001708Sstevel case HPC_LED_BLINK:
19011708Sstevel schpc_p->schpc_slot[slot].led.led_fault =
19021708Sstevel LED_FLASH;
19031708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
19041708Sstevel break;
19051708Sstevel }
19061708Sstevel break;
19071708Sstevel case HPC_ACTIVE_LED:
19081708Sstevel switch (hpc_led_info->state) {
19091708Sstevel case HPC_LED_OFF:
19101708Sstevel schpc_p->schpc_slot[slot].led.led_service =
19111708Sstevel LED_OFF;
19121708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
19131708Sstevel break;
19141708Sstevel case HPC_LED_ON:
19151708Sstevel schpc_p->schpc_slot[slot].led.led_service =
19161708Sstevel LED_ON;
19171708Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
19181708Sstevel break;
19191708Sstevel case HPC_LED_BLINK:
19201708Sstevel schpc_p->schpc_slot[slot].led.led_service =
19211708Sstevel LED_FLASH;
19221708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
19231708Sstevel break;
19241708Sstevel }
19251708Sstevel break;
19261708Sstevel default:
19271708Sstevel mutex_enter(&schpc_p->schpc_mutex);
19281708Sstevel schpc_p->schpc_slot[slot].state &=
19291708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
19301708Sstevel cv_signal(&schpc_p->schpc_cv);
19311708Sstevel mutex_exit(&schpc_p->schpc_mutex);
19321708Sstevel
19331708Sstevel return (0);
19341708Sstevel }
19351708Sstevel
19361708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
19371708Sstevel
19381708Sstevel mutex_enter(&schpc_p->schpc_mutex);
19391708Sstevel schpc_p->schpc_slot[slot].state &=
19401708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
19411708Sstevel cv_signal(&schpc_p->schpc_cv);
19421708Sstevel mutex_exit(&schpc_p->schpc_mutex);
19431708Sstevel
19441708Sstevel return (0);
19451708Sstevel
19461708Sstevel case HPC_CTRL_ENABLE_AUTOCFG:
19471708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
19481708Sstevel "HPC_CTRL_ENABLE_AUTOCFG");
19491708Sstevel
19501708Sstevel schpc_p->schpc_slot[slot].state |=
19511708Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
19521708Sstevel
19531708Sstevel mutex_enter(&schpc_p->schpc_mutex);
19541708Sstevel schpc_p->schpc_slot[slot].state &=
19551708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
19561708Sstevel cv_signal(&schpc_p->schpc_cv);
19571708Sstevel mutex_exit(&schpc_p->schpc_mutex);
19581708Sstevel
19591708Sstevel return (0);
19601708Sstevel
19611708Sstevel case HPC_CTRL_DISABLE_AUTOCFG:
19621708Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
19631708Sstevel "HPC_CTRL_DISABLE_AUTOCFG");
19641708Sstevel schpc_p->schpc_slot[slot].state &=
19651708Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
19661708Sstevel
19671708Sstevel mutex_enter(&schpc_p->schpc_mutex);
19681708Sstevel schpc_p->schpc_slot[slot].state &=
19691708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
19701708Sstevel cv_signal(&schpc_p->schpc_cv);
19711708Sstevel mutex_exit(&schpc_p->schpc_mutex);
19721708Sstevel
19731708Sstevel return (0);
19741708Sstevel
19751708Sstevel case HPC_CTRL_DISABLE_ENUM:
19761708Sstevel case HPC_CTRL_ENABLE_ENUM:
19771708Sstevel default:
19781708Sstevel mutex_enter(&schpc_p->schpc_mutex);
19791708Sstevel schpc_p->schpc_slot[slot].state &=
19801708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
19811708Sstevel cv_signal(&schpc_p->schpc_cv);
19821708Sstevel mutex_exit(&schpc_p->schpc_mutex);
19831708Sstevel
19841708Sstevel return (HPC_ERR_NOTSUPPORTED);
19851708Sstevel }
19861708Sstevel }
19871708Sstevel
19881708Sstevel /*
19891708Sstevel * schpc_test
19901708Sstevel *
19911708Sstevel * Tests the slot.
19921708Sstevel */
19931708Sstevel /*ARGSUSED*/
19941708Sstevel static void
schpc_test(caddr_t ops_arg,int slot,void * data,uint_t flags)19951708Sstevel schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags)
19961708Sstevel {
19971708Sstevel pci_getslot_t slotstatus;
19981708Sstevel pci_setslot_t setslot;
19991708Sstevel int expander, board;
20001708Sstevel int rval;
20011708Sstevel int retry = 1;
20021708Sstevel
20031708Sstevel SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)",
2004*11311SSurya.Prakki@Sun.COM (void *)ops_arg, SCHPC_SLOT_NUM(slot));
20051708Sstevel
20061708Sstevel SCHPC_DEBUG3(D_IOC_TEST,
20071708Sstevel " schpc_test() Expander=%d Board=%d Slot=%d",
20081708Sstevel schpc_p->schpc_slot[slot].expander,
20091708Sstevel schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot));
20101708Sstevel
20111708Sstevel expander = schpc_p->schpc_slot[slot].expander;
20121708Sstevel board = schpc_p->schpc_slot[slot].board;
20131708Sstevel
20141708Sstevel restart_test:
20151708Sstevel /*
20161708Sstevel * Initial the slot with its occupant and receptacle in good condition.
20171708Sstevel */
20181708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_REC_GOOD;
20191708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_OCC_GOOD;
20201708Sstevel
20211708Sstevel
20221708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
20231708Sstevel
20241708Sstevel if (rval) {
20251708Sstevel /*
20261708Sstevel * System Controller/Mailbox failure.
20271708Sstevel */
20281708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
20291708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
20301708Sstevel "Communicate with System Controller", expander, board,
20311708Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
20321708Sstevel
20331708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
20341708Sstevel return;
20351708Sstevel }
20361708Sstevel
20371708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
20381708Sstevel
20391708Sstevel cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
20401708Sstevel "is not hot pluggable\n", expander, board,
20411708Sstevel SCHPC_SLOT_NUM(slot));
20421708Sstevel
20431708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
20441708Sstevel return;
20451708Sstevel }
20461708Sstevel
20471708Sstevel switch (slotstatus.slot_condition) {
20481708Sstevel case PCIMSG_SLOTCOND_OCC_FAIL:
20491708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
20501708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
20511708Sstevel "System Controller/Occupant Failed",
20521708Sstevel expander, board, SCHPC_SLOT_NUM(slot),
20531708Sstevel schpc_p->schpc_slot[slot].ap_id);
20541708Sstevel
20551708Sstevel schpc_setslotled(expander, board, slot,
20561708Sstevel (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON));
20571708Sstevel
20581708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_OCC_GOOD;
20591708Sstevel return;
20601708Sstevel case PCIMSG_SLOTCOND_REC_FAIL:
20611708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
20621708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
20631708Sstevel "System Controller/Receptacle Failed",
20641708Sstevel expander, board, SCHPC_SLOT_NUM(slot),
20651708Sstevel schpc_p->schpc_slot[slot].ap_id);
20661708Sstevel
20671708Sstevel schpc_setslotled(expander, board, slot,
20681708Sstevel (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON));
20691708Sstevel
20701708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
20711708Sstevel return;
20721708Sstevel case PCIMSG_SLOTCOND_NOHOTPLUG:
20731708Sstevel cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
20741708Sstevel "is not hot pluggable\n", expander, board,
20751708Sstevel SCHPC_SLOT_NUM(slot));
20761708Sstevel
20771708Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
20781708Sstevel return;
20791708Sstevel }
20801708Sstevel
20811708Sstevel if (slotstatus.slot_power_on) {
20821708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
20831708Sstevel
20841708Sstevel if (!slotstatus.slot_HEALTHY) {
20851708Sstevel /*
20861708Sstevel * cPCI Adapter is not asserting HEALTHY#.
20871708Sstevel */
20881708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
20891708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
20901708Sstevel "PCI adapter not HEALTHY", expander, board,
20911708Sstevel SCHPC_SLOT_NUM(slot),
20921708Sstevel schpc_p->schpc_slot[slot].ap_id);
20931708Sstevel
20941708Sstevel schpc_setslotled(expander, board, slot,
20951708Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
20961708Sstevel
20971708Sstevel schpc_p->schpc_slot[slot].state &=
20981708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
20991708Sstevel
21001708Sstevel return;
21011708Sstevel }
21021708Sstevel
21031708Sstevel if (!slotstatus.slot_powergood) {
21041708Sstevel /*
21051708Sstevel * PCI Power Input is not good.
21061708Sstevel */
21071708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
21081708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
21091708Sstevel "System Controller PCI Power Input Not Good",
21101708Sstevel expander, board, SCHPC_SLOT_NUM(slot),
21111708Sstevel schpc_p->schpc_slot[slot].ap_id);
21121708Sstevel
21131708Sstevel schpc_setslotled(expander, board, slot,
21141708Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
21151708Sstevel
21161708Sstevel schpc_p->schpc_slot[slot].state &=
21171708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
21181708Sstevel
21191708Sstevel return;
21201708Sstevel }
21211708Sstevel
21221708Sstevel if (slotstatus.slot_powerfault) {
21231708Sstevel /*
21241708Sstevel * PCI Power Fault.
21251708Sstevel */
21261708Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
21271708Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
21281708Sstevel "System Controller PCI Power Fault",
21291708Sstevel expander, board, SCHPC_SLOT_NUM(slot),
21301708Sstevel schpc_p->schpc_slot[slot].ap_id);
21311708Sstevel
21321708Sstevel schpc_setslotled(expander, board, slot,
21331708Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
21341708Sstevel
21351708Sstevel schpc_p->schpc_slot[slot].state &=
21361708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
21371708Sstevel
21381708Sstevel return;
21391708Sstevel }
21401708Sstevel }
21411708Sstevel
21421708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0");
21431708Sstevel
21441708Sstevel /*
21451708Sstevel * Is the slot empty?
21461708Sstevel */
21471708Sstevel if (slotstatus.slot_empty) {
21481708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty");
21491708Sstevel
21501708Sstevel schpc_p->schpc_slot[slot].state &=
21511708Sstevel ~SCHPC_SLOTSTATE_PRESENT;
21521708Sstevel
21531708Sstevel if (slotstatus.slot_power_on) {
21541708Sstevel
21551708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot "
21561708Sstevel "is powered ON");
21571708Sstevel
21581708Sstevel /*
21591708Sstevel * Tests will be retried once after powering off
21601708Sstevel * an empty slot.
21611708Sstevel */
21621708Sstevel if (retry) {
21631708Sstevel
21641708Sstevel /*
21651708Sstevel * Turn off the slot and restart test.
21661708Sstevel */
21671708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() "
21681708Sstevel "Turning Empty Slot OFF");
21691708Sstevel
21701708Sstevel schpc_init_setslot_message(&setslot);
21711708Sstevel setslot.slot_power_off = PCIMSG_ON;
21721708Sstevel (void) schpc_setslotstatus(
21731708Sstevel expander, board, slot, &setslot);
21741708Sstevel
21751708Sstevel retry = 0;
21761708Sstevel
21771708Sstevel goto restart_test;
21781708Sstevel }
21791708Sstevel }
21801708Sstevel } else {
21811708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present");
21821708Sstevel
21831708Sstevel if (!slotstatus.slot_power_on) {
21841708Sstevel if (retry) {
21851708Sstevel /*
21861708Sstevel * If there is a cassette present and the
21871708Sstevel * power is off, try turning the power on and
21881708Sstevel * restart the test. This allows access to
21891708Sstevel * the FRUID when an empty cassette is
21901708Sstevel * installed.
21911708Sstevel */
21921708Sstevel SCHPC_DEBUG0(D_IOC_TEST,
21931708Sstevel "schpc_test() Power On Adapter");
21941708Sstevel schpc_init_setslot_message(&setslot);
21951708Sstevel setslot.slot_power_on = PCIMSG_ON;
21961708Sstevel (void) schpc_setslotstatus(
21971708Sstevel expander, board, slot, &setslot);
21981708Sstevel retry = 0;
21991708Sstevel goto restart_test;
22001708Sstevel }
22011708Sstevel }
22021708Sstevel
22031708Sstevel schpc_p->schpc_slot[slot].state |=
22041708Sstevel SCHPC_SLOTSTATE_PRESENT;
22051708Sstevel }
22061708Sstevel
22071708Sstevel /*
22081708Sstevel * Is the slot powered up?
22091708Sstevel */
22101708Sstevel schpc_init_setslot_message(&setslot);
22111708Sstevel
22121708Sstevel if (slotstatus.slot_power_on) {
22131708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On");
22141708Sstevel
22151708Sstevel schpc_p->schpc_slot[slot].state |=
22161708Sstevel SCHPC_SLOTSTATE_CONNECTED;
22171708Sstevel
22181708Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
22191708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
22201708Sstevel setslot.slot_enable_ENUM = PCIMSG_ON;
22211708Sstevel setslot.slot_enable_HEALTHY = PCIMSG_ON;
22221708Sstevel } else {
22231708Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off");
22241708Sstevel
22251708Sstevel schpc_p->schpc_slot[slot].state &=
22261708Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
22271708Sstevel
22281708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
22291708Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
22301708Sstevel setslot.slot_disable_ENUM = PCIMSG_ON;
22311708Sstevel setslot.slot_disable_HEALTHY = PCIMSG_ON;
22321708Sstevel }
22331708Sstevel
22341708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
22351708Sstevel
22361708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
22371708Sstevel
22381708Sstevel /*
22391708Sstevel * Save LED State.
22401708Sstevel */
22411708Sstevel switch (setslot.slot_led_power) {
22421708Sstevel case PCIMSG_LED_ON:
22431708Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_ON;
22441708Sstevel break;
22451708Sstevel case PCIMSG_LED_OFF:
22461708Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_OFF;
22471708Sstevel break;
22481708Sstevel case PCIMSG_LED_FLASH:
22491708Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_FLASH;
22501708Sstevel break;
22511708Sstevel }
22521708Sstevel switch (setslot.slot_led_service) {
22531708Sstevel case PCIMSG_LED_ON:
22541708Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_ON;
22551708Sstevel break;
22561708Sstevel case PCIMSG_LED_OFF:
22571708Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_OFF;
22581708Sstevel break;
22591708Sstevel case PCIMSG_LED_FLASH:
22601708Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_FLASH;
22611708Sstevel break;
22621708Sstevel }
22631708Sstevel switch (setslot.slot_led_fault) {
22641708Sstevel case PCIMSG_LED_ON:
22651708Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_ON;
22661708Sstevel break;
22671708Sstevel case PCIMSG_LED_OFF:
22681708Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_OFF;
22691708Sstevel break;
22701708Sstevel case PCIMSG_LED_FLASH:
22711708Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH;
22721708Sstevel break;
22731708Sstevel }
22741708Sstevel }
22751708Sstevel
22761708Sstevel
22771708Sstevel /*
22781708Sstevel * schpc_event_handler
22791708Sstevel *
22801708Sstevel * Placed on the schpc_event_taskq by schpc_event_filter when an
22811708Sstevel * unsolicited MBOXSC_MSG_EVENT is received from the SC. It handles
22821708Sstevel * things like power insertion/removal, ENUM#, etc.
22831708Sstevel */
22841708Sstevel static void
schpc_event_handler(void * arg)22851708Sstevel schpc_event_handler(void *arg)
22861708Sstevel {
22871708Sstevel pci_getslot_t slotstatus;
22881708Sstevel uint8_t expander, board, slot;
22891708Sstevel int rval;
22901708Sstevel pcimsg_t *event = (pcimsg_t *)arg;
22911708Sstevel
22921708Sstevel /*
22931708Sstevel * OK, we got an event message. Since the event message only tells
22941708Sstevel * us something has changed and not changed to what, we need to get
22951708Sstevel * the current slot status to find how WHAT was change to WHAT.
22961708Sstevel */
22971708Sstevel
22981708Sstevel slot = event->pcimsg_slot;
22991708Sstevel expander = event->pcimsg_node; /* get expander */
23001708Sstevel board = event->pcimsg_board; /* get board */
23011708Sstevel
23021708Sstevel SCHPC_DEBUG3(D_EVENT,
23031708Sstevel "schpc_event_handler() - exp=%d board=%d slot=%d",
23041708Sstevel expander, board, slot);
23051708Sstevel
23061708Sstevel /* create a slot table index */
23071708Sstevel slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot);
23081708Sstevel
23091708Sstevel SCHPC_DEBUG1(D_EVENT,
23101708Sstevel "schpc_event_handler() - expanded slot %d", slot);
23111708Sstevel
23121708Sstevel if (schpc_p == NULL) {
23131708Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc");
23141708Sstevel kmem_free(event, sizeof (pcimsg_t));
23151708Sstevel return;
23161708Sstevel }
23171708Sstevel
23181708Sstevel mutex_enter(&schpc_p->schpc_mutex);
23191708Sstevel
23201708Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
23211708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited");
23221708Sstevel mutex_exit(&schpc_p->schpc_mutex);
23231708Sstevel kmem_free(event, sizeof (pcimsg_t));
23241708Sstevel return;
23251708Sstevel }
23261708Sstevel /*
23271708Sstevel * Block if another thread is executing a HPC command.
23281708Sstevel */
23291708Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
23301708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy");
23311708Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
23321708Sstevel }
23331708Sstevel
23341708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
23351708Sstevel
23361708Sstevel mutex_exit(&schpc_p->schpc_mutex);
23371708Sstevel
23381708Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
23391708Sstevel
23401708Sstevel if (rval) {
23411708Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not get status "
23421708Sstevel "for expander=%d board=%d slot=%d\n",
23431708Sstevel expander, board, SCHPC_SLOT_NUM(slot));
23441708Sstevel
23451708Sstevel mutex_enter(&schpc_p->schpc_mutex);
23461708Sstevel schpc_p->schpc_slot[slot].state &=
23471708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
23481708Sstevel cv_signal(&schpc_p->schpc_cv);
23491708Sstevel mutex_exit(&schpc_p->schpc_mutex);
23501708Sstevel kmem_free(event, sizeof (pcimsg_t));
23511708Sstevel return;
23521708Sstevel }
23531708Sstevel
23541708Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
23551708Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not get good "
23561708Sstevel "status for expander=%d board=%d slot=%d\n",
23571708Sstevel expander, board, SCHPC_SLOT_NUM(slot));
23581708Sstevel
23591708Sstevel mutex_enter(&schpc_p->schpc_mutex);
23601708Sstevel schpc_p->schpc_slot[slot].state &=
23611708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
23621708Sstevel cv_signal(&schpc_p->schpc_cv);
23631708Sstevel mutex_exit(&schpc_p->schpc_mutex);
23641708Sstevel
23651708Sstevel kmem_free(event, sizeof (pcimsg_t));
23661708Sstevel return;
23671708Sstevel }
23681708Sstevel
23691708Sstevel SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d",
23701708Sstevel expander, board, SCHPC_SLOT_NUM(slot));
23711708Sstevel
23721708Sstevel if (schpc_p->schpc_slot[slot].slot_ops == NULL) {
23731708Sstevel SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event "
23741708Sstevel "for unregistered slot for expander=%d board=%d slot=%d",
23751708Sstevel expander, board, SCHPC_SLOT_NUM(slot));
23761708Sstevel
23771708Sstevel mutex_enter(&schpc_p->schpc_mutex);
23781708Sstevel schpc_p->schpc_slot[slot].state &=
23791708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
23801708Sstevel cv_signal(&schpc_p->schpc_cv);
23811708Sstevel mutex_exit(&schpc_p->schpc_mutex);
23821708Sstevel
23831708Sstevel kmem_free(event, sizeof (pcimsg_t));
23841708Sstevel return;
23851708Sstevel }
23861708Sstevel
23871708Sstevel /* Slot Power Event */
23881708Sstevel
23891708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_power) {
23901708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event");
23911708Sstevel /*
23921708Sstevel * The SC may have changed to slot power status.
23931708Sstevel */
23941708Sstevel if (slotstatus.slot_power_on) {
23951708Sstevel schpc_p->schpc_slot[slot].state |=
23961708Sstevel SCHPC_SLOTSTATE_CONNECTED;
23971708Sstevel
2398*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
23991708Sstevel schpc_p->schpc_slot[slot].slot_handle,
24001708Sstevel HPC_EVENT_SLOT_POWER_ON, 0);
24011708Sstevel } else {
24021708Sstevel schpc_p->schpc_slot[slot].state &=
24031708Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
24041708Sstevel
2405*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
24061708Sstevel schpc_p->schpc_slot[slot].slot_handle,
24071708Sstevel HPC_EVENT_SLOT_POWER_OFF, 0);
24081708Sstevel }
24091708Sstevel }
24101708Sstevel
24111708Sstevel /* Adapter Insertion/Removal Event */
24121708Sstevel
24131708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_presence) {
24141708Sstevel if (slotstatus.slot_empty == PCIMSG_ON) {
24151708Sstevel
24161708Sstevel /* Adapter Removed */
24171708Sstevel
24181708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed");
24191708Sstevel
24201708Sstevel if (schpc_p->schpc_slot[slot].state &
24211708Sstevel SCHPC_SLOTSTATE_CONNECTED) {
24221708Sstevel /*
24231708Sstevel * If the adapter has been removed while
24241708Sstevel * there the slot is connected, it could be
24251708Sstevel * due to a ENUM handling.
24261708Sstevel */
24271708Sstevel cmn_err(CE_WARN, "Card removed from "
24281708Sstevel "powered on slot at "
24291708Sstevel "expander=%d board=%d slot=%d\n",
24301708Sstevel expander, board, SCHPC_SLOT_NUM(slot));
24311708Sstevel
24321708Sstevel schpc_p->schpc_slot[slot].state &=
24331708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
24341708Sstevel rval = schpc_disconnect((caddr_t)schpc_p,
24351708Sstevel schpc_p->schpc_slot[slot].slot_handle,
24361708Sstevel 0, 0);
24371708Sstevel mutex_enter(&schpc_p->schpc_mutex);
24381708Sstevel while (schpc_p->schpc_slot[slot].state &
24391708Sstevel SCHPC_SLOTSTATE_EXECUTING) {
24401708Sstevel SCHPC_DEBUG0(D_EVENT,
24411708Sstevel "schpc_event_handler - "
24421708Sstevel "Slot is busy");
24431708Sstevel cv_wait(&schpc_p->schpc_cv,
24441708Sstevel &schpc_p->schpc_mutex);
24451708Sstevel }
24461708Sstevel
24471708Sstevel schpc_p->schpc_slot[slot].state |=
24481708Sstevel SCHPC_SLOTSTATE_EXECUTING;
24491708Sstevel
24501708Sstevel mutex_exit(&schpc_p->schpc_mutex);
24511708Sstevel }
24521708Sstevel schpc_p->schpc_slot[slot].state |=
24531708Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
24541708Sstevel
24551708Sstevel schpc_p->schpc_slot[slot].state &=
24567656SSherry.Moore@Sun.COM ~SCHPC_SLOTSTATE_PRESENT;
24571708Sstevel
2458*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
24591708Sstevel schpc_p->schpc_slot[slot].slot_handle,
24601708Sstevel HPC_EVENT_SLOT_REMOVAL, 0);
24611708Sstevel } else {
24621708Sstevel
24631708Sstevel /* Adapter Inserted */
24641708Sstevel
24651708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted");
24661708Sstevel
24671708Sstevel if (schpc_p->schpc_slot[slot].state &
24681708Sstevel SCHPC_SLOTSTATE_PRESENT) {
24691708Sstevel /*
24701708Sstevel * If the adapter is already present
24711708Sstevel * throw the this event away.
24721708Sstevel */
24731708Sstevel
24741708Sstevel SCHPC_DEBUG0(D_EVENT,
24751708Sstevel "Adapter is already present");
24761708Sstevel
24771708Sstevel mutex_enter(&schpc_p->schpc_mutex);
24781708Sstevel schpc_p->schpc_slot[slot].state &=
24791708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
24801708Sstevel cv_signal(&schpc_p->schpc_cv);
24811708Sstevel mutex_exit(&schpc_p->schpc_mutex);
24821708Sstevel
24831708Sstevel kmem_free(event, sizeof (pcimsg_t));
24841708Sstevel return;
24851708Sstevel }
24861708Sstevel
24871708Sstevel schpc_p->schpc_slot[slot].state |=
24881708Sstevel SCHPC_SLOTSTATE_PRESENT;
24891708Sstevel
24901708Sstevel schpc_p->schpc_slot[slot].state &=
24911708Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
24921708Sstevel
2493*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
24941708Sstevel schpc_p->schpc_slot[slot].slot_handle,
24951708Sstevel HPC_EVENT_SLOT_INSERTION, 0);
24961708Sstevel
24971708Sstevel if (schpc_p->schpc_slot[slot].state &
24981708Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE) {
24991708Sstevel SCHPC_DEBUG0(D_EVENT, "Auto Configuration "
25001708Sstevel "(Connect/Configure) Started");
25011708Sstevel
25021708Sstevel schpc_p->schpc_slot[slot].state &=
25031708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
25041708Sstevel
25051708Sstevel rval = schpc_connect((caddr_t)schpc_p,
25061708Sstevel schpc_p->schpc_slot[slot].slot_handle,
25071708Sstevel 0, 0);
25081708Sstevel
25091708Sstevel if (rval) {
25101708Sstevel cmn_err(CE_WARN, "schpc/Event Handler -"
25111708Sstevel " Can not connect");
25121708Sstevel
25131708Sstevel mutex_enter(&schpc_p->schpc_mutex);
25141708Sstevel schpc_p->schpc_slot[slot].state &=
25151708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
25161708Sstevel cv_signal(&schpc_p->schpc_cv);
25171708Sstevel mutex_exit(&schpc_p->schpc_mutex);
25181708Sstevel
25191708Sstevel kmem_free(event, sizeof (pcimsg_t));
25201708Sstevel return;
25211708Sstevel }
25221708Sstevel mutex_enter(&schpc_p->schpc_mutex);
25231708Sstevel while (schpc_p->schpc_slot[slot].state &
25241708Sstevel SCHPC_SLOTSTATE_EXECUTING) {
25251708Sstevel SCHPC_DEBUG0(D_EVENT,
25261708Sstevel "schpc_event_handler - "
25271708Sstevel "Slot is busy");
25281708Sstevel cv_wait(&schpc_p->schpc_cv,
25291708Sstevel &schpc_p->schpc_mutex);
25301708Sstevel }
25311708Sstevel
25321708Sstevel schpc_p->schpc_slot[slot].state |=
25331708Sstevel SCHPC_SLOTSTATE_EXECUTING;
25341708Sstevel
25351708Sstevel mutex_exit(&schpc_p->schpc_mutex);
25361708Sstevel
2537*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
25381708Sstevel schpc_p->schpc_slot[slot].slot_handle,
25391708Sstevel HPC_EVENT_SLOT_CONFIGURE, 0);
25401708Sstevel } else {
25411708Sstevel schpc_setslotled(expander, board, slot,
25421708Sstevel SERVICE_LED_ON);
25431708Sstevel }
25441708Sstevel }
25451708Sstevel }
25461708Sstevel
25471708Sstevel /* ENUM# signal change event */
25481708Sstevel
25491708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) {
25501708Sstevel /*
25511708Sstevel * ENUM should only be received to the adapter remove
25521708Sstevel * procedure.
25531708Sstevel */
25541708Sstevel
25551708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted");
25561708Sstevel
25571708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_FLASH);
25581708Sstevel
25591708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM;
25601708Sstevel
2561*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
25621708Sstevel schpc_p->schpc_slot[slot].slot_handle,
25631708Sstevel HPC_EVENT_SLOT_ENUM, 0);
25641708Sstevel }
25651708Sstevel
25661708Sstevel /* HEALTHY# signal change event */
25671708Sstevel
25681708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) {
25691708Sstevel
25701708Sstevel if (!slotstatus.slot_HEALTHY) {
25711708Sstevel
25721708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED");
25731708Sstevel
25741708Sstevel schpc_p->schpc_slot[slot].state &=
25751708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
25761708Sstevel
2577*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
25781708Sstevel schpc_p->schpc_slot[slot].slot_handle,
25791708Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0);
25801708Sstevel
25811708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
25821708Sstevel } else {
25831708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK");
25841708Sstevel
25851708Sstevel schpc_p->schpc_slot[slot].state |=
25861708Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
25871708Sstevel
2588*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
25891708Sstevel schpc_p->schpc_slot[slot].slot_handle,
25901708Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0);
25911708Sstevel
25921708Sstevel schpc_setslotled(expander, board, slot,
25931708Sstevel FAULT_LED_OFF);
25941708Sstevel }
25951708Sstevel }
25961708Sstevel
25971708Sstevel /* Good Power change event */
25981708Sstevel
25991708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) {
26001708Sstevel if (slotstatus.slot_powergood == PCIMSG_ON) {
26011708Sstevel
26021708Sstevel SCHPC_DEBUG0(D_EVENT,
26031708Sstevel "Event Type: Slot Power Good Detected");
26041708Sstevel
26051708Sstevel schpc_p->schpc_slot[slot].state |=
26061708Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
26071708Sstevel
2608*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
26091708Sstevel schpc_p->schpc_slot[slot].slot_handle,
26101708Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0);
26111708Sstevel
26121708Sstevel schpc_setslotled(expander, board, slot,
26131708Sstevel FAULT_LED_OFF);
26141708Sstevel } else {
26151708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good "
26161708Sstevel "Detected");
26171708Sstevel
26181708Sstevel if (schpc_p->schpc_slot[slot].state &
26191708Sstevel SCHPC_SLOTSTATE_CONNECTED) {
26201708Sstevel
26211708Sstevel SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: "
26221708Sstevel "power failed");
26231708Sstevel
26241708Sstevel schpc_p->schpc_slot[slot].state &=
26251708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
26261708Sstevel
2627*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
26281708Sstevel schpc_p->schpc_slot[slot].slot_handle,
26291708Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0);
26301708Sstevel
26311708Sstevel schpc_setslotled(expander, board, slot,
26321708Sstevel FAULT_LED_ON);
26331708Sstevel }
26341708Sstevel }
26351708Sstevel }
26361708Sstevel
26371708Sstevel /* Power Fault change event */
26381708Sstevel
26391708Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) {
26401708Sstevel if (slotstatus.slot_powerfault == PCIMSG_ON) {
26411708Sstevel
26421708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
26431708Sstevel "Detected");
26441708Sstevel
26451708Sstevel schpc_p->schpc_slot[slot].state &=
26461708Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
26471708Sstevel
2648*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
26491708Sstevel schpc_p->schpc_slot[slot].slot_handle,
26501708Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0);
26511708Sstevel
26521708Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
26531708Sstevel } else {
26541708Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
26551708Sstevel "Cleared");
26561708Sstevel
26571708Sstevel schpc_p->schpc_slot[slot].state |=
26581708Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
26591708Sstevel
2660*11311SSurya.Prakki@Sun.COM (void) hpc_slot_event_notify(
26611708Sstevel schpc_p->schpc_slot[slot].slot_handle,
26621708Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0);
26631708Sstevel
26641708Sstevel schpc_setslotled(expander, board, slot,
26651708Sstevel FAULT_LED_OFF);
26661708Sstevel }
26671708Sstevel }
26681708Sstevel mutex_enter(&schpc_p->schpc_mutex);
26691708Sstevel schpc_p->schpc_slot[slot].state &=
26701708Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
26711708Sstevel cv_signal(&schpc_p->schpc_cv);
26721708Sstevel mutex_exit(&schpc_p->schpc_mutex);
26731708Sstevel
26741708Sstevel kmem_free(event, sizeof (pcimsg_t));
26751708Sstevel }
26761708Sstevel
26771708Sstevel
26781708Sstevel /*
26791708Sstevel * schpc_event_filter
26801708Sstevel *
26811708Sstevel * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the
26821708Sstevel * schpc_event_taskq for processing by the schpc_event_handler _if_
26831708Sstevel * hotpluggable pci slots have been registered; otherwise, the
26841708Sstevel * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox
26851708Sstevel * open for future messages.
26861708Sstevel */
26871708Sstevel static void
schpc_event_filter(pcimsg_t * pmsg)26881708Sstevel schpc_event_filter(pcimsg_t *pmsg)
26891708Sstevel {
26901708Sstevel if (slots_registered == B_TRUE) {
26911708Sstevel
26921708Sstevel pcimsg_t *pevent;
26931708Sstevel
26941708Sstevel /*
26951708Sstevel * If hotpluggable pci slots have been registered then enqueue
26961708Sstevel * the event onto the schpc_event_taskq for processing.
26971708Sstevel */
26981708Sstevel
26991708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
27001708Sstevel "slots_registered = B_TRUE");
27011708Sstevel
27021708Sstevel pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP);
27031708Sstevel bcopy(pmsg, pevent, sizeof (pcimsg_t));
27041708Sstevel
27051708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
27061708Sstevel "event alloc'd");
27071708Sstevel
27081708Sstevel if (taskq_dispatch(schpc_event_taskq, schpc_event_handler,
27091708Sstevel (void *)pevent, TQ_SLEEP) == NULL) {
27101708Sstevel cmn_err(CE_WARN, "schpc: schpc_event_filter - "
27111708Sstevel "taskq_dispatch failed to enqueue event");
27121708Sstevel kmem_free(pevent, sizeof (pcimsg_t));
27131708Sstevel return;
27141708Sstevel }
27151708Sstevel
27161708Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
27171708Sstevel "event was taskq_dispatch'ed to schpc_event_handler");
27181708Sstevel } else {
27191708Sstevel /*
27201708Sstevel * Oops, schpc received an event _before_ the slots have been
27211708Sstevel * registered. In that case there is no choice but to toss
27221708Sstevel * the event.
27231708Sstevel */
27241708Sstevel cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding "
27251708Sstevel "premature event");
27261708Sstevel }
27271708Sstevel }
27281708Sstevel
27291708Sstevel
27301708Sstevel /*
27311708Sstevel * schpc_msg_thread
27321708Sstevel * A stand-alone thread that monitors the incoming mailbox for
27331708Sstevel * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from
27341708Sstevel * the mailbox for processing.
27351708Sstevel *
27361708Sstevel * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the
27371708Sstevel * schpc_replylist, and the waiting thread is notified that its REPLY
27381708Sstevel * message has arrived; otherwise, if no REPLY match is found, then it is
27391708Sstevel * discarded.
27401708Sstevel *
27411708Sstevel * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed
27421708Sstevel * by the schpc_event_handler.
27431708Sstevel *
27441708Sstevel * The schpc_msg_thread is started in _init().
27451708Sstevel */
27461708Sstevel void
schpc_msg_thread(void)27471708Sstevel schpc_msg_thread(void)
27481708Sstevel {
27491708Sstevel int err;
27501708Sstevel uint32_t type;
27511708Sstevel uint32_t cmd;
27521708Sstevel uint64_t transid;
27531708Sstevel uint32_t length;
27541708Sstevel pcimsg_t msg;
27551708Sstevel
27561708Sstevel SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running");
27571708Sstevel
27581708Sstevel /* CONSTCOND */
27591708Sstevel while (1) {
27601708Sstevel
27611708Sstevel /* setup wildcard arguments */
27621708Sstevel type = 0;
27631708Sstevel cmd = 0;
27641708Sstevel transid = 0;
27651708Sstevel length = sizeof (pcimsg_t);
27661708Sstevel bzero(&msg, sizeof (pcimsg_t));
27671708Sstevel
27681708Sstevel err = mboxsc_getmsg(KEY_SCPC, &type, &cmd,
27697656SSherry.Moore@Sun.COM &transid, &length, (void *)&msg,
27707656SSherry.Moore@Sun.COM schpc_timeout_getmsg);
27711708Sstevel
27721708Sstevel if (err) {
27731708Sstevel switch (err) {
27741708Sstevel
27751708Sstevel /*FALLTHROUGH*/
27761708Sstevel case ETIMEDOUT:
27771708Sstevel case EAGAIN:
27781708Sstevel continue;
27791708Sstevel
27801708Sstevel default:
27811708Sstevel /*
27821708Sstevel * unfortunately, we can't do very much here
27831708Sstevel * because we're wildcarding mboxsc_getmsg
27841708Sstevel * so if it encounters an error, we can't
27851708Sstevel * identify which transid it belongs to.
27861708Sstevel */
27871708Sstevel cmn_err(CE_WARN,
27881708Sstevel "schpc - mboxsc_getmsg failed, err=0x%x", err);
27891708Sstevel delay(drv_usectohz(100000));
27901708Sstevel continue;
27911708Sstevel }
27921708Sstevel }
27931708Sstevel
27941708Sstevel if (msg.pcimsg_revision != PCIMSG_REVISION) {
27951708Sstevel /*
27961708Sstevel * This version of the schpc driver only understands
27971708Sstevel * version 1.0 of the PCI Hot Plug Message format.
27981708Sstevel */
27991708Sstevel cmn_err(CE_WARN, " schpc: schpc_msg_thread - "
28001708Sstevel "discarding event w/ unknown message version %x",
28011708Sstevel msg.pcimsg_revision);
28021708Sstevel continue;
28031708Sstevel }
28041708Sstevel
28051708Sstevel switch (type) {
28061708Sstevel
28071708Sstevel case MBOXSC_MSG_EVENT:
28081708Sstevel schpc_event_filter(&msg);
28091708Sstevel break;
28101708Sstevel
28111708Sstevel case MBOXSC_MSG_REPLY:
28121708Sstevel schpc_reply_handler(&msg, type, cmd, transid, length);
28131708Sstevel break;
28141708Sstevel
28151708Sstevel default:
28161708Sstevel cmn_err(CE_WARN,
28171708Sstevel "schpc - mboxsc_getmsg unknown msg"
28181708Sstevel " type=0x%x", type);
28191708Sstevel break;
28201708Sstevel }
28211708Sstevel }
28221708Sstevel /* this thread never exits */
28231708Sstevel }
28241708Sstevel
28251708Sstevel
28261708Sstevel void
schpc_reply_handler(pcimsg_t * pmsg,uint32_t type,uint32_t cmd,uint64_t transid,uint32_t length)28271708Sstevel schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
28281708Sstevel uint64_t transid, uint32_t length)
28291708Sstevel {
28301708Sstevel schpc_replylist_t *entry;
28311708Sstevel
28321708Sstevel mutex_enter(&schpc_replylist_mutex);
28331708Sstevel entry = schpc_replylist_first;
28341708Sstevel while (entry != NULL) {
28351708Sstevel if (entry->transid == transid) {
28361708Sstevel break;
28371708Sstevel } else
28381708Sstevel entry = entry->next;
28391708Sstevel }
28401708Sstevel if (entry) {
28411708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
28421708Sstevel "schpc_reply_handler() - 0x%lx transid reply "
28431708Sstevel "received", transid);
28441708Sstevel
28451708Sstevel mutex_enter(&entry->reply_lock);
28461708Sstevel if (entry->reply_cexit == B_FALSE) {
28471708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
28481708Sstevel "schpc_reply_handler() - 0x%lx transid"
28491708Sstevel " cv_signal waiting thread", transid);
28501708Sstevel
28511708Sstevel /*
28521708Sstevel * emulate mboxsc_getmsg by copying the reply
28531708Sstevel */
28541708Sstevel entry->type = type;
28551708Sstevel entry->cmd = cmd;
28561708Sstevel entry->transid = transid;
28571708Sstevel entry->length = length;
28581708Sstevel bcopy((caddr_t)pmsg, &entry->reply, length);
28591708Sstevel
28601708Sstevel /* reply was received */
28611708Sstevel entry->reply_recvd = B_TRUE;
28621708Sstevel
28631708Sstevel /*
28641708Sstevel * wake up thread waiting for reply with transid
28651708Sstevel */
28661708Sstevel cv_signal(&entry->reply_cv);
28671708Sstevel }
28681708Sstevel mutex_exit(&entry->reply_lock);
28691708Sstevel } else {
28701708Sstevel cmn_err(CE_WARN, "schpc - no match for transid 0x%lx",
28711708Sstevel transid);
28721708Sstevel }
28731708Sstevel mutex_exit(&schpc_replylist_mutex);
28741708Sstevel }
28751708Sstevel
28761708Sstevel
28771708Sstevel /*
28781708Sstevel * schpc_putrequest
28791708Sstevel *
28801708Sstevel * A wrapper around the synchronous call mboxsc_putmsg().
28811708Sstevel */
28821708Sstevel int
schpc_putrequest(uint32_t key,uint32_t type,uint32_t cmd,uint64_t * transidp,uint32_t length,void * datap,clock_t timeout,schpc_replylist_t ** entryp)28831708Sstevel schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
28841708Sstevel uint32_t length, void *datap, clock_t timeout,
28851708Sstevel schpc_replylist_t **entryp)
28861708Sstevel {
28871708Sstevel int rval;
28881708Sstevel
28891708Sstevel /* add the request to replylist to keep track of outstanding requests */
28901708Sstevel *entryp = schpc_replylist_link(cmd, *transidp, length);
28911708Sstevel
28921708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
28931708Sstevel "0x%lx transid mboxsc_putmsg called", *transidp);
28941708Sstevel
28951708Sstevel /* wait synchronously for request to be sent */
28961708Sstevel rval = mboxsc_putmsg(key, type, cmd, transidp, length,
28977656SSherry.Moore@Sun.COM (void *)datap, timeout);
28981708Sstevel
28991708Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
29001708Sstevel "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval);
29011708Sstevel
29021708Sstevel /* if problem is encountered then remove the request from replylist */
29031708Sstevel if (rval)
29041708Sstevel schpc_replylist_unlink(*entryp);
29051708Sstevel
29061708Sstevel return (rval);
29071708Sstevel }
29081708Sstevel
29091708Sstevel
29101708Sstevel /*
29111708Sstevel * schpc_getreply
29121708Sstevel *
29131708Sstevel * Wait for the schpc_msg_thread to respond that a matching reply has
29141708Sstevel * arrived; otherwise, timeout and remove the entry from the schpc_replylist.
29151708Sstevel */
29161708Sstevel /*ARGSUSED*/
29171708Sstevel int
schpc_getreply(uint32_t key,uint32_t * typep,uint32_t * cmdp,uint64_t * transidp,uint32_t * lengthp,void * datap,clock_t timeout,schpc_replylist_t * listp)29181708Sstevel schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
29191708Sstevel uint64_t *transidp, uint32_t *lengthp, void *datap,
29201708Sstevel clock_t timeout, schpc_replylist_t *listp)
29211708Sstevel {
29221708Sstevel int rc = 0;
29231708Sstevel
29241708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
29251708Sstevel "schpc_getreply() - 0x%lx transid waiting for reply",
29261708Sstevel *transidp);
29271708Sstevel
29281708Sstevel /*
29291708Sstevel * wait here until schpc_msg_thread because it's always
29301708Sstevel * looking for reply messages
29311708Sstevel */
29321708Sstevel mutex_enter(&listp->reply_lock);
29331708Sstevel
29341708Sstevel while (listp->reply_recvd == B_FALSE) {
29351708Sstevel /*
29361708Sstevel * wait for reply or timeout
29371708Sstevel */
29381708Sstevel rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock,
29397656SSherry.Moore@Sun.COM ddi_get_lbolt() + drv_usectohz(timeout * 1000));
29401708Sstevel switch (rc) {
29411708Sstevel case -1: /* most likely a timeout, but check anyway */
29421708Sstevel
29431708Sstevel /* message was received after all */
29441708Sstevel if (listp->reply_recvd == B_TRUE)
29451708Sstevel break;
29461708Sstevel
29471708Sstevel /* no, it's really a timeout */
29481708Sstevel listp->reply_cexit = B_TRUE;
29491708Sstevel mutex_exit(&listp->reply_lock);
29501708Sstevel cmn_err(CE_WARN,
29511708Sstevel "schpc - 0x%lx transid reply timed out", *transidp);
29521708Sstevel schpc_replylist_unlink(listp);
29531708Sstevel return (ETIMEDOUT);
29541708Sstevel
29551708Sstevel default:
29561708Sstevel break;
29571708Sstevel }
29581708Sstevel }
29591708Sstevel
29601708Sstevel *typep = listp->type;
29611708Sstevel *cmdp = listp->cmd;
29621708Sstevel *transidp = listp->transid;
29631708Sstevel *lengthp = listp->length;
29641708Sstevel bcopy((caddr_t)&listp->reply, datap, *lengthp);
29651708Sstevel mutex_exit(&listp->reply_lock);
29661708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
29671708Sstevel "schpc_getreply() - 0x%lx transid received", *transidp);
29681708Sstevel schpc_replylist_unlink(listp);
29691708Sstevel return (0);
29701708Sstevel }
29711708Sstevel
29721708Sstevel
29731708Sstevel /*
29741708Sstevel * schpc_replylist_unlink
29751708Sstevel *
29761708Sstevel * Deallocate a schpc_replylist_t element.
29771708Sstevel */
29781708Sstevel void
schpc_replylist_unlink(schpc_replylist_t * entry)29791708Sstevel schpc_replylist_unlink(schpc_replylist_t *entry)
29801708Sstevel {
29811708Sstevel #if DEBUG
29821708Sstevel schpc_replylist_t *dbg_entry;
29831708Sstevel #endif /* DEBUG */
29841708Sstevel
29851708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
29861708Sstevel "schpc_replylist_unlink() - 0x%lx transid deleted from replylist",
29871708Sstevel entry->transid);
29881708Sstevel
29891708Sstevel mutex_enter(&schpc_replylist_mutex);
29901708Sstevel if (entry->prev) {
29911708Sstevel entry->prev->next = entry->next;
29921708Sstevel if (entry->next)
29931708Sstevel entry->next->prev = entry->prev;
29941708Sstevel } else {
29951708Sstevel schpc_replylist_first = entry->next;
29961708Sstevel if (entry->next)
29971708Sstevel entry->next->prev = NULL;
29981708Sstevel }
29991708Sstevel if (entry == schpc_replylist_last) {
30001708Sstevel schpc_replylist_last = entry->prev;
30011708Sstevel }
30021708Sstevel kmem_free(entry, sizeof (schpc_replylist_t));
30031708Sstevel schpc_replylist_count--;
30041708Sstevel
30051708Sstevel #if DEBUG
30061708Sstevel if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
30071708Sstevel dbg_entry = schpc_replylist_first;
30081708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist "
30091708Sstevel "count = %d\n", schpc_replylist_count);
30101708Sstevel while (dbg_entry != NULL) {
30111708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - "
30121708Sstevel "0x%lx transid\n", dbg_entry->transid);
30131708Sstevel dbg_entry = dbg_entry->next;
30141708Sstevel }
30151708Sstevel }
30161708Sstevel #endif /* DEBUG */
30171708Sstevel
30181708Sstevel mutex_exit(&schpc_replylist_mutex);
30191708Sstevel }
30201708Sstevel
30211708Sstevel
30221708Sstevel /*
30231708Sstevel * schpc_replylist_link
30241708Sstevel *
30251708Sstevel * Allocate and initialize a schpc_replylist_t element.
30261708Sstevel */
30271708Sstevel schpc_replylist_t *
schpc_replylist_link(uint32_t cmd,uint64_t transid,uint32_t length)30281708Sstevel schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length)
30291708Sstevel {
30301708Sstevel schpc_replylist_t *entry;
30311708Sstevel #if DEBUG
30321708Sstevel schpc_replylist_t *dbg_entry;
30331708Sstevel #endif /* DEBUG */
30341708Sstevel
30351708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
30361708Sstevel "schpc_replylist_link() - 0x%lx transid inserting into replylist",
30371708Sstevel transid);
30381708Sstevel
30391708Sstevel entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP);
30401708Sstevel mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL);
30411708Sstevel cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL);
30421708Sstevel entry->type = MBOXSC_MSG_REPLY;
30431708Sstevel entry->cmd = cmd;
30441708Sstevel entry->transid = transid;
30451708Sstevel entry->length = length;
30461708Sstevel entry->reply_recvd = B_FALSE;
30471708Sstevel entry->reply_cexit = B_FALSE;
30481708Sstevel
30491708Sstevel mutex_enter(&schpc_replylist_mutex);
30501708Sstevel if (schpc_replylist_last) {
30511708Sstevel entry->prev = schpc_replylist_last;
30521708Sstevel schpc_replylist_last->next = entry;
30531708Sstevel schpc_replylist_last = entry;
30541708Sstevel } else {
30551708Sstevel schpc_replylist_last = schpc_replylist_first = entry;
30561708Sstevel }
30571708Sstevel
30581708Sstevel schpc_replylist_count++;
30591708Sstevel
30601708Sstevel #if DEBUG
30611708Sstevel if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
30621708Sstevel dbg_entry = schpc_replylist_first;
30631708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist "
30641708Sstevel "count = %d\n", schpc_replylist_count);
30651708Sstevel while (dbg_entry != NULL) {
30661708Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_link() - "
30671708Sstevel "0x%lx transid\n", dbg_entry->transid);
30681708Sstevel dbg_entry = dbg_entry->next;
30691708Sstevel }
30701708Sstevel }
30711708Sstevel #endif /* DEBUG */
30721708Sstevel
30731708Sstevel mutex_exit(&schpc_replylist_mutex);
30741708Sstevel
30751708Sstevel return (entry);
30761708Sstevel }
30771708Sstevel
30781708Sstevel
30791708Sstevel /*
30801708Sstevel * schpc_getslotstatus
30811708Sstevel *
30821708Sstevel * Issues a Get Slot Status command to the System Controller
30831708Sstevel * for a specific slot.
30841708Sstevel */
30851708Sstevel static int
schpc_getslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_getslot_t * slotstatus)30861708Sstevel schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
30871708Sstevel pci_getslot_t *slotstatus)
30881708Sstevel {
30891708Sstevel pcimsg_t request;
30901708Sstevel pcimsg_t reply;
30911708Sstevel int rval;
30921708Sstevel uint32_t type, cmd, length;
30931708Sstevel uint64_t transid;
30941708Sstevel schpc_replylist_t *entry;
30951708Sstevel
30961708Sstevel SCHPC_DEBUG4(D_GETSLOTSTATUS,
30971708Sstevel "schpc_getslotstatus(expander=%d board=%d "
30981708Sstevel "slot=%d slotstatus=0x%p", expander, board,
3099*11311SSurya.Prakki@Sun.COM SCHPC_SLOT_NUM(slot), (void *)slotstatus);
31001708Sstevel
31011708Sstevel if (schpc_p == NULL) {
31021708Sstevel return (1);
31031708Sstevel }
31041708Sstevel
31051708Sstevel bzero(&request, sizeof (pcimsg_t));
31061708Sstevel
31071708Sstevel request.pcimsg_node = expander;
31081708Sstevel request.pcimsg_board = board;
31091708Sstevel request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
31101708Sstevel request.pcimsg_revision = PCIMSG_REVISION;
31111708Sstevel request.pcimsg_command = PCIMSG_GETSLOTSTATUS;
31121708Sstevel
31131708Sstevel type = MBOXSC_MSG_REQUEST;
31141708Sstevel cmd = PCIMSG_GETSLOTSTATUS;
31151708Sstevel transid = schpc_gettransid(schpc_p, slot);
31161708Sstevel length = sizeof (pcimsg_t);
31171708Sstevel
31181708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
31191708Sstevel "0x%lx transid schpc_putrequest called", transid);
31201708Sstevel
31211708Sstevel rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
31221708Sstevel (void *)&request, schpc_timeout_putmsg, &entry);
31231708Sstevel
31241708Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
31251708Sstevel "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
31261708Sstevel
31271708Sstevel if (rval) {
31281708Sstevel return (rval);
31291708Sstevel }
31301708Sstevel
31311708Sstevel bzero(&reply, sizeof (pcimsg_t));
31321708Sstevel type = MBOXSC_MSG_REPLY;
31331708Sstevel
31341708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
31351708Sstevel "0x%lx transid schpc_getreply called", transid);
31361708Sstevel
31371708Sstevel rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
31387656SSherry.Moore@Sun.COM (void *)&reply, schpc_timeout_getmsg, entry);
31391708Sstevel
31401708Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
31411708Sstevel "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
31421708Sstevel
31431708Sstevel if (rval == 0) {
31441708Sstevel *slotstatus = reply.pcimsg_type.pcimsg_getslot;
31451708Sstevel
31461708Sstevel SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()");
31471708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_power_on %x",
31481708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_power_on);
31491708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powergood %x",
31501708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_powergood);
31511708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powerfault %x",
31521708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_powerfault);
31531708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_empty %x",
31541708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_empty);
31551708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_cap %x",
31561708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_freq_cap);
31571708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_setting %x",
31581708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_freq_setting);
31591708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_condition %x",
31601708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_condition);
31611708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_HEALTHY %x",
31621708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY);
31631708Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_ENUM %x",
31641708Sstevel reply.pcimsg_type.pcimsg_getslot.slot_ENUM);
31651708Sstevel }
31661708Sstevel
31671708Sstevel return (rval);
31681708Sstevel }
31691708Sstevel
31701708Sstevel
31711708Sstevel /*
31721708Sstevel * schpc_setslotstatus
31731708Sstevel *
31741708Sstevel * Issues a Set Slot Status command to the System Controller
31751708Sstevel * for a specific slot.
31761708Sstevel */
31771708Sstevel static int
schpc_setslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_setslot_t * slotstatus)31781708Sstevel schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
31791708Sstevel pci_setslot_t *slotstatus)
31801708Sstevel {
31811708Sstevel pcimsg_t request;
31821708Sstevel pcimsg_t reply;
31831708Sstevel int rval;
31841708Sstevel uint32_t type, cmd, length;
31851708Sstevel uint64_t transid;
31861708Sstevel schpc_replylist_t *entry;
31871708Sstevel
31881708Sstevel SCHPC_DEBUG4(D_SETSLOTSTATUS,
31891708Sstevel "schpc_setslotstatus(expander=%d board=%d "
31901708Sstevel "slot=%d slotstatus=0x%p", expander, board,
3191*11311SSurya.Prakki@Sun.COM SCHPC_SLOT_NUM(slot), (void *)slotstatus);
31921708Sstevel
31931708Sstevel bzero(&request, sizeof (pcimsg_t));
31941708Sstevel
31951708Sstevel if (schpc_p == NULL) {
31961708Sstevel return (1);
31971708Sstevel }
31981708Sstevel
31991708Sstevel request.pcimsg_node = expander;
32001708Sstevel request.pcimsg_board = board;
32011708Sstevel request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
32021708Sstevel request.pcimsg_revision = PCIMSG_REVISION;
32031708Sstevel request.pcimsg_command = PCIMSG_SETSLOTSTATUS;
32041708Sstevel
32051708Sstevel request.pcimsg_type.pcimsg_setslot = *slotstatus;
32061708Sstevel
32071708Sstevel SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change");
32081708Sstevel SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d",
32091708Sstevel slotstatus->slot_led_power,
32101708Sstevel slotstatus->slot_led_service,
32111708Sstevel slotstatus->slot_led_fault);
32121708Sstevel
32131708Sstevel type = MBOXSC_MSG_REQUEST;
32141708Sstevel cmd = PCIMSG_SETSLOTSTATUS;
32151708Sstevel transid = schpc_gettransid(schpc_p, slot);
32161708Sstevel length = sizeof (pcimsg_t);
32171708Sstevel
32181708Sstevel SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
32191708Sstevel "0x%lx transid schpc_putrequest called", transid);
32201708Sstevel
32211708Sstevel rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
32221708Sstevel (void *)&request, schpc_timeout_putmsg, &entry);
32231708Sstevel
32241708Sstevel SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
32251708Sstevel "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
32261708Sstevel
32271708Sstevel if (rval) {
32281708Sstevel return (rval);
32291708Sstevel }
32301708Sstevel
32311708Sstevel bzero(&reply, sizeof (pcimsg_t));
32321708Sstevel type = MBOXSC_MSG_REPLY;
32331708Sstevel
32341708Sstevel SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
32351708Sstevel "0x%lx transid schpc_getreply called", transid);
32361708Sstevel
32371708Sstevel rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
32387656SSherry.Moore@Sun.COM (void *)&reply, schpc_timeout_getmsg, entry);
32391708Sstevel
32401708Sstevel SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
32411708Sstevel "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
32421708Sstevel
32431708Sstevel if (rval == 0) {
32441708Sstevel slotstatus->slot_replystatus =
32451708Sstevel reply.pcimsg_type.pcimsg_setslot.slot_replystatus;
32461708Sstevel }
32471708Sstevel
32481708Sstevel return (rval);
32491708Sstevel }
32501708Sstevel
32511708Sstevel /*
32521708Sstevel * schpc_setslotled
32531708Sstevel *
32541708Sstevel * Changes the attention indicators for a given slot.
32551708Sstevel */
32561708Sstevel static void
schpc_setslotled(int expander,int board,int slot,uint32_t led_state)32571708Sstevel schpc_setslotled(int expander, int board, int slot, uint32_t led_state)
32581708Sstevel {
32591708Sstevel
32601708Sstevel pci_setslot_t setslot;
32611708Sstevel
32621708Sstevel if (schpc_p == NULL) {
32631708Sstevel return;
32641708Sstevel }
32651708Sstevel
32661708Sstevel schpc_init_setslot_message(&setslot);
32671708Sstevel
32681708Sstevel if (led_state & POWER_LED_ON) {
32691708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
32701708Sstevel }
32711708Sstevel if (led_state & POWER_LED_OFF) {
32721708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF;
32731708Sstevel }
32741708Sstevel if (led_state & POWER_LED_FLASH) {
32751708Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH;
32761708Sstevel }
32771708Sstevel if (led_state & SERVICE_LED_ON) {
32781708Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON;
32791708Sstevel }
32801708Sstevel if (led_state & SERVICE_LED_OFF) {
32811708Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF;
32821708Sstevel }
32831708Sstevel if (led_state & SERVICE_LED_FLASH) {
32841708Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH;
32851708Sstevel }
32861708Sstevel if (led_state & FAULT_LED_ON) {
32871708Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON;
32881708Sstevel }
32891708Sstevel if (led_state & FAULT_LED_OFF) {
32901708Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF;
32911708Sstevel }
32921708Sstevel if (led_state & FAULT_LED_FLASH) {
32931708Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH;
32941708Sstevel }
32951708Sstevel
32961708Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
32971708Sstevel case PCIMSG_LED_ON:
32981708Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
32991708Sstevel break;
33001708Sstevel case PCIMSG_LED_OFF:
33011708Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
33021708Sstevel break;
33031708Sstevel case PCIMSG_LED_FLASH:
33041708Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
33051708Sstevel break;
33061708Sstevel }
33071708Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
33081708Sstevel case PCIMSG_LED_ON:
33091708Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
33101708Sstevel break;
33111708Sstevel case PCIMSG_LED_OFF:
33121708Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
33131708Sstevel break;
33141708Sstevel case PCIMSG_LED_FLASH:
33151708Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
33161708Sstevel break;
33171708Sstevel }
33181708Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
33191708Sstevel case PCIMSG_LED_ON:
33201708Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
33211708Sstevel break;
33221708Sstevel case PCIMSG_LED_OFF:
33231708Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
33241708Sstevel break;
33251708Sstevel case PCIMSG_LED_FLASH:
33261708Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
33271708Sstevel break;
33281708Sstevel }
33291708Sstevel
33301708Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
33311708Sstevel }
33321708Sstevel
33331708Sstevel /*
33341708Sstevel * schpc_init_setslot_message
33351708Sstevel *
33361708Sstevel * Initialize Set Slot Message before using it.
33371708Sstevel */
33381708Sstevel static void
schpc_init_setslot_message(pci_setslot_t * setslot)33391708Sstevel schpc_init_setslot_message(pci_setslot_t *setslot)
33401708Sstevel {
33411708Sstevel /*
33421708Sstevel * Initialize Set Slot Command.
33431708Sstevel */
33441708Sstevel setslot->slot_power_on = PCIMSG_OFF;
33451708Sstevel setslot->slot_power_off = PCIMSG_OFF;
33461708Sstevel setslot->slot_led_power = PCIMSG_LED_OFF;
33471708Sstevel setslot->slot_led_service = PCIMSG_LED_OFF;
33481708Sstevel setslot->slot_led_fault = PCIMSG_LED_OFF;
33491708Sstevel setslot->slot_disable_ENUM = PCIMSG_OFF;
33501708Sstevel setslot->slot_enable_ENUM = PCIMSG_OFF;
33511708Sstevel setslot->slot_disable_HEALTHY = PCIMSG_OFF;
33521708Sstevel setslot->slot_enable_HEALTHY = PCIMSG_OFF;
33531708Sstevel }
33541708Sstevel
33551708Sstevel /*
33561708Sstevel * schpc_gettransid
33571708Sstevel *
33581708Sstevel * Builds a unique transaction ID.
33591708Sstevel */
33601708Sstevel static uint64_t
schpc_gettransid(schpc_t * schpc_p,int slot)33611708Sstevel schpc_gettransid(schpc_t *schpc_p, int slot)
33621708Sstevel {
33631708Sstevel uint64_t trans_id;
33641708Sstevel
33651708Sstevel mutex_enter(&schpc_p->schpc_mutex);
33661708Sstevel
33671708Sstevel if (++schpc_p->schpc_transid == 0)
33681708Sstevel schpc_p->schpc_transid = 1;
33691708Sstevel
33701708Sstevel trans_id = (schpc_p->schpc_slot[slot].expander<<24) |
33711708Sstevel (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid;
33721708Sstevel
33731708Sstevel mutex_exit(&schpc_p->schpc_mutex);
33741708Sstevel
33751708Sstevel SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning",
33761708Sstevel trans_id);
33771708Sstevel
33781708Sstevel return (trans_id);
33791708Sstevel }
33801708Sstevel
33811708Sstevel /*
33821708Sstevel * schpc_slot_get_index
33831708Sstevel *
33841708Sstevel * get slot table index from the slot handle
33851708Sstevel */
33861708Sstevel static int
schpc_slot_get_index(schpc_t * schpc_p,hpc_slot_t slot)33871708Sstevel schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot)
33881708Sstevel {
33891708Sstevel int i;
33901708Sstevel int rval = -1;
33911708Sstevel
33921708Sstevel ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex));
33931708Sstevel
33941708Sstevel for (i = 0; i < schpc_p->schpc_number_of_slots; i++) {
33951708Sstevel if (schpc_p->schpc_slot[i].slot_handle == slot)
33961708Sstevel return (i);
33971708Sstevel }
33981708Sstevel
33991708Sstevel return (rval);
34001708Sstevel }
34011708Sstevel
34021708Sstevel /*
34031708Sstevel * schpc_register_all_slots
34041708Sstevel *
34051708Sstevel * Search device tree for pci nodes and register attachment points
34061708Sstevel * for all hot pluggable slots.
34071708Sstevel */
34081708Sstevel /*ARGSUSED*/
34091708Sstevel static void
schpc_register_all_slots(schpc_t * schpc_p)34101708Sstevel schpc_register_all_slots(schpc_t *schpc_p)
34111708Sstevel {
34121708Sstevel int slot = 0;
34131708Sstevel char caddr[64];
34141708Sstevel dev_info_t *pci_dip = NULL;
34151708Sstevel find_dev_t find_dev;
34161708Sstevel int leaf, schizo, expander, portid, offset;
34171708Sstevel
34181708Sstevel SCHPC_DEBUG1(D_ATTACH,
3419*11311SSurya.Prakki@Sun.COM "schpc_register_all_slots(schpc_p=%p)", (void *)schpc_p);
34201708Sstevel
34211708Sstevel /*
34221708Sstevel * Allow the event_handler to start processing unsolicited
34231708Sstevel * events now that slots are about to be registered.
34241708Sstevel */
34251708Sstevel slots_registered = B_TRUE;
34261708Sstevel
34271708Sstevel for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) {
34281708Sstevel
34291708Sstevel leaf = SCHPC_SLOT_LEAF(slot);
34301708Sstevel schizo = SCHPC_SLOT_SCHIZO(slot);
34311708Sstevel expander = SCHPC_SLOT_EXPANDER(slot);
34321708Sstevel
34331708Sstevel if (schizo == 0)
34341708Sstevel portid = 0x1c;
34351708Sstevel else
34361708Sstevel portid = 0x1d;
34371708Sstevel
34381708Sstevel if (leaf == 0)
34391708Sstevel offset = 0x600000;
34401708Sstevel else
34411708Sstevel offset = 0x700000;
34421708Sstevel
34431708Sstevel portid = (expander << 5) | portid;
34441708Sstevel
34451708Sstevel (void) sprintf(caddr, "%x,%x", portid, offset);
34461708Sstevel
34471708Sstevel SCHPC_DEBUG3(D_ATTACH,
34481708Sstevel "schpc_register_all_slots: searching for pci@%s"
34491708Sstevel " schizo=%d, leaf=%d", caddr, schizo, leaf);
34501708Sstevel
34511708Sstevel find_dev.cname = "pci";
34521708Sstevel find_dev.caddr = caddr;
34531708Sstevel find_dev.schizo = schizo;
34541708Sstevel find_dev.leaf = leaf;
34551708Sstevel find_dev.dip = NULL;
34561708Sstevel
34571708Sstevel /* root node doesn't have to be held */
34581708Sstevel ddi_walk_devs(ddi_root_node(), schpc_match_dip,
34591708Sstevel &find_dev);
34601708Sstevel
34611708Sstevel pci_dip = find_dev.dip;
34621708Sstevel
34631708Sstevel if (pci_dip == NULL) {
34641708Sstevel
34651708Sstevel SCHPC_DEBUG1(D_ATTACH,
34661708Sstevel "schpc_register_all_slots: pci@%s NOT FOUND",
34671708Sstevel caddr);
34681708Sstevel
34691708Sstevel continue;
34701708Sstevel }
34711708Sstevel
34721708Sstevel SCHPC_DEBUG2(D_ATTACH,
34731708Sstevel "schpc_register_all_slots: pci@%s FOUND dip=0x%p",
3474*11311SSurya.Prakki@Sun.COM caddr, (void *)pci_dip);
34751708Sstevel
34761708Sstevel (void) schpc_add_pci(pci_dip);
34771708Sstevel
34781708Sstevel /*
34791708Sstevel * Release hold acquired in schpc_match_dip()
34801708Sstevel */
34811708Sstevel ndi_rele_devi(pci_dip);
34821708Sstevel }
34831708Sstevel
34841708Sstevel SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit");
34851708Sstevel
34861708Sstevel thread_exit();
34871708Sstevel }
34881708Sstevel
34891708Sstevel /*
34901708Sstevel * schpc_add_pci
34911708Sstevel *
34921708Sstevel * Routine to add attachments points associated with a pci node.
34931708Sstevel * Can be call externally by DR when configuring a PCI I/O Board.
34941708Sstevel */
34951708Sstevel int
schpc_add_pci(dev_info_t * bdip)34961708Sstevel schpc_add_pci(dev_info_t *bdip)
34971708Sstevel {
34981708Sstevel int portid;
34991708Sstevel int expander, board, schizo, leaf, slot, status;
35001708Sstevel char ap_id[MAXNAMELEN];
35011708Sstevel char caddr[64];
35021708Sstevel char *naddr;
35031708Sstevel hpc_slot_info_t slot_info;
35041708Sstevel hpc_slot_ops_t *slot_ops;
35051708Sstevel dev_info_t *sdip = bdip;
35061708Sstevel
3507*11311SSurya.Prakki@Sun.COM SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", (void *)sdip);
35081708Sstevel
35091708Sstevel if (schpc_p == NULL) {
35101708Sstevel /*
35111708Sstevel * The schpc driver has not been attached yet.
35121708Sstevel */
35131708Sstevel return (DDI_SUCCESS);
35141708Sstevel }
35151708Sstevel
35161708Sstevel if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) {
3517*11311SSurya.Prakki@Sun.COM cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n",
3518*11311SSurya.Prakki@Sun.COM (void *)sdip);
35191708Sstevel return (DDI_FAILURE);
35201708Sstevel }
35211708Sstevel
35221708Sstevel expander = schpc_getexpander(sdip);
35231708Sstevel board = schpc_getboard(sdip);
35241708Sstevel
35251708Sstevel switch (portid & 0x1f) {
35261708Sstevel
35271708Sstevel case 0x1c:
35281708Sstevel schizo = 0;
35291708Sstevel break;
35301708Sstevel case 0x1d:
35311708Sstevel schizo = 1;
35321708Sstevel break;
35331708Sstevel default:
35341708Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3535*11311SSurya.Prakki@Sun.COM "Invalid pci portid 0x%x\n", (void *)sdip, portid);
35361708Sstevel return (DDI_FAILURE);
35371708Sstevel }
35381708Sstevel
35391708Sstevel naddr = ddi_get_name_addr(sdip);
35401708Sstevel if (naddr == NULL) {
35411708Sstevel SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr"
3542*11311SSurya.Prakki@Sun.COM "(0x%p) returns null", (void *)sdip);
35431708Sstevel return (DDI_FAILURE);
35441708Sstevel }
35451708Sstevel
35461708Sstevel (void) sprintf(caddr, "%x,600000", portid);
35471708Sstevel
35481708Sstevel if (strcmp(caddr, naddr) == 0) {
35491708Sstevel leaf = 0;
35501708Sstevel } else {
35511708Sstevel (void) sprintf(caddr, "%x,700000", portid);
35521708Sstevel if (strcmp(caddr, naddr) == 0) {
35531708Sstevel char *name;
35541708Sstevel
35551708Sstevel leaf = 1;
35561708Sstevel name = ddi_binding_name(sdip);
35571708Sstevel if ((strcmp(name, "pci108e,8002") == 0) &&
35587656SSherry.Moore@Sun.COM (schizo == 0)) {
35591708Sstevel int circ;
35601708Sstevel dev_info_t *cdip;
35611708Sstevel /*
35621708Sstevel * XMITS 0 Leaf B will have its hot
35631708Sstevel * pluggable slot off a PCI-PCI bridge,
35641708Sstevel * which is the only child.
35651708Sstevel */
35661708Sstevel ndi_devi_enter(sdip, &circ);
35671708Sstevel cdip = ddi_get_child(sdip);
35681708Sstevel if (cdip == NULL) {
35691708Sstevel cmn_err(CE_WARN,
35707656SSherry.Moore@Sun.COM "schpc_add_pci(dip=0x%p) - "
35717656SSherry.Moore@Sun.COM "Invalid pci name addr %s\n",
3572*11311SSurya.Prakki@Sun.COM (void *)sdip, naddr);
35731708Sstevel ndi_devi_exit(sdip, circ);
35741708Sstevel return (DDI_FAILURE);
35751708Sstevel }
35761708Sstevel ndi_devi_exit(sdip, circ);
35771708Sstevel sdip = cdip;
35781708Sstevel }
35791708Sstevel } else {
35801708Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3581*11311SSurya.Prakki@Sun.COM "Invalid pci name addr %s\n", (void *)sdip, naddr);
35821708Sstevel return (DDI_FAILURE);
35831708Sstevel }
35841708Sstevel }
35851708Sstevel
35861708Sstevel /* create a slot table index */
35871708Sstevel slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf);
35881708Sstevel
35891708Sstevel if (schpc_p->schpc_slot[slot].devi) {
35901708Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3591*11311SSurya.Prakki@Sun.COM "pci node already registered\n", (void *)sdip);
35921708Sstevel return (DDI_FAILURE);
35931708Sstevel }
35941708Sstevel
35951708Sstevel /*
35961708Sstevel * There is no need to hold the dip while saving it in
35971708Sstevel * the devi field below. The dip is never dereferenced.
35981708Sstevel * (If that changes, this code should be modified).
35991708Sstevel * We want to avoid holding the dip here because it
36001708Sstevel * prevents DR.
36011708Sstevel *
36021708Sstevel * NOTE: Even though the slot on XMITS0 Leaf-B
36031708Sstevel * is connected to a pci_pci bridge, we will be saving
36041708Sstevel * the busdip in this datastructure. This will make
36051708Sstevel * it easier to identify the dip being removed in
36061708Sstevel * schpc_remove_pci().
36071708Sstevel */
36081708Sstevel schpc_p->schpc_slot[slot].devi = bdip;
36091708Sstevel
36101708Sstevel schpc_p->schpc_slot[slot].expander = expander;
36111708Sstevel schpc_p->schpc_slot[slot].board = board;
36121708Sstevel schpc_p->schpc_slot[slot].schizo = schizo;
36131708Sstevel schpc_p->schpc_slot[slot].leaf = leaf;
36141708Sstevel
36151708Sstevel /*
36161708Sstevel * Starcat PCI slots are always PCI device 1.
36171708Sstevel */
36181708Sstevel schpc_p->schpc_slot[slot].pci_id = 1;
36191708Sstevel
36201708Sstevel schpc_buildapid(sdip, slot, (char *)&ap_id);
36211708Sstevel
36221708Sstevel (void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id);
36231708Sstevel
36241708Sstevel /* safe to call ddi_pathname(): bdip is held */
36251708Sstevel (void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path);
36261708Sstevel
36271708Sstevel status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot));
36281708Sstevel switch (status) {
36291708Sstevel case RSV_UNKNOWN:
36301708Sstevel case RSV_PRESENT:
36311708Sstevel case RSV_MISS:
36321708Sstevel case RSV_PASS:
36331708Sstevel case RSV_EMPTY_CASSETTE:
36341708Sstevel
36351708Sstevel /*
36361708Sstevel * Test the condition of the slot.
36371708Sstevel */
36381708Sstevel schpc_test((caddr_t)schpc_p, slot, 0, 0);
36391708Sstevel break;
36401708Sstevel case RSV_BLACK:
36411708Sstevel schpc_p->schpc_slot[slot].state = 0;
36421708Sstevel cmn_err(CE_WARN, "schpc: PCI card blacklisted: "
36431708Sstevel "expander=%d board=%d slot=%d\n", expander,
36441708Sstevel board, SCHPC_SLOT_NUM(slot));
36451708Sstevel break;
36461708Sstevel default:
36471708Sstevel schpc_p->schpc_slot[slot].state = 0;
36481708Sstevel cmn_err(CE_WARN, "schpc: PCI card failed by POST: "
36491708Sstevel "expander=%d board=%d slot=%d failure=0x%x\n",
36501708Sstevel expander, board, SCHPC_SLOT_NUM(slot), status);
36511708Sstevel break;
36521708Sstevel }
36531708Sstevel
36541708Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) {
36551708Sstevel
36561708Sstevel /* allocate slot ops */
36571708Sstevel
36581708Sstevel slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
36591708Sstevel schpc_p->schpc_slot[slot].slot_ops = slot_ops;
36601708Sstevel
36611708Sstevel /*
36621708Sstevel * Default to Autoconfiguration disabled.
36631708Sstevel */
36641708Sstevel schpc_p->schpc_slot[slot].state &=
36651708Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
36661708Sstevel
36671708Sstevel /*
36681708Sstevel * Fill in the slot information structure that
36691708Sstevel * describes the slot.
36701708Sstevel */
36711708Sstevel slot_info.version = HPC_SLOT_OPS_VERSION;
36721708Sstevel
36731708Sstevel if (schpc_p->schpc_hotplugmodel ==
36741708Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG)
36751708Sstevel slot_info.slot_type = HPC_SLOT_TYPE_PCI;
36761708Sstevel else
36771708Sstevel slot_info.slot_type = HPC_SLOT_TYPE_CPCI;
36781708Sstevel
36791708Sstevel slot_info.slot.pci.device_number =
36801708Sstevel schpc_p->schpc_slot[slot].pci_id;
36811708Sstevel
36821708Sstevel slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
36831708Sstevel
36841708Sstevel if (schpc_use_legacy_apid)
36851708Sstevel slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE;
36861708Sstevel else
36871708Sstevel slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
36881708Sstevel HPC_SLOT_CREATE_DEVLINK;
36891708Sstevel
3690*11311SSurya.Prakki@Sun.COM (void) strcpy(slot_info.slot.pci.slot_logical_name,
36911708Sstevel schpc_p->schpc_slot[slot].ap_id);
36921708Sstevel
36931708Sstevel /*
36941708Sstevel * Fill in the slot ops structure that tells
36951708Sstevel * the Hot Plug Services what function we
36961708Sstevel * support.
36971708Sstevel */
36981708Sstevel slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
36991708Sstevel if (schpc_p->schpc_hotplugmodel ==
37001708Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
37011708Sstevel slot_ops->hpc_op_connect = schpc_connect;
37021708Sstevel slot_ops->hpc_op_disconnect = schpc_disconnect;
37031708Sstevel slot_ops->hpc_op_insert = NULL;
37041708Sstevel slot_ops->hpc_op_remove = NULL;
37051708Sstevel slot_ops->hpc_op_control = schpc_pci_control;
37061708Sstevel } else {
37071708Sstevel slot_ops->hpc_op_connect = NULL;
37081708Sstevel slot_ops->hpc_op_disconnect = NULL;
37091708Sstevel slot_ops->hpc_op_insert = NULL;
37101708Sstevel slot_ops->hpc_op_remove = NULL;
37111708Sstevel slot_ops->hpc_op_control = schpc_cpci_control;
37121708Sstevel }
37131708Sstevel
37141708Sstevel SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC "
37151708Sstevel "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s",
37161708Sstevel schpc_p->schpc_slot[slot].nexus_path,
3717*11311SSurya.Prakki@Sun.COM (void *)schpc_p, SCHPC_SLOT_NUM(slot),
37181708Sstevel slot_info.slot.pci.device_number,
37191708Sstevel slot_info.slot.pci.slot_logical_name);
37201708Sstevel
37211708Sstevel if (hpc_slot_register(schpc_p->schpc_devi,
37221708Sstevel schpc_p->schpc_slot[slot].nexus_path, &slot_info,
37231708Sstevel &schpc_p->schpc_slot[slot].slot_handle,
37241708Sstevel slot_ops, (caddr_t)schpc_p, 0) != 0) {
37251708Sstevel
37261708Sstevel /*
37271708Sstevel * If the slot can not be registered,
37281708Sstevel * then the slot_ops need to be freed.
37291708Sstevel */
37301708Sstevel cmn_err(CE_WARN, "schpc%d Unable to Register "
37311708Sstevel "Slot %s", schpc_p->schpc_instance,
37321708Sstevel slot_info.slot.pci.slot_logical_name);
37331708Sstevel
37341708Sstevel hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops);
37351708Sstevel
37361708Sstevel schpc_p->schpc_slot[slot].slot_ops = NULL;
37371708Sstevel
37381708Sstevel return (DDI_FAILURE);
37391708Sstevel }
37401708Sstevel
37411708Sstevel /*
37421708Sstevel * We are ready to take commands from the HPC Services.
37431708Sstevel */
37441708Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED;
37451708Sstevel }
37461708Sstevel
37471708Sstevel return (DDI_SUCCESS);
37481708Sstevel }
37491708Sstevel
37501708Sstevel /*
37511708Sstevel * schpc_remove_pci
37521708Sstevel *
37531708Sstevel * Routine to remove attachments points associated with a pci node.
37541708Sstevel * Can be call externally by DR when unconfiguring a PCI I/O Board.
37551708Sstevel */
37561708Sstevel int
schpc_remove_pci(dev_info_t * dip)37571708Sstevel schpc_remove_pci(dev_info_t *dip)
37581708Sstevel {
37591708Sstevel int slot;
37601708Sstevel
3761*11311SSurya.Prakki@Sun.COM SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", (void *)dip);
37621708Sstevel
37631708Sstevel if (schpc_p == NULL) {
37641708Sstevel /*
37651708Sstevel * The schpc driver has not been attached yet.
37661708Sstevel */
37671708Sstevel return (DDI_SUCCESS);
37681708Sstevel }
37691708Sstevel
37701708Sstevel for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) {
37711708Sstevel if (schpc_p->schpc_slot[slot].devi == dip) {
37721708Sstevel
37731708Sstevel if (schpc_p->schpc_slot[slot].slot_ops) {
37741708Sstevel if (hpc_slot_unregister(
37751708Sstevel &schpc_p->schpc_slot[slot].slot_handle)) {
37761708Sstevel cmn_err(CE_WARN,
37771708Sstevel "schpc_remove_pci(dip=0x%p) - "
37781708Sstevel "unable to unregister pci slots\n",
3779*11311SSurya.Prakki@Sun.COM (void *)dip);
37801708Sstevel return (DDI_FAILURE);
37811708Sstevel } else {
37821708Sstevel hpc_free_slot_ops(
37831708Sstevel schpc_p->schpc_slot[slot].slot_ops);
37841708Sstevel
37851708Sstevel schpc_p->schpc_slot[slot].slot_ops =
37861708Sstevel NULL;
37871708Sstevel
37881708Sstevel schpc_p->schpc_slot[slot].devi = NULL;
37891708Sstevel
37901708Sstevel return (DDI_SUCCESS);
37911708Sstevel }
37921708Sstevel } else {
37931708Sstevel schpc_p->schpc_slot[slot].devi = NULL;
37941708Sstevel
37951708Sstevel return (DDI_SUCCESS);
37961708Sstevel }
37971708Sstevel }
37981708Sstevel }
37991708Sstevel
38001708Sstevel cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) "
3801*11311SSurya.Prakki@Sun.COM "dip not found\n", (void *)dip);
38021708Sstevel
38031708Sstevel return (DDI_SUCCESS);
38041708Sstevel }
38051708Sstevel
38061708Sstevel /*
38071708Sstevel * schpc_match_dip
38081708Sstevel *
38091708Sstevel * Used by ddi_walk_devs to find PCI Nexus nodes associated with
38101708Sstevel * Hot Plug Controllers.
38111708Sstevel */
38121708Sstevel static int
schpc_match_dip(dev_info_t * dip,void * arg)38131708Sstevel schpc_match_dip(dev_info_t *dip, void *arg)
38141708Sstevel {
38151708Sstevel char *naddr;
38161708Sstevel find_dev_t *find_dev = (find_dev_t *)arg;
38171708Sstevel
38181708Sstevel if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 &&
38191708Sstevel ((((naddr = ddi_get_name_addr(dip)) != NULL) &&
38201708Sstevel (strcmp(find_dev->caddr, naddr) == 0)) ||
38211708Sstevel ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) {
38221708Sstevel /*
38231708Sstevel * While ddi_walk_devs() holds dips when invoking this
38241708Sstevel * callback, this dip is being saved and will be accessible
38251708Sstevel * to the caller outside ddi_walk_devs(). Therefore it must be
38261708Sstevel * held.
38271708Sstevel */
38281708Sstevel ndi_hold_devi(dip);
38291708Sstevel find_dev->dip = dip;
38301708Sstevel
38311708Sstevel SCHPC_DEBUG2(D_ATTACH,
38321708Sstevel "schpc_match_dip: pci@%s FOUND dip=0x%p",
3833*11311SSurya.Prakki@Sun.COM find_dev->caddr, (void *)find_dev->dip);
38341708Sstevel
38351708Sstevel return (DDI_WALK_TERMINATE);
38361708Sstevel }
38371708Sstevel
38381708Sstevel ASSERT(find_dev->dip == NULL);
38391708Sstevel return (DDI_WALK_CONTINUE);
38401708Sstevel }
38411708Sstevel
38421708Sstevel /*
38431708Sstevel * schpc_buildapid
38441708Sstevel *
38451708Sstevel * Takes a component address and translates it into a ap_id prefix.
38461708Sstevel */
38471708Sstevel static void
schpc_buildapid(dev_info_t * dip,int slot,char * ap_id)38481708Sstevel schpc_buildapid(dev_info_t *dip, int slot, char *ap_id)
38491708Sstevel {
38501708Sstevel int r, pci_id_cnt, pci_id_bit;
38511708Sstevel int slots_before, found;
38521708Sstevel unsigned char *slot_names_data, *s;
38531708Sstevel int slot_names_size;
38541708Sstevel int slot_num;
38551708Sstevel unsigned int bit_mask;
38561708Sstevel
38571708Sstevel slot_num = SCHPC_SLOT_NUM(slot);
38581708Sstevel
38591708Sstevel if (schpc_use_legacy_apid) {
38601708Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot);
38611708Sstevel
3862*11311SSurya.Prakki@Sun.COM (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
38631708Sstevel schpc_getboard(dip), slot_num);
38641708Sstevel
38651708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
38661708Sstevel
38671708Sstevel return;
38681708Sstevel }
38691708Sstevel
38701708Sstevel r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
38711708Sstevel "slot-names", (caddr_t)&slot_names_data,
38721708Sstevel &slot_names_size);
38731708Sstevel
38741708Sstevel if (r == DDI_PROP_SUCCESS) {
38751708Sstevel
38761708Sstevel /*
38771708Sstevel * We can try to use the slot-names property to
38781708Sstevel * build our ap-id.
38791708Sstevel */
38801708Sstevel bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) |
38811708Sstevel (slot_names_data[1] << 16) | (slot_names_data[0] << 24);
38821708Sstevel
38831708Sstevel pci_id_bit = 1;
38841708Sstevel pci_id_cnt = slots_before = found = 0;
38851708Sstevel
38861708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x",
38871708Sstevel slot, bit_mask);
38881708Sstevel
38891708Sstevel /*
38901708Sstevel * Walk the bit mask until we find the bit that corresponds
38911708Sstevel * to our slots device number. We count how many bits
38921708Sstevel * we find before we find our slot's bit.
38931708Sstevel */
38941708Sstevel while (!found && (pci_id_cnt < 32)) {
38951708Sstevel
38961708Sstevel while (schpc_p->schpc_slot[slot].pci_id
38971708Sstevel != pci_id_cnt) {
38981708Sstevel
38991708Sstevel /*
39001708Sstevel * Find the next bit set.
39011708Sstevel */
39021708Sstevel while (!(bit_mask & pci_id_bit) &&
39031708Sstevel (pci_id_cnt < 32)) {
39041708Sstevel pci_id_bit = pci_id_bit << 1;
39051708Sstevel pci_id_cnt++;
39061708Sstevel }
39071708Sstevel
39081708Sstevel if (schpc_p->schpc_slot[slot].pci_id !=
39091708Sstevel pci_id_cnt)
39101708Sstevel slots_before++;
39111708Sstevel else
39121708Sstevel found = 1;
39131708Sstevel }
39141708Sstevel }
39151708Sstevel
39161708Sstevel if (pci_id_cnt < 32) {
39171708Sstevel
39181708Sstevel /*
39191708Sstevel * Set ptr to first string.
39201708Sstevel */
39211708Sstevel s = slot_names_data + 4;
39221708Sstevel
39231708Sstevel /*
39241708Sstevel * Increment past all the strings for the slots
39251708Sstevel * before ours.
39261708Sstevel */
39271708Sstevel while (slots_before) {
39281708Sstevel while (*s != NULL)
39291708Sstevel s++;
39301708Sstevel s++;
39311708Sstevel slots_before--;
39321708Sstevel }
39331708Sstevel
39341708Sstevel /*
39351708Sstevel * We should be at our string.
39361708Sstevel */
39371708Sstevel
3938*11311SSurya.Prakki@Sun.COM (void) sprintf(ap_id, "IO%d_%s",
3939*11311SSurya.Prakki@Sun.COM schpc_getexpander(dip), s);
39401708Sstevel
39411708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s",
39421708Sstevel slot, ap_id);
39431708Sstevel
39441708Sstevel kmem_free(slot_names_data, slot_names_size);
39451708Sstevel return;
39461708Sstevel }
39471708Sstevel
39481708Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found",
39491708Sstevel slot);
39501708Sstevel
39511708Sstevel kmem_free(slot_names_data, slot_names_size);
39521708Sstevel } else
39531708Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found",
39541708Sstevel slot);
39551708Sstevel
39561708Sstevel /*
39571708Sstevel * Build the ap-id using the legacy naming scheme.
39581708Sstevel */
3959*11311SSurya.Prakki@Sun.COM (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
39601708Sstevel schpc_getboard(dip), slot_num);
39611708Sstevel
39621708Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
39631708Sstevel }
39641708Sstevel
39651708Sstevel /*
39661708Sstevel * schpc_getexpander
39671708Sstevel *
39681708Sstevel * Returns the Expander Number (0-17) for the dip passed in. The Expander
39691708Sstevel * Number is extracted from the portid property of the pci node. Portid
39701708Sstevel * consists of <Expbrd#><1110x>, where x is the schizo number.
39711708Sstevel */
39721708Sstevel static int
schpc_getexpander(dev_info_t * dip)39731708Sstevel schpc_getexpander(dev_info_t *dip)
39741708Sstevel {
39751708Sstevel int id;
39761708Sstevel
39771708Sstevel id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1);
39781708Sstevel
39791708Sstevel if (id != -1)
39801708Sstevel return (id >> 5);
39811708Sstevel else {
39821708Sstevel id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1);
39831708Sstevel return (id);
39841708Sstevel }
39851708Sstevel }
39861708Sstevel
39871708Sstevel /*
39881708Sstevel * schpc_getboard
39891708Sstevel *
39901708Sstevel * Returns the board number (0 or 1) for the dip passed in.
39911708Sstevel */
39921708Sstevel static int
schpc_getboard(dev_info_t * dip)39931708Sstevel schpc_getboard(dev_info_t *dip)
39941708Sstevel {
39951708Sstevel _NOTE(ARGUNUSED(dip))
39961708Sstevel
39971708Sstevel /*
39981708Sstevel * Hot Pluggable PCI/cPCI slots are only available on
39991708Sstevel * Board 1 (half-bandwidth slot).
40001708Sstevel */
40011708Sstevel return (1);
40021708Sstevel }
40031708Sstevel
40041708Sstevel /*ARGSUSED*/
40051708Sstevel static int
schpc_get_slot_status(uint_t expander,uint_t board,uint_t slot)40061708Sstevel schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot)
40071708Sstevel {
40081708Sstevel gdcd_t *gdcd;
40091708Sstevel int prd_slot, status, bus;
40101708Sstevel
40111708Sstevel SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
40121708Sstevel "exp=%d board=%d slot=%d", expander, board, slot);
40131708Sstevel
40141708Sstevel if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t),
40151708Sstevel KM_SLEEP)) == NULL) {
40161708Sstevel return (RSV_UNDEFINED);
40171708Sstevel }
40181708Sstevel
40191708Sstevel /*
40201708Sstevel * Get the Starcat Specific Global DCD Structure from the golden
40211708Sstevel * IOSRAM.
40221708Sstevel */
40231708Sstevel if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
40241708Sstevel cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
40251708Sstevel "From IOSRAM\n");
40261708Sstevel kmem_free(gdcd, sizeof (gdcd_t));
40271708Sstevel return (RSV_UNDEFINED);
40281708Sstevel }
40291708Sstevel
40301708Sstevel if (gdcd->h.dcd_magic != GDCD_MAGIC) {
40311708Sstevel
40321708Sstevel cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n",
40331708Sstevel gdcd->h.dcd_magic);
40341708Sstevel
40351708Sstevel kmem_free(gdcd, sizeof (gdcd_t));
40361708Sstevel return (RSV_UNDEFINED);
40371708Sstevel }
40381708Sstevel
40391708Sstevel if (gdcd->h.dcd_version != DCD_VERSION) {
40401708Sstevel cmn_err(CE_WARN, "schpc: GDCD Bad Version: "
40411708Sstevel "GDCD Version 0x%x Expecting 0x%x\n",
40421708Sstevel gdcd->h.dcd_version, DCD_VERSION);
40431708Sstevel
40441708Sstevel kmem_free(gdcd, sizeof (gdcd_t));
40451708Sstevel return (RSV_UNDEFINED);
40461708Sstevel }
40471708Sstevel
40481708Sstevel if (slot < 2)
40491708Sstevel prd_slot = 4;
40501708Sstevel else
40511708Sstevel prd_slot = 5;
40521708Sstevel
40531708Sstevel bus = slot & 0x1;
40541708Sstevel
40551708Sstevel status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0];
40561708Sstevel
40571708Sstevel kmem_free(gdcd, sizeof (gdcd_t));
40581708Sstevel
40591708Sstevel SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
40601708Sstevel "prd_slot=%d bus=%d status=%d", prd_slot, bus, status);
40611708Sstevel
40621708Sstevel return (status);
40631708Sstevel }
40641708Sstevel
40651708Sstevel #define LEAF_SAVE_END 0xff
40661708Sstevel
40671708Sstevel typedef struct {
40681708Sstevel int reg;
40691708Sstevel int offset;
40701708Sstevel int access_size;
40711708Sstevel int number;
40721708Sstevel } save_reg_list_t;
40731708Sstevel
40741708Sstevel /*
40751708Sstevel * Save List Array. Describes the leaf registers that need to
40761708Sstevel * be restored after a leaf reset.
40771708Sstevel *
40781708Sstevel * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space
40791708Sstevel * Entry 2 - Offset Start
40801708Sstevel * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit
40811708Sstevel * Entry 4 - # of registers to be saved starting at offset,
40821708Sstevel */
40831708Sstevel save_reg_list_t save_reg_list[] = { 0, 0x110, 8, 1,
40841708Sstevel 0, 0x200, 8, 2,
40851708Sstevel 0, 0x1000, 8, 0x18,
40861708Sstevel 0, 0x1a00, 8, 1,
40871708Sstevel 0, 0x2000, 8, 1,
40881708Sstevel 0, 0x2020, 8, 1,
40891708Sstevel 0, 0x2040, 8, 1,
40901708Sstevel 0, 0x2308, 8, 2,
40911708Sstevel 0, 0x2800, 8, 1,
40921708Sstevel 2, 0x04, 2, 1, /* Command */
40931708Sstevel 2, 0x0d, 1, 1, /* Latency */
40941708Sstevel 2, 0x40, 1, 1, /* Bus # */
40951708Sstevel 2, 0x41, 1, 1, /* Sub. Bus # */
40961708Sstevel LEAF_SAVE_END, 0, 0, 0};
40971708Sstevel
40981708Sstevel static int
schpc_save_leaf(int slot)40991708Sstevel schpc_save_leaf(int slot)
41001708Sstevel {
41011708Sstevel int save_entry, list_entry, reg;
41021708Sstevel caddr_t leaf_regs;
41031708Sstevel ddi_device_acc_attr_t attr;
41041708Sstevel
41051708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
41061708Sstevel
41071708Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
41081708Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
41091708Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
41101708Sstevel
41111708Sstevel /*
41121708Sstevel * Map in the 3 addresses spaces defined for XMITS.
41131708Sstevel */
41141708Sstevel for (reg = 0; reg < 3; reg++) {
41151708Sstevel if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg,
41161708Sstevel &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot].
41171708Sstevel saved_handle[reg]) != DDI_SUCCESS) {
41181708Sstevel cmn_err(CE_WARN, "Mapin failed\n");
41191708Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
41201708Sstevel return (1);
41211708Sstevel }
41221708Sstevel
41231708Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs;
41241708Sstevel }
41251708Sstevel
41261708Sstevel
41271708Sstevel /*
41281708Sstevel * Determine how many entries are in the list so we can
41291708Sstevel * allocate the save space.
41301708Sstevel */
41311708Sstevel list_entry = 0;
41321708Sstevel save_entry = 0;
41331708Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
41341708Sstevel save_entry += save_reg_list[list_entry].number;
41351708Sstevel list_entry++;
41361708Sstevel }
41371708Sstevel
41381708Sstevel schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t));
41391708Sstevel
41401708Sstevel if (schpc_p->schpc_slot[slot].saved_size == 0)
41411708Sstevel return (0);
41421708Sstevel
41431708Sstevel schpc_p->schpc_slot[slot].saved_regs =
41441708Sstevel (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size,
41451708Sstevel KM_SLEEP);
41461708Sstevel
41471708Sstevel /*
41481708Sstevel * Walk through the register list and save contents.
41491708Sstevel */
41501708Sstevel list_entry = 0;
41511708Sstevel save_entry = 0;
41521708Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
41531708Sstevel schpc_save_entry(slot, list_entry, save_entry);
41541708Sstevel save_entry += save_reg_list[list_entry].number;
41551708Sstevel list_entry ++;
41561708Sstevel }
41571708Sstevel
41581708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
41591708Sstevel
41601708Sstevel return (0);
41611708Sstevel }
41621708Sstevel
41631708Sstevel static void
schpc_restore_leaf(int slot)41641708Sstevel schpc_restore_leaf(int slot)
41651708Sstevel {
41661708Sstevel int save_entry, list_entry, reg;
41671708Sstevel
41681708Sstevel if (schpc_p->schpc_slot[slot].saved_regs == NULL)
41691708Sstevel return;
41701708Sstevel
41711708Sstevel /*
41721708Sstevel * Walk through the register list and restore contents.
41731708Sstevel */
41741708Sstevel list_entry = 0;
41751708Sstevel save_entry = 0;
41761708Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
41771708Sstevel
41781708Sstevel schpc_restore_entry(slot, list_entry, save_entry);
41791708Sstevel
41801708Sstevel save_entry += save_reg_list[list_entry].number;
41811708Sstevel list_entry ++;
41821708Sstevel }
41831708Sstevel
41841708Sstevel /*
41851708Sstevel * Free the mapped in registers.
41861708Sstevel */
41871708Sstevel for (reg = 0; reg < 3; reg++) {
41881708Sstevel if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) {
41891708Sstevel
41901708Sstevel ddi_regs_map_free(
41911708Sstevel &schpc_p->schpc_slot[slot].saved_handle[reg]);
41921708Sstevel
41931708Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
41941708Sstevel }
41951708Sstevel }
41961708Sstevel
41971708Sstevel kmem_free(schpc_p->schpc_slot[slot].saved_regs,
41981708Sstevel schpc_p->schpc_slot[slot].saved_size);
41991708Sstevel
42001708Sstevel schpc_p->schpc_slot[slot].saved_size = 0;
42011708Sstevel schpc_p->schpc_slot[slot].saved_regs = NULL;
42021708Sstevel
42031708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot);
42041708Sstevel }
42051708Sstevel
42061708Sstevel static void
schpc_save_entry(int slot,int list_entry,int save_entry)42071708Sstevel schpc_save_entry(int slot, int list_entry, int save_entry)
42081708Sstevel {
42091708Sstevel int reg, reads = 0;
42101708Sstevel
42111708Sstevel reg = save_reg_list[list_entry].reg;
42121708Sstevel
42131708Sstevel while (reads < save_reg_list[list_entry].number) {
42141708Sstevel switch (save_reg_list[list_entry].access_size) {
42151708Sstevel case 8:
42161708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
42171708Sstevel ddi_get64(
42181708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
42191708Sstevel (uint64_t *)(schpc_p->schpc_slot[slot].
42201708Sstevel saved_regs_va[reg]
42211708Sstevel + save_reg_list[list_entry].offset +
42221708Sstevel (reads * sizeof (uint64_t))));
42231708Sstevel #ifdef DEBUG
42241708Sstevel if (schpc_dump_save_regs)
42251708Sstevel cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg,
42261708Sstevel save_reg_list[list_entry].offset +
42271708Sstevel (reads * sizeof (uint64_t)),
42281708Sstevel schpc_p->schpc_slot[slot].
42291708Sstevel saved_regs[save_entry]);
42301708Sstevel #endif
42311708Sstevel
42321708Sstevel break;
42331708Sstevel case 4:
42341708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
42351708Sstevel ddi_get32(
42361708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
42371708Sstevel (uint32_t *)(schpc_p->schpc_slot[slot].
42381708Sstevel saved_regs_va[reg]
42391708Sstevel + save_reg_list[list_entry].offset +
42401708Sstevel (reads * sizeof (uint32_t))));
42411708Sstevel
42421708Sstevel #ifdef DEBUG
42431708Sstevel if (schpc_dump_save_regs)
42441708Sstevel cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg,
42451708Sstevel save_reg_list[list_entry].offset +
42461708Sstevel (reads * sizeof (uint32_t)),
42471708Sstevel schpc_p->schpc_slot[slot].
42481708Sstevel saved_regs[save_entry]);
42491708Sstevel #endif
42501708Sstevel
42511708Sstevel break;
42521708Sstevel case 2:
42531708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
42541708Sstevel ddi_get16(
42551708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
42561708Sstevel (uint16_t *)(schpc_p->schpc_slot[slot].
42571708Sstevel saved_regs_va[reg]
42581708Sstevel + save_reg_list[list_entry].offset +
42591708Sstevel (reads * sizeof (uint16_t))));
42601708Sstevel
42611708Sstevel #ifdef DEBUG
42621708Sstevel if (schpc_dump_save_regs)
42631708Sstevel cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg,
42641708Sstevel save_reg_list[list_entry].offset +
42651708Sstevel (reads * sizeof (uint16_t)),
42661708Sstevel schpc_p->schpc_slot[slot].
42671708Sstevel saved_regs[save_entry]);
42681708Sstevel #endif
42691708Sstevel
42701708Sstevel break;
42711708Sstevel case 1:
42721708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
42731708Sstevel ddi_get8(
42741708Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
42751708Sstevel (uint8_t *)(schpc_p->schpc_slot[slot].
42761708Sstevel saved_regs_va[reg]
42771708Sstevel + save_reg_list[list_entry].offset +
42781708Sstevel (reads * sizeof (uint8_t))));
42791708Sstevel
42801708Sstevel #ifdef DEBUG
42811708Sstevel if (schpc_dump_save_regs)
42821708Sstevel cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg,
42831708Sstevel save_reg_list[list_entry].offset +
42841708Sstevel (reads * sizeof (uint8_t)),
42851708Sstevel schpc_p->schpc_slot[slot].
42861708Sstevel saved_regs[save_entry]);
42871708Sstevel #endif
42881708Sstevel
42891708Sstevel break;
42901708Sstevel default:
42911708Sstevel cmn_err(CE_WARN,
42921708Sstevel "schpc: Illegal List Entry\n");
42931708Sstevel }
42941708Sstevel reads++;
42951708Sstevel save_entry++;
42961708Sstevel }
42971708Sstevel }
42981708Sstevel
42991708Sstevel static void
schpc_restore_entry(int slot,int list_entry,int save_entry)43001708Sstevel schpc_restore_entry(int slot, int list_entry, int save_entry)
43011708Sstevel {
43021708Sstevel int reg, writes = 0;
43031708Sstevel
43041708Sstevel reg = save_reg_list[list_entry].reg;
43051708Sstevel
43061708Sstevel while (writes < save_reg_list[list_entry].number) {
43071708Sstevel switch (save_reg_list[list_entry].access_size) {
43081708Sstevel case 8:
43091708Sstevel #ifdef DEBUG
43101708Sstevel if (schpc_dump_save_regs)
43111708Sstevel cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg,
43121708Sstevel save_reg_list[list_entry].offset +
43131708Sstevel (writes * sizeof (uint64_t)),
43141708Sstevel schpc_p->schpc_slot[slot].
43151708Sstevel saved_regs[save_entry]);
43161708Sstevel #endif
43171708Sstevel
43181708Sstevel ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg],
43191708Sstevel (uint64_t *)(schpc_p->schpc_slot[slot].
43201708Sstevel saved_regs_va[reg]
43211708Sstevel + save_reg_list[list_entry].offset +
43221708Sstevel (writes * sizeof (uint64_t))),
43231708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
43241708Sstevel
43251708Sstevel break;
43261708Sstevel case 4:
43271708Sstevel #ifdef DEBUG
43281708Sstevel if (schpc_dump_save_regs)
43291708Sstevel cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg,
43301708Sstevel save_reg_list[list_entry].offset +
43311708Sstevel (writes * sizeof (uint32_t)),
43321708Sstevel schpc_p->schpc_slot[slot].
43331708Sstevel saved_regs[save_entry]);
43341708Sstevel #endif
43351708Sstevel
43361708Sstevel ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg],
43371708Sstevel (uint32_t *)(schpc_p->schpc_slot[slot].
43381708Sstevel saved_regs_va[reg]
43391708Sstevel + save_reg_list[list_entry].offset +
43401708Sstevel (writes * sizeof (uint32_t))),
43411708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
43421708Sstevel
43431708Sstevel break;
43441708Sstevel case 2:
43451708Sstevel #ifdef DEBUG
43461708Sstevel if (schpc_dump_save_regs)
43471708Sstevel cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg,
43481708Sstevel save_reg_list[list_entry].offset +
43491708Sstevel (writes * sizeof (uint16_t)),
43501708Sstevel schpc_p->schpc_slot[slot].
43511708Sstevel saved_regs[save_entry]);
43521708Sstevel #endif
43531708Sstevel
43541708Sstevel ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg],
43551708Sstevel (uint16_t *)(schpc_p->schpc_slot[slot].
43561708Sstevel saved_regs_va[reg]
43571708Sstevel + save_reg_list[list_entry].offset +
43581708Sstevel (writes * sizeof (uint16_t))),
43591708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
43601708Sstevel
43611708Sstevel break;
43621708Sstevel case 1:
43631708Sstevel #ifdef DEBUG
43641708Sstevel if (schpc_dump_save_regs)
43651708Sstevel cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg,
43661708Sstevel save_reg_list[list_entry].offset +
43671708Sstevel (writes * sizeof (uint8_t)),
43681708Sstevel schpc_p->schpc_slot[slot].
43691708Sstevel saved_regs[save_entry]);
43701708Sstevel #endif
43711708Sstevel
43721708Sstevel ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg],
43731708Sstevel (uint8_t *)(schpc_p->schpc_slot[slot].
43741708Sstevel saved_regs_va[reg]
43751708Sstevel + save_reg_list[list_entry].offset +
43761708Sstevel (writes * sizeof (uint8_t))),
43771708Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
43781708Sstevel
43791708Sstevel break;
43801708Sstevel default:
43811708Sstevel cmn_err(CE_WARN,
43821708Sstevel "schpc: Illegal List Entry\n");
43831708Sstevel }
43841708Sstevel writes++;
43851708Sstevel save_entry++;
43861708Sstevel }
43871708Sstevel }
43881708Sstevel
43891708Sstevel /*
43901708Sstevel * Returns TRUE if a leaf reset is required to change frequencies/mode.
43911708Sstevel */
43921708Sstevel static int
schpc_is_leaf_reset_required(int slot)43931708Sstevel schpc_is_leaf_reset_required(int slot)
43941708Sstevel {
43951708Sstevel char *name;
43961708Sstevel int32_t mod_rev;
43971708Sstevel
43981708Sstevel /*
43991708Sstevel * Only XMITS 3.0 and greater connected slots will require a
44001708Sstevel * reset to switch frequency and/or mode.
44011708Sstevel */
44021708Sstevel name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
44031708Sstevel
44041708Sstevel if (strcmp(name, "pci108e,8002") == 0) {
44051708Sstevel mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
44061708Sstevel schpc_p->schpc_slot[slot].devi,
44071708Sstevel DDI_PROP_DONTPASS, "module-revision#", 0);
44081708Sstevel
44091708Sstevel SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
44101708Sstevel
44111708Sstevel /*
44121708Sstevel * Check for XMITS 3.0 or greater.
44131708Sstevel */
44141708Sstevel if (mod_rev >= XMITS_30) {
44151708Sstevel
44161708Sstevel /*
44171708Sstevel * The leaf attached to C5V0 (slot 1) should
44181708Sstevel * not be reset.
44191708Sstevel */
44201708Sstevel if ((slot & 3) == 1) {
44211708Sstevel
44221708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
44231708Sstevel "Not Required - C5V0", slot);
44241708Sstevel
44251708Sstevel return (0);
44261708Sstevel }
44271708Sstevel
44281708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
44291708Sstevel "Required", slot);
44301708Sstevel
44311708Sstevel return (1);
44321708Sstevel }
44331708Sstevel }
44341708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot);
44351708Sstevel
44361708Sstevel return (0);
44371708Sstevel }
44381708Sstevel
44391708Sstevel /*
44401708Sstevel * Returns TRUE if the bus can change frequencies.
44411708Sstevel */
44421708Sstevel static int
schpc_is_freq_switchable(int slot)44431708Sstevel schpc_is_freq_switchable(int slot)
44441708Sstevel {
44451708Sstevel char *name;
44461708Sstevel int32_t mod_rev;
44471708Sstevel
44481708Sstevel name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
44491708Sstevel
44501708Sstevel if (strcmp(name, "pci108e,8002") == 0) {
44511708Sstevel mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
44521708Sstevel schpc_p->schpc_slot[slot].devi,
44531708Sstevel DDI_PROP_DONTPASS, "module-revision#", 0);
44541708Sstevel
44551708Sstevel SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
44561708Sstevel
44571708Sstevel /*
44581708Sstevel * We will only report back that XMITS 2.0 (mod_rev = 2)
44591708Sstevel * or greater will have the ability to switch frequencies.
44601708Sstevel */
44611708Sstevel if (mod_rev >= XMITS_20) {
44621708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - "
44631708Sstevel "Frequency is switchable", slot);
44641708Sstevel return (1);
44651708Sstevel }
44661708Sstevel }
44671708Sstevel
44681708Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot);
44691708Sstevel return (0);
44701708Sstevel }
44711708Sstevel
44721708Sstevel /*
44731708Sstevel * schpc_slot_freq
44741708Sstevel *
44751708Sstevel * Convert the slot frequency setting to integer value.
44761708Sstevel */
44771708Sstevel static int
schpc_slot_freq(pci_getslot_t * getslotp)44781708Sstevel schpc_slot_freq(pci_getslot_t *getslotp)
44791708Sstevel {
44801708Sstevel switch (getslotp->slot_freq_setting) {
44811708Sstevel case PCIMSG_FREQ_33MHZ:
44821708Sstevel return (SCHPC_33MHZ);
44831708Sstevel case PCIMSG_FREQ_66MHZ:
44841708Sstevel return (SCHPC_66MHZ);
44851708Sstevel case PCIMSG_FREQ_90MHZ:
44861708Sstevel return (SCHPC_90MHZ);
44871708Sstevel case PCIMSG_FREQ_133MHZ:
44881708Sstevel return (SCHPC_133MHZ);
44891708Sstevel default:
44901708Sstevel return (0);
44911708Sstevel }
44921708Sstevel }
44931708Sstevel
44941708Sstevel /*
44951708Sstevel * schpc_find_dip
44961708Sstevel *
44971708Sstevel * Used by ddi_walk_devs to find the dip which belongs
44981708Sstevel * to a certain slot.
44991708Sstevel *
45001708Sstevel * When this function returns, the dip is held. It is the
45011708Sstevel * responsibility of the caller to release the dip.
45021708Sstevel */
45031708Sstevel static int
schpc_find_dip(dev_info_t * dip,void * arg)45041708Sstevel schpc_find_dip(dev_info_t *dip, void *arg)
45051708Sstevel {
45061708Sstevel find_dev_t *find_dev = (find_dev_t *)arg;
45071708Sstevel char *pathname = find_dev->caddr;
45081708Sstevel
45091708Sstevel (void) ddi_pathname(dip, pathname);
45101708Sstevel if (strcmp(find_dev->cname, pathname) == 0) {
45111708Sstevel ndi_hold_devi(dip);
45121708Sstevel find_dev->dip = dip;
45131708Sstevel return (DDI_WALK_TERMINATE);
45141708Sstevel }
45151708Sstevel return (DDI_WALK_CONTINUE);
45161708Sstevel }
4517