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