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