xref: /titanic_50/usr/src/uts/sun4u/starcat/io/schpc.c (revision aac517695f87c6b55a5fefa5a14da8c270097ef4)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel 
2803831d35Sstevel /*
2903831d35Sstevel  * Starcat IOSRAM/Tunnel PCI Hot Plug Controller Driver
3003831d35Sstevel  */
3103831d35Sstevel 
3203831d35Sstevel #define	CPCI_ENUM
3303831d35Sstevel 
3403831d35Sstevel #include <sys/note.h>
3503831d35Sstevel #include <sys/types.h>
3603831d35Sstevel #include <sys/cmn_err.h>
3703831d35Sstevel #include <sys/kmem.h>
3803831d35Sstevel #include <sys/errno.h>
3903831d35Sstevel #include <sys/open.h>
4003831d35Sstevel #include <sys/stat.h>
4103831d35Sstevel #include <sys/conf.h>
4203831d35Sstevel #include <sys/ddi.h>
4303831d35Sstevel #include <sys/cmn_err.h>
4403831d35Sstevel #include <sys/sunddi.h>
4503831d35Sstevel #include <sys/sunndi.h>
4603831d35Sstevel #include <sys/ddi_impldefs.h>
4703831d35Sstevel #include <sys/ndi_impldefs.h>
4803831d35Sstevel #include <sys/modctl.h>
4903831d35Sstevel #include <sys/disp.h>
5003831d35Sstevel #include <sys/async.h>
5103831d35Sstevel #include <sys/hotplug/hpcsvc.h>
5203831d35Sstevel #include <sys/mboxsc.h>
5303831d35Sstevel #include <sys/schpc_msg.h>
5403831d35Sstevel #include <sys/schpc.h>
5503831d35Sstevel #include <post/scat_dcd.h>
5603831d35Sstevel #include <sys/taskq.h>
5703831d35Sstevel 
5803831d35Sstevel #ifdef DEBUG
5903831d35Sstevel int schpc_dump_save_regs = 0;
6003831d35Sstevel static uint_t schpc_debug_flags = 0;
6103831d35Sstevel #define	SCHPC_DEBUG0(f, s) if ((f)& schpc_debug_flags) \
6203831d35Sstevel 	cmn_err(CE_CONT, "schpc: " s "\n")
6303831d35Sstevel #define	SCHPC_DEBUG1(f, s, a) if ((f)& schpc_debug_flags) \
6403831d35Sstevel 	cmn_err(CE_CONT, "schpc: " s "\n", a)
6503831d35Sstevel #define	SCHPC_DEBUG2(f, s, a, b) if ((f)& schpc_debug_flags) \
6603831d35Sstevel 	cmn_err(CE_CONT, "schpc: " s "\n", a, b)
6703831d35Sstevel #define	SCHPC_DEBUG3(f, s, a, b, c) if ((f)& schpc_debug_flags) \
6803831d35Sstevel 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c)
6903831d35Sstevel #define	SCHPC_DEBUG4(f, s, a, b, c, d) if ((f)& schpc_debug_flags) \
7003831d35Sstevel 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d)
7103831d35Sstevel #define	SCHPC_DEBUG5(f, s, a, b, c, d, e) if ((f)& schpc_debug_flags) \
7203831d35Sstevel 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e)
7303831d35Sstevel #define	SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& schpc_debug_flags) \
7403831d35Sstevel 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e, ff)
7503831d35Sstevel #else
7603831d35Sstevel 
7703831d35Sstevel #define	SCHPC_DEBUG0(f, s)
7803831d35Sstevel #define	SCHPC_DEBUG1(f, s, a)
7903831d35Sstevel #define	SCHPC_DEBUG2(f, s, a, b)
8003831d35Sstevel #define	SCHPC_DEBUG3(f, s, a, b, c)
8103831d35Sstevel #define	SCHPC_DEBUG4(f, s, a, b, c, d)
8203831d35Sstevel #define	SCHPC_DEBUG5(f, s, a, b, c, d, e)
8303831d35Sstevel #define	SCHPC_DEBUG6(f, s, a, b, c, d, e, ff)
8403831d35Sstevel 
8503831d35Sstevel #endif
8603831d35Sstevel 
8703831d35Sstevel #define	D_IDENTIFY	0x00000001
8803831d35Sstevel #define	D_ATTACH	0x00000002
8903831d35Sstevel #define	D_DETACH	0x00000004
9003831d35Sstevel #define	D_OPEN		0x00000008
9103831d35Sstevel #define	D_GETSLOTSTATUS	0x00000010
9203831d35Sstevel #define	D_SETSLOTSTATUS	0x00000020
9303831d35Sstevel #define	D_IOCTL		0x00010000
9403831d35Sstevel #define	D_IOC_CONNECT	0x00020000
9503831d35Sstevel #define	D_IOC_CONTROL	0x00040000
9603831d35Sstevel #define	D_IOC_CONFIG	0x00080000
9703831d35Sstevel #define	D_IOC_STATUS	0x00100000
9803831d35Sstevel #define	D_IOC_MSG	0x00200000
9903831d35Sstevel #define	D_IOC_TEST	0x00400000
10003831d35Sstevel #define	D_IOC_LED	0x00800000
10103831d35Sstevel #define	D_EVENT		0x01000000
10203831d35Sstevel #define	D_THREAD	0x02000000
10303831d35Sstevel #define	D_TRANSID	0x04000000
10403831d35Sstevel #define	D_SLOTTABLE	0x08000000
10503831d35Sstevel #define	D_FREQCHG	0x10000000
10603831d35Sstevel #define	D_APID		0x20000000
10703831d35Sstevel 
10803831d35Sstevel /*
10903831d35Sstevel  * driver global data:
11003831d35Sstevel  */
11103831d35Sstevel static void *per_schpc_state;		/* soft state head */
11203831d35Sstevel dev_info_t *schpc_devi;
11303831d35Sstevel static schpc_t	*schpc_p;
11403831d35Sstevel 
11503831d35Sstevel clock_t schpc_timeout_putmsg = 60 * 1000; /* 60 seconds */
11603831d35Sstevel clock_t schpc_timeout_getmsg = 60 * 1000; /* 60 seconds */
11703831d35Sstevel clock_t schpc_timeout_event = 60 * 5 * 1000; /* 5 minutes */
11803831d35Sstevel 
11903831d35Sstevel int schpc_use_legacy_apid = 0;
12003831d35Sstevel 
12103831d35Sstevel static mboxsc_timeout_range_t schpc_putmsg_timeout_range;
12203831d35Sstevel static mboxsc_timeout_range_t schpc_getmsg_timeout_range;
12303831d35Sstevel 
12403831d35Sstevel static taskq_t *schpc_event_taskq = NULL;
12503831d35Sstevel 
12603831d35Sstevel /*
12703831d35Sstevel  * replies to mboxsc_getmsg() are handled asynchronously by the
12803831d35Sstevel  * schpc_msg_thread using a linked list of schpc_replylist_t
12903831d35Sstevel  * elements
13003831d35Sstevel  */
13103831d35Sstevel typedef struct schpc_replylist {
13203831d35Sstevel 	struct schpc_replylist	*prev;		/* link to previous entry */
13303831d35Sstevel 	struct schpc_replylist	*next;		/* link to next entry */
13403831d35Sstevel 	kcondvar_t		reply_cv;	/* condvar for getting reply */
13503831d35Sstevel 	kmutex_t		reply_lock;	/* mutex for getting reply */
13603831d35Sstevel 	uint32_t		type;		/* mboxsc_xxxmsg() msg type */
13703831d35Sstevel 	uint32_t		cmd;		/* mboxsc_xxxmsg() cmd */
13803831d35Sstevel 	uint64_t		transid;	/* mboxsc_xxxmsg() trans id */
13903831d35Sstevel 	uint32_t		length;		/* mboxsc_xxxmsg() length */
14003831d35Sstevel 	pcimsg_t		reply;		/* mboxsc_xxxmsg() reply msg */
14103831d35Sstevel 	boolean_t		reply_recvd;	/* msg reply received */
14203831d35Sstevel 	boolean_t		reply_cexit;	/* client early exit */
14303831d35Sstevel } schpc_replylist_t;
14403831d35Sstevel 
14503831d35Sstevel static kmutex_t schpc_replylist_mutex; /* replylist mutex */
14603831d35Sstevel static uint32_t schpc_replylist_count; /* replylist size */
14703831d35Sstevel static schpc_replylist_t *schpc_replylist_first; /* replylist 1st elem */
14803831d35Sstevel static schpc_replylist_t *schpc_replylist_last; /* replylist last elem */
14903831d35Sstevel static boolean_t slots_registered = B_FALSE; /* slots registered? */
15003831d35Sstevel 
15103831d35Sstevel typedef struct {
15203831d35Sstevel 	char		*cname;
15303831d35Sstevel 	char		*caddr;
15403831d35Sstevel 	char		schizo;
15503831d35Sstevel 	char		leaf;
15603831d35Sstevel 	dev_info_t	*dip;
15703831d35Sstevel } find_dev_t;
15803831d35Sstevel 
15903831d35Sstevel /*
16003831d35Sstevel  * Function prototypes for local functions
16103831d35Sstevel  */
16203831d35Sstevel static int schpc_getexpander(dev_info_t *);
16303831d35Sstevel static int schpc_getboard(dev_info_t *);
16403831d35Sstevel static void schpc_event_handler(void *);
16503831d35Sstevel static void schpc_event_filter(pcimsg_t	*msg);
16603831d35Sstevel static void schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
16703831d35Sstevel 				uint64_t transid, uint32_t length);
16803831d35Sstevel static uint64_t schpc_gettransid(schpc_t *, int);
16903831d35Sstevel static int schpc_slot_get_index(schpc_t *, hpc_slot_t);
17003831d35Sstevel static void schpc_register_all_slots(schpc_t *);
17103831d35Sstevel static void schpc_setslotled(int, int, int, uint32_t);
17203831d35Sstevel static void schpc_init_setslot_message(pci_setslot_t *);
17303831d35Sstevel static void schpc_test(caddr_t, int, void *, uint_t);
17403831d35Sstevel static int schpc_getslotstatus(uint32_t, uint32_t, uint32_t, pci_getslot_t *);
17503831d35Sstevel static int schpc_setslotstatus(uint32_t, uint32_t, uint32_t,  pci_setslot_t *);
17603831d35Sstevel static int schpc_match_dip(dev_info_t *, void *);
17703831d35Sstevel static void schpc_buildapid(dev_info_t *, int, char *);
17803831d35Sstevel static int schpc_get_slot_status(uint_t, uint_t, uint_t);
17903831d35Sstevel static void schpc_replylist_unlink(schpc_replylist_t *entry);
18003831d35Sstevel static schpc_replylist_t *schpc_replylist_link(uint32_t cmd, uint64_t transid,
18103831d35Sstevel 						uint32_t length);
18203831d35Sstevel static void schpc_msg_thread(void);
18303831d35Sstevel static int schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd,
18403831d35Sstevel 				uint64_t *transidp, uint32_t length,
18503831d35Sstevel 				void *datap, clock_t timeout,
18603831d35Sstevel 				schpc_replylist_t **entryp);
18703831d35Sstevel static int schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
18803831d35Sstevel 			uint64_t *transidp, uint32_t *lengthp, void *datap,
18903831d35Sstevel 			clock_t timeout, schpc_replylist_t *listp);
19003831d35Sstevel 
19103831d35Sstevel static int schpc_slot_freq(pci_getslot_t *);
19203831d35Sstevel static int schpc_find_dip(dev_info_t *, void *);
19303831d35Sstevel 
19403831d35Sstevel static int schpc_save_leaf(int slot);
19503831d35Sstevel static void schpc_restore_leaf(int slot);
19603831d35Sstevel static int schpc_is_leaf_reset_required(int slot);
19703831d35Sstevel static int schpc_is_freq_switchable(int slot);
19803831d35Sstevel static void schpc_save_entry(int slot, int list_entry, int save_entry);
19903831d35Sstevel static void schpc_restore_entry(int slot, int list_entry, int save_entry);
20003831d35Sstevel 
20103831d35Sstevel /*
20203831d35Sstevel  * Function prototype for Hot Plug Services
20303831d35Sstevel  */
20403831d35Sstevel static int schpc_connect(caddr_t, hpc_slot_t, void *, uint_t);
20503831d35Sstevel static int schpc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
20603831d35Sstevel static int schpc_cpci_control(caddr_t, hpc_slot_t, int, caddr_t);
20703831d35Sstevel static int schpc_pci_control(caddr_t, hpc_slot_t, int, caddr_t);
20803831d35Sstevel 
20903831d35Sstevel extern int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t);
21003831d35Sstevel 
21103831d35Sstevel /*
21203831d35Sstevel  * cb_ops and dev_ops:
21303831d35Sstevel  */
21403831d35Sstevel static struct cb_ops schpc_cb_ops = {
21503831d35Sstevel 	nodev,			/* open */
21603831d35Sstevel 	nodev,			/* close */
21703831d35Sstevel 	nodev,			/* strategy */
21803831d35Sstevel 	nodev,			/* print */
21903831d35Sstevel 	nodev,			/* dump */
22003831d35Sstevel 	nodev,			/* read */
22103831d35Sstevel 	nodev,			/* write */
22203831d35Sstevel 	nodev,			/* ioctl */
22303831d35Sstevel 	nodev,			/* devmap */
22403831d35Sstevel 	nodev,			/* mmap */
22503831d35Sstevel 	nodev,			/* segmap */
22603831d35Sstevel 	nochpoll,		/* poll */
22703831d35Sstevel 	ddi_prop_op,		/* prop_op */
22803831d35Sstevel 	0,			/* streamtab  */
22903831d35Sstevel 	D_NEW | D_MP | D_HOTPLUG /* Driver compatibility flag */
23003831d35Sstevel };
23103831d35Sstevel 
23203831d35Sstevel /*
23303831d35Sstevel  * Function prototype for dev_ops
23403831d35Sstevel  */
23503831d35Sstevel static int schpc_attach(dev_info_t *, ddi_attach_cmd_t);
23603831d35Sstevel static int schpc_detach(dev_info_t *, ddi_detach_cmd_t);
23703831d35Sstevel static int schpc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
23803831d35Sstevel 
23903831d35Sstevel static struct dev_ops schpc_dev_ops = {
24003831d35Sstevel 	DEVO_REV,			/* devo_rev, */
24103831d35Sstevel 	0,				/* refcnt  */
24203831d35Sstevel 	schpc_info,			/* get_dev_info */
24303831d35Sstevel 	nulldev,			/* identify */
24403831d35Sstevel 	nulldev,			/* probe */
24503831d35Sstevel 	schpc_attach,			/* attach */
24603831d35Sstevel 	schpc_detach,			/* detach */
24703831d35Sstevel 	nodev,				/* reset */
24803831d35Sstevel 	&schpc_cb_ops,			/* driver operations */
24919397407SSherry Moore 	(struct bus_ops *)0,		/* no bus operations */
25019397407SSherry Moore 	NULL,				/* power */
25119397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
25203831d35Sstevel };
25303831d35Sstevel 
25403831d35Sstevel /*
25503831d35Sstevel  * loadable module declarations:
25603831d35Sstevel  */
25703831d35Sstevel static struct modldrv modldrv = {
25803831d35Sstevel 	&mod_driverops,
25919397407SSherry Moore 	"PCI Hot Plug Controller Driver (schpc)",
26003831d35Sstevel 	&schpc_dev_ops,
26103831d35Sstevel };
26203831d35Sstevel 
26303831d35Sstevel static struct modlinkage modlinkage = {
26403831d35Sstevel 	MODREV_1,
26503831d35Sstevel 	(void *)&modldrv,
26603831d35Sstevel 	NULL
26703831d35Sstevel };
26803831d35Sstevel 
26903831d35Sstevel int
_init(void)27003831d35Sstevel _init(void)
27103831d35Sstevel {
27203831d35Sstevel 	int		ret;
27303831d35Sstevel 	int		rv;
27403831d35Sstevel 
27503831d35Sstevel 	SCHPC_DEBUG0(D_ATTACH, "_init() installing module");
27603831d35Sstevel 
27703831d35Sstevel 	ret = ddi_soft_state_init(&per_schpc_state, sizeof (schpc_t), 1);
27803831d35Sstevel 	if (ret != 0) {
27903831d35Sstevel 		return (ret);
28003831d35Sstevel 	}
28103831d35Sstevel 
28203831d35Sstevel 	/*
28303831d35Sstevel 	 * Initialize Outgoing Mailbox.
28403831d35Sstevel 	 */
28503831d35Sstevel 	ret = mboxsc_init(KEY_PCSC, MBOXSC_MBOX_OUT, NULL);
28603831d35Sstevel 
28703831d35Sstevel 	if (ret != 0) {
28803831d35Sstevel 		ddi_soft_state_fini(&per_schpc_state);
28903831d35Sstevel 		return (ret);
29003831d35Sstevel 	}
29103831d35Sstevel 
29203831d35Sstevel 	ret = mboxsc_ctrl(KEY_PCSC, MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE,
29303831d35Sstevel 	    (void *) &schpc_putmsg_timeout_range);
29403831d35Sstevel 
29503831d35Sstevel 	if (ret != 0) {
29603831d35Sstevel 		ddi_soft_state_fini(&per_schpc_state);
29703831d35Sstevel 		return (ret);
29803831d35Sstevel 	}
29903831d35Sstevel 
30003831d35Sstevel 	if (schpc_timeout_putmsg < schpc_putmsg_timeout_range.min_timeout) {
30103831d35Sstevel 		schpc_timeout_putmsg = schpc_putmsg_timeout_range.min_timeout;
30203831d35Sstevel 		cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
30303831d35Sstevel 		    schpc_timeout_putmsg);
30403831d35Sstevel 	}
30503831d35Sstevel 
30603831d35Sstevel 	if (schpc_timeout_putmsg > schpc_putmsg_timeout_range.max_timeout) {
30703831d35Sstevel 		schpc_timeout_putmsg = schpc_putmsg_timeout_range.max_timeout;
30803831d35Sstevel 		cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
30903831d35Sstevel 		    schpc_timeout_putmsg);
31003831d35Sstevel 	}
31103831d35Sstevel 
31203831d35Sstevel 	/*
31303831d35Sstevel 	 * Create the schpc_event_taskq for MBOXSC_MSG_EVENT processing.
31403831d35Sstevel 	 */
31503831d35Sstevel 	schpc_event_taskq = taskq_create("schpc_event_taskq", 2,
31603831d35Sstevel 	    minclsyspri, 4, 4, TASKQ_PREPOPULATE);
31703831d35Sstevel 
31803831d35Sstevel 	/*
31903831d35Sstevel 	 * Initialize Incoming Mailbox.
32003831d35Sstevel 	 * NOTE: the callback is null because the schpc_msg_thread will
32103831d35Sstevel 	 * handle all incoming MBOXSC_MSG_EVENT and MBOXSC_MSG_REPLY
32203831d35Sstevel 	 * messages.
32303831d35Sstevel 	 */
32403831d35Sstevel 	ret = mboxsc_init(KEY_SCPC, MBOXSC_MBOX_IN, NULL);
32503831d35Sstevel 
32603831d35Sstevel 	if (ret != 0) {
32703831d35Sstevel 		cmn_err(CE_WARN, "schpc: can not initialize KEY_SCPC as "
32803831d35Sstevel 		    "MBOXSC_MBOX_IN");
32903831d35Sstevel 		ddi_soft_state_fini(&per_schpc_state);
33003831d35Sstevel 		return (ret);
33103831d35Sstevel 	}
33203831d35Sstevel 
33303831d35Sstevel 	ret = mboxsc_ctrl(KEY_SCPC, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE,
33403831d35Sstevel 	    (void *) &schpc_getmsg_timeout_range);
33503831d35Sstevel 
33603831d35Sstevel 	if (ret != 0) {
33703831d35Sstevel 		ddi_soft_state_fini(&per_schpc_state);
33803831d35Sstevel 		return (ret);
33903831d35Sstevel 	}
34003831d35Sstevel 
34103831d35Sstevel 	if (schpc_timeout_getmsg < schpc_getmsg_timeout_range.min_timeout) {
34203831d35Sstevel 		schpc_timeout_getmsg = schpc_getmsg_timeout_range.min_timeout;
34303831d35Sstevel 		cmn_err(CE_WARN, " schpc: resetting getmsg timeout to %ld\n",
34403831d35Sstevel 		    schpc_timeout_getmsg);
34503831d35Sstevel 	}
34603831d35Sstevel 
34703831d35Sstevel 	if (schpc_timeout_getmsg > schpc_getmsg_timeout_range.max_timeout) {
34803831d35Sstevel 		schpc_timeout_getmsg = schpc_getmsg_timeout_range.max_timeout;
34903831d35Sstevel 		cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
35003831d35Sstevel 		    schpc_timeout_putmsg);
35103831d35Sstevel 	}
35203831d35Sstevel 
35303831d35Sstevel 	if (schpc_timeout_event < schpc_getmsg_timeout_range.min_timeout) {
35403831d35Sstevel 		schpc_timeout_event = schpc_getmsg_timeout_range.min_timeout;
35503831d35Sstevel 		cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
35603831d35Sstevel 		    schpc_timeout_event);
35703831d35Sstevel 	}
35803831d35Sstevel 
35903831d35Sstevel 	if (schpc_timeout_event > schpc_getmsg_timeout_range.max_timeout) {
36003831d35Sstevel 		schpc_timeout_event = schpc_getmsg_timeout_range.max_timeout;
36103831d35Sstevel 		cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
36203831d35Sstevel 		    schpc_timeout_event);
36303831d35Sstevel 	}
36403831d35Sstevel 
36503831d35Sstevel 	ret = mod_install(&modlinkage);
36603831d35Sstevel 	if (ret != 0) {
36703831d35Sstevel 		if ((rv = mboxsc_fini(KEY_PCSC)) != 0) {
36803831d35Sstevel 			cmn_err(CE_WARN, "schpc: _init() - "
36903831d35Sstevel 			    "mboxsc_fini(KEY_PCSC) failed: 0x%x", rv);
37003831d35Sstevel 		}
37103831d35Sstevel 		if ((rv = mboxsc_fini(KEY_SCPC)) != 0) {
37203831d35Sstevel 			cmn_err(CE_WARN, "schpc: _init() - "
37303831d35Sstevel 			    "mboxsc_fini(KEY_SCPC) failed: 0x%x", rv);
37403831d35Sstevel 		}
37503831d35Sstevel 		taskq_destroy(schpc_event_taskq);
37603831d35Sstevel 		ddi_soft_state_fini(&per_schpc_state);
37703831d35Sstevel 		return (ret);
37803831d35Sstevel 	}
37903831d35Sstevel 
38003831d35Sstevel 	SCHPC_DEBUG0(D_ATTACH, "_init() module installed");
38103831d35Sstevel 
38203831d35Sstevel 	/*
38303831d35Sstevel 	 * Start the schpc_msg_thread to continuously monitor the
38403831d35Sstevel 	 * MBOXSC_MBOX_IN mailbox for incoming MBOXSC_MSG_EVENTs and
38503831d35Sstevel 	 * MBOXSC_MSG_REPLYs.
38603831d35Sstevel 	 */
38703831d35Sstevel 	mutex_init(&schpc_replylist_mutex, NULL, MUTEX_DRIVER, NULL);
38803831d35Sstevel 	(void) thread_create(NULL, 0, schpc_msg_thread,
38903831d35Sstevel 	    NULL, 0, &p0, TS_RUN, minclsyspri);
39003831d35Sstevel 
39103831d35Sstevel 	SCHPC_DEBUG0(D_ATTACH, "_init() started schpc_msg_thread");
39203831d35Sstevel 
39303831d35Sstevel 	return (ret);
39403831d35Sstevel }
39503831d35Sstevel 
39603831d35Sstevel int
_fini(void)39703831d35Sstevel _fini(void)
39803831d35Sstevel {
39903831d35Sstevel 	SCHPC_DEBUG0(D_ATTACH, "_fini()");
40003831d35Sstevel 
40103831d35Sstevel 	return (DDI_FAILURE);
40203831d35Sstevel }
40303831d35Sstevel 
40403831d35Sstevel int
_info(struct modinfo * modinfop)40503831d35Sstevel _info(struct modinfo *modinfop)
40603831d35Sstevel {
40703831d35Sstevel 	SCHPC_DEBUG0(D_ATTACH, "_info() called.");
40803831d35Sstevel 
40903831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
41003831d35Sstevel }
41103831d35Sstevel 
41203831d35Sstevel static int
schpc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)41303831d35Sstevel schpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
41403831d35Sstevel {
41503831d35Sstevel 	int		instance = ddi_get_instance(devi);
41603831d35Sstevel 	int		rval;
41703831d35Sstevel 
41803831d35Sstevel 	SCHPC_DEBUG1(D_ATTACH, "attach(%x) ATTACH", instance);
41903831d35Sstevel 
42003831d35Sstevel 	switch (cmd) {
42103831d35Sstevel 	case DDI_ATTACH:
42203831d35Sstevel 
42303831d35Sstevel 		/*
42403831d35Sstevel 		 * Allocate the soft state structure for this instance.
42503831d35Sstevel 		 */
42603831d35Sstevel 		rval = ddi_soft_state_zalloc(per_schpc_state, instance);
42703831d35Sstevel 
42803831d35Sstevel 		if (rval != DDI_SUCCESS) {
42903831d35Sstevel 			SCHPC_DEBUG1(D_ATTACH,
43003831d35Sstevel 			    "schpc_attach(%x) Can not allocate "
43103831d35Sstevel 			    "soft state structure", instance);
43203831d35Sstevel 			return (DDI_FAILURE);
43303831d35Sstevel 		}
43403831d35Sstevel 
43503831d35Sstevel 		schpc_p = (schpc_t *)ddi_get_soft_state(per_schpc_state,
43603831d35Sstevel 		    instance);
43703831d35Sstevel 
43803831d35Sstevel 		if (schpc_p == NULL) {
43903831d35Sstevel 			return (DDI_FAILURE);
44003831d35Sstevel 		}
44103831d35Sstevel 
44203831d35Sstevel 		mutex_init(&schpc_p->schpc_mutex, NULL, MUTEX_DRIVER, NULL);
44303831d35Sstevel 		cv_init(&schpc_p->schpc_cv, NULL, CV_DRIVER, NULL);
44403831d35Sstevel 
44503831d35Sstevel 		/*
44603831d35Sstevel 		 * Put schpc structure on global linked list.
44703831d35Sstevel 		 */
44803831d35Sstevel 
44903831d35Sstevel 		/*
45003831d35Sstevel 		 * Initialize starting transaction ID.
45103831d35Sstevel 		 */
45203831d35Sstevel 		schpc_p->schpc_transid = 0;
45303831d35Sstevel 
45403831d35Sstevel 		schpc_p->schpc_number_of_slots = STARCAT_MAX_SLOTS;
45503831d35Sstevel 
45603831d35Sstevel 		SCHPC_DEBUG2(D_ATTACH, "schpc_attach(%x) slot-table property "
45703831d35Sstevel 		    "describes %d slots", instance,
45803831d35Sstevel 		    schpc_p->schpc_number_of_slots);
45903831d35Sstevel 
46003831d35Sstevel 		schpc_p->schpc_hotplugmodel = ddi_getprop(DDI_DEV_T_ANY,
46103831d35Sstevel 		    devi, 0, "hot-plug-model", SCHPC_HOTPLUGTYPE_CPCIHOTPLUG);
46203831d35Sstevel 
46303831d35Sstevel 		SCHPC_DEBUG2(D_ATTACH, "attach(%x) ATTACH - Hot Plug Model=%x",
46403831d35Sstevel 		    instance, schpc_p->schpc_hotplugmodel);
46503831d35Sstevel 
46603831d35Sstevel 		/*
46703831d35Sstevel 		 * What type of hot plug do these slots support?  The only
46803831d35Sstevel 		 * types of slots we support is the cPCI Hot Plug Model
46903831d35Sstevel 		 * and Not Hot Pluggable.
47003831d35Sstevel 		 */
47103831d35Sstevel 		if (schpc_p->schpc_hotplugmodel !=
47203831d35Sstevel 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
47303831d35Sstevel 			schpc_p->schpc_hotplugmodel =
47403831d35Sstevel 			    SCHPC_HOTPLUGTYPE_NOTHOTPLUGGABLE;
47503831d35Sstevel 		}
47603831d35Sstevel 
47703831d35Sstevel 		schpc_p->schpc_slot = (schpc_slot_t *)kmem_zalloc((size_t)
47803831d35Sstevel 		    (schpc_p->schpc_number_of_slots * sizeof (schpc_slot_t)),
47903831d35Sstevel 		    KM_SLEEP);
48003831d35Sstevel 
48103831d35Sstevel 		schpc_p->schpc_devi = devi;
48203831d35Sstevel 		schpc_p->schpc_instance = instance;
48303831d35Sstevel 
48403831d35Sstevel 		/*
48503831d35Sstevel 		 * Start thread to search the device tree and register
48603831d35Sstevel 		 * all found pci slots.
48703831d35Sstevel 		 */
48803831d35Sstevel 		(void) thread_create(NULL, 0, schpc_register_all_slots,
48903831d35Sstevel 		    (void *)schpc_p, 0, &p0, TS_RUN, minclsyspri);
49003831d35Sstevel 
49103831d35Sstevel 		break;
49203831d35Sstevel 
49303831d35Sstevel 	case DDI_PM_RESUME:
49403831d35Sstevel 	case DDI_RESUME:
49503831d35Sstevel 		return (DDI_SUCCESS);
49603831d35Sstevel 	default:
49703831d35Sstevel 		cmn_err(CE_WARN, "schpc%d: Cmd != DDI_ATTACH/DDI_RESUME",
49803831d35Sstevel 		    instance);
49903831d35Sstevel 
50003831d35Sstevel 		return (DDI_FAILURE);
50103831d35Sstevel 	}
50203831d35Sstevel 
50303831d35Sstevel 	SCHPC_DEBUG1(D_ATTACH,
50403831d35Sstevel 	    "schpc_attach(%x) Attach - DDI_SUCCESS", instance);
50503831d35Sstevel 
50603831d35Sstevel 	return (DDI_SUCCESS);
50703831d35Sstevel }
50803831d35Sstevel 
50903831d35Sstevel /*ARGSUSED*/
51003831d35Sstevel static int
schpc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)51103831d35Sstevel schpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
51203831d35Sstevel {
51303831d35Sstevel 	int	instance = ddi_get_instance(devi);
51403831d35Sstevel 
51503831d35Sstevel 	SCHPC_DEBUG1(D_DETACH, "detach(%x) DETACH", instance);
51603831d35Sstevel 
51703831d35Sstevel 	return (DDI_FAILURE);
51803831d35Sstevel }
51903831d35Sstevel 
52003831d35Sstevel /*ARGSUSED*/
52103831d35Sstevel static int
schpc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)52203831d35Sstevel schpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
52303831d35Sstevel 	void **result)
52403831d35Sstevel {
52503831d35Sstevel 	int	error;
52603831d35Sstevel 
52703831d35Sstevel 	switch (infocmd) {
52803831d35Sstevel 	case DDI_INFO_DEVT2DEVINFO:
52903831d35Sstevel 		*result = (void *)schpc_devi;
53003831d35Sstevel 		error = DDI_SUCCESS;
53103831d35Sstevel 		break;
53203831d35Sstevel 	case DDI_INFO_DEVT2INSTANCE:
53303831d35Sstevel 		*result = (void *)0;
53403831d35Sstevel 		error = DDI_SUCCESS;
53503831d35Sstevel 		break;
53603831d35Sstevel 	default:
53703831d35Sstevel 		error = DDI_FAILURE;
53803831d35Sstevel 	}
53903831d35Sstevel 	return (error);
54003831d35Sstevel }
54103831d35Sstevel 
54203831d35Sstevel /*
54303831d35Sstevel  * schpc_connect()
54403831d35Sstevel  *
54503831d35Sstevel  * Called by Hot Plug Services to connect a slot to the bus.
54603831d35Sstevel  */
54703831d35Sstevel 
54803831d35Sstevel /*ARGSUSED*/
54903831d35Sstevel static int
schpc_connect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)55003831d35Sstevel schpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
55103831d35Sstevel {
55203831d35Sstevel 	int		rval;
55303831d35Sstevel 	int		expander, board;
55403831d35Sstevel 	pci_setslot_t	setslot;
55503831d35Sstevel 	pci_getslot_t	getslot;
55603831d35Sstevel 	int		slot;
55703831d35Sstevel 
55803831d35Sstevel 	SCHPC_DEBUG2(D_IOC_CONNECT, "schpc_connect( ops_arg=%p slot_hdl=%p)",
559*07d06da5SSurya Prakki 	    (void *)ops_arg, (void *)slot_hdl);
56003831d35Sstevel 
56103831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
56203831d35Sstevel 
56303831d35Sstevel 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
56403831d35Sstevel 
56503831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
56603831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect - HPC Not Inited");
56703831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
56803831d35Sstevel 		return (HPC_ERR_FAILED);
56903831d35Sstevel 	}
57003831d35Sstevel 
57103831d35Sstevel 	/*
57203831d35Sstevel 	 * Check to see if the slot is already connected.
57303831d35Sstevel 	 */
57403831d35Sstevel 	if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED) {
57503831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
57603831d35Sstevel 		return (0);
57703831d35Sstevel 	}
57803831d35Sstevel 
57903831d35Sstevel 	/*
58003831d35Sstevel 	 * Block if another thread is executing a HPC command.
58103831d35Sstevel 	 */
58203831d35Sstevel 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
58303831d35Sstevel 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
58403831d35Sstevel 	}
58503831d35Sstevel 
58603831d35Sstevel 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
58703831d35Sstevel 
58803831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
58903831d35Sstevel 
59003831d35Sstevel 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
59103831d35Sstevel 	board = schpc_p->schpc_slot[slot].board; /* get board */
59203831d35Sstevel 
59303831d35Sstevel 	SCHPC_DEBUG3(D_IOC_CONNECT,
59403831d35Sstevel 	    "schpc_connect Expander=%x Board=%x Slot=%x",
59503831d35Sstevel 	    expander, board, SCHPC_SLOT_NUM(slot));
59603831d35Sstevel 
59703831d35Sstevel 
59803831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_OCC_GOOD)) {
59903831d35Sstevel 		cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
60003831d35Sstevel 		    "connection on Expander %d Board %d Slot %d - "
60103831d35Sstevel 		    "Ap_Id=%s : Occupant is in failed state",
60203831d35Sstevel 		    expander, board, SCHPC_SLOT_NUM(slot),
60303831d35Sstevel 		    schpc_p->schpc_slot[slot].ap_id);
60403831d35Sstevel 
60503831d35Sstevel 		/* Fault LED should already be illuminated */
60603831d35Sstevel 
60703831d35Sstevel 		goto failed;
60803831d35Sstevel 	}
60903831d35Sstevel 
61003831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD)) {
61103831d35Sstevel 		cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
61203831d35Sstevel 		    "connection on Expander %d Board %d Slot %d - "
61303831d35Sstevel 		    "Ap_Id=%s : Receptacle is in failed state",
61403831d35Sstevel 		    expander, board, SCHPC_SLOT_NUM(slot),
61503831d35Sstevel 		    schpc_p->schpc_slot[slot].ap_id);
61603831d35Sstevel 
61703831d35Sstevel 		/* Fault LED should already be illuminated */
61803831d35Sstevel 
61903831d35Sstevel 		goto failed;
62003831d35Sstevel 	}
62103831d35Sstevel 
62203831d35Sstevel 	rval = schpc_getslotstatus(expander, board, slot, &getslot);
62303831d35Sstevel 
62403831d35Sstevel 	if (rval) {
62503831d35Sstevel 		/*
62603831d35Sstevel 		 * System Controller/Mailbox failure.
62703831d35Sstevel 		 */
62803831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
62903831d35Sstevel 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
63003831d35Sstevel 		    "Communicate with System Controller", expander, board,
63103831d35Sstevel 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
63203831d35Sstevel 
63303831d35Sstevel 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
63403831d35Sstevel 
63503831d35Sstevel 		goto failed;
63603831d35Sstevel 	}
63703831d35Sstevel 
63803831d35Sstevel 	if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
63903831d35Sstevel 
64003831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
64103831d35Sstevel 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
64203831d35Sstevel 		    "Read Slot Status", expander, board,
64303831d35Sstevel 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
64403831d35Sstevel 
64503831d35Sstevel 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
64603831d35Sstevel 
64703831d35Sstevel 		goto failed;
64803831d35Sstevel 	}
64903831d35Sstevel 
65003831d35Sstevel 	if (getslot.slot_empty) {
65103831d35Sstevel 		/*
65203831d35Sstevel 		 * If the slot is empty - fail the connection request.
65303831d35Sstevel 		 */
65403831d35Sstevel 		goto failed;
65503831d35Sstevel 	}
65603831d35Sstevel 
65703831d35Sstevel 	SCHPC_DEBUG3(D_FREQCHG, "Slot %d - slot_freq_setting %d "
65803831d35Sstevel 	    "slot_freq_cap %d", slot, getslot.slot_freq_setting,
65903831d35Sstevel 	    getslot.slot_freq_cap);
66003831d35Sstevel 
66103831d35Sstevel 	if (!schpc_is_freq_switchable(slot) &&
66203831d35Sstevel 	    (getslot.slot_freq_setting > getslot.slot_freq_cap)) {
66303831d35Sstevel 
66403831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
66503831d35Sstevel 		    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
66603831d35Sstevel 		    "Bus Speed Mismatch", expander,
66703831d35Sstevel 		    board, SCHPC_SLOT_NUM(slot),
66803831d35Sstevel 		    schpc_p->schpc_slot[slot].ap_id);
66903831d35Sstevel 
67003831d35Sstevel 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
67103831d35Sstevel 
67203831d35Sstevel 		goto failed;
67303831d35Sstevel 	}
67403831d35Sstevel 
67503831d35Sstevel 	if (schpc_is_leaf_reset_required(slot) &&
67603831d35Sstevel 	    (schpc_p->schpc_slot[slot].saved_regs == NULL)) {
67703831d35Sstevel 
67803831d35Sstevel 		SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Save Regs before connect",
67903831d35Sstevel 		    slot);
68003831d35Sstevel 
68103831d35Sstevel 		/*
68203831d35Sstevel 		 * A prior disconnect had not saved off the leaf so lets
68303831d35Sstevel 		 * save it now. This is probably due to the domain being
68403831d35Sstevel 		 * booted with a slot with no cassette.
68503831d35Sstevel 		 */
68603831d35Sstevel 		if (schpc_save_leaf(slot) != 0) {
68703831d35Sstevel 			cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
68803831d35Sstevel 
68903831d35Sstevel 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
69003831d35Sstevel 			    expander, board, slot & 3,
69103831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
69203831d35Sstevel 
69303831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
69403831d35Sstevel 
69503831d35Sstevel 			goto failed;
69603831d35Sstevel 		}
69703831d35Sstevel 	}
69803831d35Sstevel 
69903831d35Sstevel 	/*
70003831d35Sstevel 	 * Initialize Set Slot Command.
70103831d35Sstevel 	 */
70203831d35Sstevel 	schpc_init_setslot_message(&setslot);
70303831d35Sstevel 
70403831d35Sstevel 	setslot.slot_power_on = PCIMSG_ON;	   /* Turn slot power on */
70503831d35Sstevel 
70603831d35Sstevel 	setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash Fault LED */
70703831d35Sstevel 
70803831d35Sstevel 	rval = schpc_setslotstatus(expander, board, slot, &setslot);
70903831d35Sstevel 
71003831d35Sstevel 	if (rval != 0) {
71103831d35Sstevel 		/*
71203831d35Sstevel 		 * System Controller/Mailbox failure.
71303831d35Sstevel 		 */
71403831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
71503831d35Sstevel 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
71603831d35Sstevel 		    "Communicate with System Controller", expander, board,
71703831d35Sstevel 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
71803831d35Sstevel 
71903831d35Sstevel 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
72003831d35Sstevel 
72103831d35Sstevel 		goto failed;
72203831d35Sstevel 	}
72303831d35Sstevel 
72403831d35Sstevel 	if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
72503831d35Sstevel 
72603831d35Sstevel 		/*
72703831d35Sstevel 		 * The Request was successfully completed.
72803831d35Sstevel 		 */
72903831d35Sstevel 
73003831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect() - setslotstatus "
73103831d35Sstevel 		    "succeeded");
73203831d35Sstevel 
73303831d35Sstevel 		/*
73403831d35Sstevel 		 * Need to check HEALTHY# signal.
73503831d35Sstevel 		 */
73603831d35Sstevel 		rval = schpc_getslotstatus(expander, board, slot, &getslot);
73703831d35Sstevel 
73803831d35Sstevel 		if (rval) {
73903831d35Sstevel 			/*
74003831d35Sstevel 			 * System Controller/Mailbox failure.
74103831d35Sstevel 			 */
74203831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
74303831d35Sstevel 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
74403831d35Sstevel 			    "Unable to Communicate with System Controller",
74503831d35Sstevel 			    expander, board, SCHPC_SLOT_NUM(slot),
74603831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
74703831d35Sstevel 
74803831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
74903831d35Sstevel 
75003831d35Sstevel 			goto failed;
75103831d35Sstevel 		}
75203831d35Sstevel 
75303831d35Sstevel 		if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
75403831d35Sstevel 
75503831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
75603831d35Sstevel 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
75703831d35Sstevel 			    "Unable to Read Slot Status", expander, board,
75803831d35Sstevel 			    SCHPC_SLOT_NUM(slot),
75903831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
76003831d35Sstevel 
76103831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
76203831d35Sstevel 
76303831d35Sstevel 			goto failed;
76403831d35Sstevel 		}
76503831d35Sstevel 
76603831d35Sstevel 		if ((getslot.slot_powergood != PCIMSG_ON) ||
76703831d35Sstevel 		    (getslot.slot_powerfault == PCIMSG_ON)) {
76803831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
76903831d35Sstevel 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
77003831d35Sstevel 			    "Power failure detected", expander, board,
77103831d35Sstevel 			    SCHPC_SLOT_NUM(slot),
77203831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
77303831d35Sstevel 
77403831d35Sstevel 			/*
77503831d35Sstevel 			 * Initialize Set Slot Command.
77603831d35Sstevel 			 */
77703831d35Sstevel 			schpc_init_setslot_message(&setslot);
77803831d35Sstevel 
77903831d35Sstevel 			/*
78003831d35Sstevel 			 * Turn slot power off.
78103831d35Sstevel 			 */
78203831d35Sstevel 			setslot.slot_power_off = PCIMSG_ON;
78303831d35Sstevel 
78403831d35Sstevel 			(void) schpc_setslotstatus(expander, board,
78503831d35Sstevel 			    slot, &setslot);
78603831d35Sstevel 
78703831d35Sstevel 			schpc_setslotled(expander, board, slot,
78803831d35Sstevel 			    (SERVICE_LED_ON | FAULT_LED_ON));
78903831d35Sstevel 
79003831d35Sstevel 			goto failed;
79103831d35Sstevel 		}
79203831d35Sstevel 
79303831d35Sstevel 		if (!getslot.slot_HEALTHY) {
79403831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
79503831d35Sstevel 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
79603831d35Sstevel 			    "Adapter did not assert HEALTHY#", expander, board,
79703831d35Sstevel 			    SCHPC_SLOT_NUM(slot),
79803831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
79903831d35Sstevel 
80003831d35Sstevel 			/*
80103831d35Sstevel 			 * Initialize Set Slot Command.
80203831d35Sstevel 			 */
80303831d35Sstevel 			schpc_init_setslot_message(&setslot);
80403831d35Sstevel 
80503831d35Sstevel 			/*
80603831d35Sstevel 			 * Turn slot power off.
80703831d35Sstevel 			 */
80803831d35Sstevel 			setslot.slot_power_off = PCIMSG_ON;
80903831d35Sstevel 
81003831d35Sstevel 			(void) schpc_setslotstatus(expander, board, slot,
81103831d35Sstevel 			    &setslot);
81203831d35Sstevel 
81303831d35Sstevel 			schpc_setslotled(expander, board, slot,
81403831d35Sstevel 			    (SERVICE_LED_ON | FAULT_LED_ON));
81503831d35Sstevel 
81603831d35Sstevel 			goto failed;
81703831d35Sstevel 		}
81803831d35Sstevel 
81903831d35Sstevel 		/*
82003831d35Sstevel 		 * Initialize Set Slot Command.
82103831d35Sstevel 		 */
82203831d35Sstevel 		schpc_init_setslot_message(&setslot);
82303831d35Sstevel 
82403831d35Sstevel 		/*
82503831d35Sstevel 		 * Start monitoring ENUM# and HEALTHY#
82603831d35Sstevel 		 */
82703831d35Sstevel 		setslot.slot_enable_HEALTHY = PCIMSG_ON;
82803831d35Sstevel 		setslot.slot_enable_ENUM = PCIMSG_ON;
82903831d35Sstevel 
83003831d35Sstevel 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
83103831d35Sstevel 
83203831d35Sstevel 		if (rval != 0) {
83303831d35Sstevel 			/*
83403831d35Sstevel 			 * System Controller/Mailbox failure.
83503831d35Sstevel 			 */
83603831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
83703831d35Sstevel 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
83803831d35Sstevel 			    "Unable to Communicate with System Controller",
83903831d35Sstevel 			    expander, board, SCHPC_SLOT_NUM(slot),
84003831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
84103831d35Sstevel 
84203831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
84303831d35Sstevel 
84403831d35Sstevel 			goto failed;
84503831d35Sstevel 		}
84603831d35Sstevel 		if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
84703831d35Sstevel 
84803831d35Sstevel 			int		freq;
84903831d35Sstevel 			find_dev_t	find_dev;
85003831d35Sstevel 
85103831d35Sstevel 			/*
85203831d35Sstevel 			 * The Request was successfully completed.
85303831d35Sstevel 			 */
85403831d35Sstevel 
85503831d35Sstevel 			SCHPC_DEBUG0(D_IOC_CONNECT,
85603831d35Sstevel 			    "schpc_connect() - setslotstatus succeeded");
85703831d35Sstevel 
85803831d35Sstevel 			schpc_p->schpc_slot[slot].state |=
85903831d35Sstevel 			    SCHPC_SLOTSTATE_CONNECTED;
86003831d35Sstevel 
86103831d35Sstevel 			schpc_setslotled(expander, board, slot,
86203831d35Sstevel 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_OFF));
86303831d35Sstevel 
86403831d35Sstevel 			find_dev.cname = schpc_p->schpc_slot[slot].nexus_path;
86503831d35Sstevel 			find_dev.caddr = (char *)kmem_alloc(MAXPATHLEN,
86603831d35Sstevel 			    KM_SLEEP);
86703831d35Sstevel 			find_dev.dip = NULL;
86803831d35Sstevel 
86903831d35Sstevel 			/* root node doesn't have to be held */
87003831d35Sstevel 			ddi_walk_devs(ddi_root_node(), schpc_find_dip,
87103831d35Sstevel 			    &find_dev);
87203831d35Sstevel 			if (find_dev.dip != NULL) {
87303831d35Sstevel 				/*
87403831d35Sstevel 				 * Update the clock-frequency property to
87503831d35Sstevel 				 * reflect the new slot-frequency.
87603831d35Sstevel 				 */
87703831d35Sstevel 				freq = schpc_slot_freq(&getslot);
87803831d35Sstevel 				SCHPC_DEBUG2(D_FREQCHG,
87903831d35Sstevel 				    "schpc_connect: updating dip=%p freq=%dHZ",
880*07d06da5SSurya Prakki 				    (void *)find_dev.dip, freq);
88103831d35Sstevel 				if (ndi_prop_update_int(DDI_DEV_T_NONE,
88203831d35Sstevel 				    find_dev.dip, "clock-frequency", freq)
88303831d35Sstevel 				    != DDI_SUCCESS) {
88403831d35Sstevel 					cmn_err(CE_WARN,
88503831d35Sstevel 					    "schpc: - failed to update "
88603831d35Sstevel 					    "clock-frequency property for %s",
88703831d35Sstevel 					    find_dev.cname);
88803831d35Sstevel 				}
88903831d35Sstevel 				ndi_rele_devi(find_dev.dip);
89003831d35Sstevel 			} else {
89103831d35Sstevel 				cmn_err(CE_WARN,
89203831d35Sstevel 				    "schpc: couldn't find dip for %s ",
89303831d35Sstevel 				    find_dev.cname);
89403831d35Sstevel 			}
89503831d35Sstevel 			kmem_free(find_dev.caddr, MAXPATHLEN);
89603831d35Sstevel 
89703831d35Sstevel 			mutex_enter(&schpc_p->schpc_mutex);
89803831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
89903831d35Sstevel 			    ~SCHPC_SLOTSTATE_EXECUTING;
90003831d35Sstevel 
90103831d35Sstevel 			/*
90203831d35Sstevel 			 * If leaf registers were saved off, then they
90303831d35Sstevel 			 * need to be restored.
90403831d35Sstevel 			 */
90503831d35Sstevel 			schpc_restore_leaf(slot);
90603831d35Sstevel 
90703831d35Sstevel 			/*
90803831d35Sstevel 			 * Since the device saw a PCI Reset, we need to
90903831d35Sstevel 			 * wait 2^25 clock cycles before the first
91003831d35Sstevel 			 * Configuration access. The worst case is 33MHz,
91103831d35Sstevel 			 * which is a 1 second wait.
91203831d35Sstevel 			 */
91303831d35Sstevel 			drv_usecwait(1000000);
91403831d35Sstevel 
91503831d35Sstevel 			cv_signal(&schpc_p->schpc_cv);
91603831d35Sstevel 			mutex_exit(&schpc_p->schpc_mutex);
91703831d35Sstevel 
91803831d35Sstevel 			return (0);
91903831d35Sstevel 		} else {
92003831d35Sstevel 			/*
92103831d35Sstevel 			 * The System Controller Rejected the
92203831d35Sstevel 			 * connection request.
92303831d35Sstevel 			 */
92403831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
92503831d35Sstevel 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s :"
92603831d35Sstevel 			    "System Controller failed connection request",
92703831d35Sstevel 			    expander, board, SCHPC_SLOT_NUM(slot),
92803831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
92903831d35Sstevel 
93003831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
93103831d35Sstevel 
93203831d35Sstevel 			goto failed;
93303831d35Sstevel 		}
93403831d35Sstevel 	}
93503831d35Sstevel 
93603831d35Sstevel 	/*
93703831d35Sstevel 	 * The System Controller Rejected the connection request.
93803831d35Sstevel 	 */
93903831d35Sstevel 	cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
94003831d35Sstevel 	    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
94103831d35Sstevel 	    "failed connection request", expander, board, SCHPC_SLOT_NUM(slot),
94203831d35Sstevel 	    schpc_p->schpc_slot[slot].ap_id);
94303831d35Sstevel 
94403831d35Sstevel 	schpc_setslotled(expander, board, slot, FAULT_LED_ON);
94503831d35Sstevel 
94603831d35Sstevel failed:
94703831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
94803831d35Sstevel 	schpc_p->schpc_slot[slot].state &=
94903831d35Sstevel 	    ~SCHPC_SLOTSTATE_EXECUTING;
95003831d35Sstevel 	cv_signal(&schpc_p->schpc_cv);
95103831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
95203831d35Sstevel 
95303831d35Sstevel 	return (HPC_ERR_FAILED);
95403831d35Sstevel }
95503831d35Sstevel 
95603831d35Sstevel /*
95703831d35Sstevel  * schpc_disconnect()
95803831d35Sstevel  *
95903831d35Sstevel  * Called by Hot Plug Services to disconnect a slot to the bus.
96003831d35Sstevel  */
96103831d35Sstevel 
96203831d35Sstevel /*ARGSUSED*/
96303831d35Sstevel static int
schpc_disconnect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)96403831d35Sstevel schpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data,
96503831d35Sstevel 	uint_t flags)
96603831d35Sstevel {
96703831d35Sstevel 	int		rval;
96803831d35Sstevel 	int		expander, board, slot;
96903831d35Sstevel 	pci_setslot_t	setslot;
97003831d35Sstevel 
97103831d35Sstevel 	SCHPC_DEBUG2(D_IOC_CONNECT,
972*07d06da5SSurya Prakki 	    "schpc_disconnect( ops_arg=%p slot_hdl=%p)", (void *)ops_arg,
973*07d06da5SSurya Prakki 	    slot_hdl);
97403831d35Sstevel 
97503831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
97603831d35Sstevel 
97703831d35Sstevel 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
97803831d35Sstevel 
97903831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
98003831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONNECT,
98103831d35Sstevel 		    "schpc_disconnect - HPC Not Inited");
98203831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
98303831d35Sstevel 		return (HPC_ERR_FAILED);
98403831d35Sstevel 	}
98503831d35Sstevel 
98603831d35Sstevel 	/*
98703831d35Sstevel 	 * Check to see if we are already disconnected.
98803831d35Sstevel 	 */
98903831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) {
99003831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
99103831d35Sstevel 		return (0);
99203831d35Sstevel 	}
99303831d35Sstevel 
99403831d35Sstevel 	/*
99503831d35Sstevel 	 * Block if another thread is executing a HPC command.
99603831d35Sstevel 	 */
99703831d35Sstevel 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
99803831d35Sstevel 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
99903831d35Sstevel 	}
100003831d35Sstevel 
100103831d35Sstevel 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
100203831d35Sstevel 
100303831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
100403831d35Sstevel 
100503831d35Sstevel 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
100603831d35Sstevel 	board = schpc_p->schpc_slot[slot].board; /* get board */
100703831d35Sstevel 
100803831d35Sstevel 	/*
100903831d35Sstevel 	 * If a leaf reset is going to be asserted due to a mode/freq.
101003831d35Sstevel 	 * change, then the leaf registers of the XMITS bridge will need
101103831d35Sstevel 	 * to be saved off prior to the connect.
101203831d35Sstevel 	 */
101303831d35Sstevel 	if (schpc_is_leaf_reset_required(slot)) {
101403831d35Sstevel 		if (schpc_save_leaf(slot) != 0) {
101503831d35Sstevel 
101603831d35Sstevel 			cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
101703831d35Sstevel 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
101803831d35Sstevel 			    expander, board, slot & 3,
101903831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
102003831d35Sstevel 
102103831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
102203831d35Sstevel 
102303831d35Sstevel 			goto failed;
102403831d35Sstevel 		}
102503831d35Sstevel 	}
102603831d35Sstevel 
102703831d35Sstevel 	/*
102803831d35Sstevel 	 * Initialize Set Slot Command.
102903831d35Sstevel 	 */
103003831d35Sstevel 	schpc_init_setslot_message(&setslot);
103103831d35Sstevel 
103203831d35Sstevel 	setslot.slot_power_off = PCIMSG_ON;	   /* Turn Power Off */
103303831d35Sstevel 
103403831d35Sstevel 	setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */
103503831d35Sstevel 
103603831d35Sstevel 	setslot.slot_disable_ENUM = PCIMSG_ON;	   /* Mask the ENUM# signal */
103703831d35Sstevel 	setslot.slot_disable_HEALTHY = PCIMSG_ON;  /* Mask the HEALTHY# sig */
103803831d35Sstevel 
103903831d35Sstevel 	rval = schpc_setslotstatus(expander, board, slot, &setslot);
104003831d35Sstevel 
104103831d35Sstevel 	SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
104203831d35Sstevel 	    "setslotstatus returned 0x%x", rval);
104303831d35Sstevel 
104403831d35Sstevel 	if (rval != 0) {
104503831d35Sstevel 		/*
104603831d35Sstevel 		 * System Controller/Mailbox failure.
104703831d35Sstevel 		 */
104803831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
104903831d35Sstevel 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
105003831d35Sstevel 		    "Communicate with System Controller", expander, board,
105103831d35Sstevel 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
105203831d35Sstevel 
105303831d35Sstevel 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
105403831d35Sstevel 
105503831d35Sstevel 		goto failed;
105603831d35Sstevel 	}
105703831d35Sstevel 
105803831d35Sstevel 	SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
105903831d35Sstevel 	    "slot_replystatus returned 0x%x", setslot.slot_replystatus);
106003831d35Sstevel 
106103831d35Sstevel 	if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
106203831d35Sstevel 
106303831d35Sstevel 		/*
106403831d35Sstevel 		 * The Request was successfully completed.
106503831d35Sstevel 		 */
106603831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
106703831d35Sstevel 		    ~SCHPC_SLOTSTATE_CONNECTED;
106803831d35Sstevel 
106903831d35Sstevel 		schpc_setslotled(expander, board, slot,
107003831d35Sstevel 		    (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF));
107103831d35Sstevel 
107203831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONNECT,
107303831d35Sstevel 		    "schpc_disconnect() - setslotstatus succeeded");
107403831d35Sstevel 
107503831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
107603831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
107703831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
107803831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
107903831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
108003831d35Sstevel 
108103831d35Sstevel 		return (0);
108203831d35Sstevel 	}
108303831d35Sstevel 	/*
108403831d35Sstevel 	 * System Controller/Mailbox failure.
108503831d35Sstevel 	 */
108603831d35Sstevel 	cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
108703831d35Sstevel 	    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
108803831d35Sstevel 	    "failed disconnection request", expander, board,
108903831d35Sstevel 	    SCHPC_SLOT_NUM(slot),
109003831d35Sstevel 	    schpc_p->schpc_slot[slot].ap_id);
109103831d35Sstevel 
109203831d35Sstevel 	schpc_setslotled(expander, board, slot, FAULT_LED_ON);
109303831d35Sstevel 
109403831d35Sstevel failed:
109503831d35Sstevel 	schpc_restore_leaf(slot);
109603831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
109703831d35Sstevel 	schpc_p->schpc_slot[slot].state &=
109803831d35Sstevel 	    ~SCHPC_SLOTSTATE_EXECUTING;
109903831d35Sstevel 	cv_signal(&schpc_p->schpc_cv);
110003831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
110103831d35Sstevel 
110203831d35Sstevel 	return (HPC_ERR_FAILED);
110303831d35Sstevel }
110403831d35Sstevel 
110503831d35Sstevel /*
110603831d35Sstevel  * schpc_cpci_control
110703831d35Sstevel  *
110803831d35Sstevel  * Called by Hot Plug Services to perform a attachment point specific
110903831d35Sstevel  * on a Hot Pluggable Compact PCI Slot.
111003831d35Sstevel  */
111103831d35Sstevel /*ARGSUSED*/
111203831d35Sstevel static int
schpc_cpci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)111303831d35Sstevel schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
111403831d35Sstevel     caddr_t arg)
111503831d35Sstevel {
111603831d35Sstevel 	int		rval;
111703831d35Sstevel 	int		expander, board, slot;
111803831d35Sstevel 	pci_setslot_t	setslot;
111903831d35Sstevel 	pci_getslot_t   slotstatus;
112003831d35Sstevel 	hpc_led_info_t	*hpc_led_info;
112103831d35Sstevel 
112203831d35Sstevel 	SCHPC_DEBUG3(D_IOC_CONTROL,
112303831d35Sstevel 	    "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)",
1124*07d06da5SSurya Prakki 	    (void *)ops_arg, (void *)slot_hdl, request);
112503831d35Sstevel 
112603831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
112703831d35Sstevel 
112803831d35Sstevel 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
112903831d35Sstevel 
113003831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
113103831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONNECT,
113203831d35Sstevel 		    "schpc_disconnect - HPC Not Inited");
113303831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
113403831d35Sstevel 		return (HPC_ERR_FAILED);
113503831d35Sstevel 	}
113603831d35Sstevel 
113703831d35Sstevel 	/*
113803831d35Sstevel 	 * Block if another thread is executing a HPC command.
113903831d35Sstevel 	 */
114003831d35Sstevel 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
114103831d35Sstevel 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
114203831d35Sstevel 	}
114303831d35Sstevel 
114403831d35Sstevel 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
114503831d35Sstevel 
114603831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
114703831d35Sstevel 
114803831d35Sstevel 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
114903831d35Sstevel 	board = schpc_p->schpc_slot[slot].board; /* get board */
115003831d35Sstevel 
115103831d35Sstevel 	/*
115203831d35Sstevel 	 * Initialize Set Slot Command.
115303831d35Sstevel 	 */
115403831d35Sstevel 	schpc_init_setslot_message(&setslot);
115503831d35Sstevel 
115603831d35Sstevel 	/*
115703831d35Sstevel 	 * Initialize LED to last know state.
115803831d35Sstevel 	 */
115903831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_power) {
116003831d35Sstevel 	case LED_ON:
116103831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_ON;
116203831d35Sstevel 		break;
116303831d35Sstevel 	case LED_OFF:
116403831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_OFF;
116503831d35Sstevel 		break;
116603831d35Sstevel 	case LED_FLASH:
116703831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_FLASH;
116803831d35Sstevel 		break;
116903831d35Sstevel 	}
117003831d35Sstevel 
117103831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_service) {
117203831d35Sstevel 	case LED_ON:
117303831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_ON;
117403831d35Sstevel 		break;
117503831d35Sstevel 	case LED_OFF:
117603831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_OFF;
117703831d35Sstevel 		break;
117803831d35Sstevel 	case LED_FLASH:
117903831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_FLASH;
118003831d35Sstevel 		break;
118103831d35Sstevel 	}
118203831d35Sstevel 
118303831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
118403831d35Sstevel 	case LED_ON:
118503831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_ON;
118603831d35Sstevel 		break;
118703831d35Sstevel 	case LED_OFF:
118803831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_OFF;
118903831d35Sstevel 		break;
119003831d35Sstevel 	case LED_FLASH:
119103831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
119203831d35Sstevel 		break;
119303831d35Sstevel 	}
119403831d35Sstevel 
119503831d35Sstevel 	switch (request) {
119603831d35Sstevel 
119703831d35Sstevel 	case HPC_CTRL_GET_LED_STATE:
119803831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
119903831d35Sstevel 		    "HPC_CTRL_GET_LED_STATE");
120003831d35Sstevel 		hpc_led_info = (hpc_led_info_t *)arg;
120103831d35Sstevel 
120203831d35Sstevel 		switch (hpc_led_info->led) {
120303831d35Sstevel 		case HPC_FAULT_LED:
120403831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
120503831d35Sstevel 			case LED_OFF:
120603831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
120703831d35Sstevel 				break;
120803831d35Sstevel 			case LED_ON:
120903831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
121003831d35Sstevel 				break;
121103831d35Sstevel 			case LED_FLASH:
121203831d35Sstevel 				hpc_led_info->state = HPC_LED_BLINK;
121303831d35Sstevel 				break;
121403831d35Sstevel 			}
121503831d35Sstevel 			break;
121603831d35Sstevel 
121703831d35Sstevel 		case HPC_POWER_LED:
121803831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_power) {
121903831d35Sstevel 			case LED_OFF:
122003831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
122103831d35Sstevel 				break;
122203831d35Sstevel 			case LED_ON:
122303831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
122403831d35Sstevel 				break;
122503831d35Sstevel 			case LED_FLASH:
122603831d35Sstevel 				hpc_led_info->state = HPC_LED_BLINK;
122703831d35Sstevel 				break;
122803831d35Sstevel 			}
122903831d35Sstevel 			break;
123003831d35Sstevel 		case HPC_ATTN_LED:
123103831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
123203831d35Sstevel 			case LED_OFF:
123303831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
123403831d35Sstevel 				break;
123503831d35Sstevel 			case LED_ON:
123603831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
123703831d35Sstevel 				break;
123803831d35Sstevel 			case LED_FLASH:
123903831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
124003831d35Sstevel 				break;
124103831d35Sstevel 			}
124203831d35Sstevel 			break;
124303831d35Sstevel 		case HPC_ACTIVE_LED:
124403831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_service) {
124503831d35Sstevel 			case LED_OFF:
124603831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
124703831d35Sstevel 				break;
124803831d35Sstevel 			case LED_ON:
124903831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
125003831d35Sstevel 				break;
125103831d35Sstevel 			case LED_FLASH:
125203831d35Sstevel 				hpc_led_info->state = HPC_LED_BLINK;
125303831d35Sstevel 				break;
125403831d35Sstevel 			}
125503831d35Sstevel 			break;
125603831d35Sstevel 		default:
125703831d35Sstevel 			SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
125803831d35Sstevel 			    "Invalid LED %x", hpc_led_info->led);
125903831d35Sstevel 
126003831d35Sstevel 			mutex_enter(&schpc_p->schpc_mutex);
126103831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
126203831d35Sstevel 			    ~SCHPC_SLOTSTATE_EXECUTING;
126303831d35Sstevel 			cv_signal(&schpc_p->schpc_cv);
126403831d35Sstevel 			mutex_exit(&schpc_p->schpc_mutex);
126503831d35Sstevel 
126603831d35Sstevel 			return (HPC_ERR_FAILED);
126703831d35Sstevel 		}
126803831d35Sstevel 
126903831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
127003831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
127103831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
127203831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
127303831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
127403831d35Sstevel 
127503831d35Sstevel 		return (0);
127603831d35Sstevel 
127703831d35Sstevel 	case HPC_CTRL_SET_LED_STATE:
127803831d35Sstevel 		hpc_led_info = (hpc_led_info_t *)arg;
127903831d35Sstevel 
128003831d35Sstevel 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1281*07d06da5SSurya Prakki 		    "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1282*07d06da5SSurya Prakki 		    (void *)hpc_led_info);
128303831d35Sstevel 
128403831d35Sstevel 		switch (hpc_led_info->led) {
128503831d35Sstevel 		case HPC_FAULT_LED:
128603831d35Sstevel 			switch (hpc_led_info->state) {
128703831d35Sstevel 			case HPC_LED_OFF:
128803831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
128903831d35Sstevel 				    LED_OFF;
129003831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_OFF;
129103831d35Sstevel 				break;
129203831d35Sstevel 			case HPC_LED_ON:
129303831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
129403831d35Sstevel 				    LED_ON;
129503831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_ON;
129603831d35Sstevel 				break;
129703831d35Sstevel 			case HPC_LED_BLINK:
129803831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
129903831d35Sstevel 				    LED_FLASH;
130003831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
130103831d35Sstevel 				break;
130203831d35Sstevel 			}
130303831d35Sstevel 			break;
130403831d35Sstevel 		case HPC_POWER_LED:
130503831d35Sstevel 			switch (hpc_led_info->state) {
130603831d35Sstevel 			case HPC_LED_OFF:
130703831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_power =
130803831d35Sstevel 				    LED_OFF;
130903831d35Sstevel 				setslot.slot_led_power = PCIMSG_LED_OFF;
131003831d35Sstevel 				break;
131103831d35Sstevel 			case HPC_LED_ON:
131203831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_power =
131303831d35Sstevel 				    LED_ON;
131403831d35Sstevel 				setslot.slot_led_power = PCIMSG_LED_ON;
131503831d35Sstevel 				break;
131603831d35Sstevel 			case HPC_LED_BLINK:
131703831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_power =
131803831d35Sstevel 				    LED_FLASH;
131903831d35Sstevel 				setslot.slot_led_power = PCIMSG_LED_FLASH;
132003831d35Sstevel 				break;
132103831d35Sstevel 			}
132203831d35Sstevel 			break;
132303831d35Sstevel 		case HPC_ATTN_LED:
132403831d35Sstevel 			switch (hpc_led_info->state) {
132503831d35Sstevel 			case HPC_LED_OFF:
132603831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
132703831d35Sstevel 				    LED_OFF;
132803831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_OFF;
132903831d35Sstevel 				break;
133003831d35Sstevel 			case HPC_LED_ON:
133103831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
133203831d35Sstevel 				    LED_FLASH;
133303831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
133403831d35Sstevel 				break;
133503831d35Sstevel 			case HPC_LED_BLINK:
133603831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
133703831d35Sstevel 				    LED_FLASH;
133803831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
133903831d35Sstevel 				break;
134003831d35Sstevel 			}
134103831d35Sstevel 			break;
134203831d35Sstevel 		case HPC_ACTIVE_LED:
134303831d35Sstevel 			switch (hpc_led_info->state) {
134403831d35Sstevel 			case HPC_LED_OFF:
134503831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_service =
134603831d35Sstevel 				    LED_OFF;
134703831d35Sstevel 				setslot.slot_led_service = PCIMSG_LED_OFF;
134803831d35Sstevel 				break;
134903831d35Sstevel 			case HPC_LED_ON:
135003831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_service =
135103831d35Sstevel 				    LED_ON;
135203831d35Sstevel 				setslot.slot_led_service = PCIMSG_LED_ON;
135303831d35Sstevel 				break;
135403831d35Sstevel 			case HPC_LED_BLINK:
135503831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_service =
135603831d35Sstevel 				    LED_FLASH;
135703831d35Sstevel 				setslot.slot_led_service = PCIMSG_LED_FLASH;
135803831d35Sstevel 				break;
135903831d35Sstevel 			}
136003831d35Sstevel 			break;
136103831d35Sstevel 		default:
136203831d35Sstevel 			mutex_enter(&schpc_p->schpc_mutex);
136303831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
136403831d35Sstevel 			    ~SCHPC_SLOTSTATE_EXECUTING;
136503831d35Sstevel 			cv_signal(&schpc_p->schpc_cv);
136603831d35Sstevel 			mutex_exit(&schpc_p->schpc_mutex);
136703831d35Sstevel 
136803831d35Sstevel 			return (0);
136903831d35Sstevel 		}
137003831d35Sstevel 
137103831d35Sstevel 		(void) schpc_setslotstatus(expander, board, slot, &setslot);
137203831d35Sstevel 
137303831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
137403831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
137503831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
137603831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
137703831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
137803831d35Sstevel 
137903831d35Sstevel 		return (0);
138003831d35Sstevel 
138103831d35Sstevel 	case HPC_CTRL_GET_SLOT_STATE: {
138203831d35Sstevel 		hpc_slot_state_t	*hpc_slot_state;
138303831d35Sstevel 
138403831d35Sstevel 		hpc_slot_state = (hpc_slot_state_t *)arg;
138503831d35Sstevel 
138603831d35Sstevel 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
138703831d35Sstevel 		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1388*07d06da5SSurya Prakki 		    (void *)hpc_slot_state);
138903831d35Sstevel 
139003831d35Sstevel 		rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
139103831d35Sstevel 
139203831d35Sstevel 		if (!rval) {
139303831d35Sstevel 
139403831d35Sstevel 			if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
139503831d35Sstevel 				return (HPC_ERR_FAILED);
139603831d35Sstevel 			}
139703831d35Sstevel 
139803831d35Sstevel 			if (slotstatus.slot_empty == PCIMSG_ON) {
139903831d35Sstevel 				*hpc_slot_state = HPC_SLOT_EMPTY;
140003831d35Sstevel 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
140103831d35Sstevel 			} else if (slotstatus.slot_power_on == PCIMSG_ON) {
140203831d35Sstevel 				*hpc_slot_state = HPC_SLOT_CONNECTED;
140303831d35Sstevel 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
140403831d35Sstevel 				schpc_p->schpc_slot[slot].state |=
140503831d35Sstevel 				    SCHPC_SLOTSTATE_CONNECTED;
140603831d35Sstevel 			} else {
140703831d35Sstevel 				*hpc_slot_state = HPC_SLOT_DISCONNECTED;
140803831d35Sstevel 				SCHPC_DEBUG0(D_IOC_CONTROL,
140903831d35Sstevel 				    "Slot Disconnected");
141003831d35Sstevel 				schpc_p->schpc_slot[slot].state &=
141103831d35Sstevel 				    ~SCHPC_SLOTSTATE_CONNECTED;
141203831d35Sstevel 			}
141303831d35Sstevel 		} else {
141403831d35Sstevel 			SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
141503831d35Sstevel 
141603831d35Sstevel 			mutex_enter(&schpc_p->schpc_mutex);
141703831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
141803831d35Sstevel 			    ~SCHPC_SLOTSTATE_EXECUTING;
141903831d35Sstevel 			cv_signal(&schpc_p->schpc_cv);
142003831d35Sstevel 			mutex_exit(&schpc_p->schpc_mutex);
142103831d35Sstevel 
142203831d35Sstevel 			return (HPC_ERR_FAILED);
142303831d35Sstevel 		}
142403831d35Sstevel 
142503831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
142603831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
142703831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
142803831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
142903831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
143003831d35Sstevel 
143103831d35Sstevel 		return (0);
143203831d35Sstevel 	}
143303831d35Sstevel 	case HPC_CTRL_GET_BOARD_TYPE: {
143403831d35Sstevel 		hpc_board_type_t	*hpc_board_type;
143503831d35Sstevel 
143603831d35Sstevel 		hpc_board_type = (hpc_board_type_t *)arg;
143703831d35Sstevel 
143803831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
143903831d35Sstevel 		    "HPC_CTRL_GET_BOARD_TYPE");
144003831d35Sstevel 
144103831d35Sstevel 		/*
144203831d35Sstevel 		 * The HPC driver does not know what board type
144303831d35Sstevel 		 * is plugged in.
144403831d35Sstevel 		 */
144503831d35Sstevel 		*hpc_board_type = HPC_BOARD_CPCI_HS;
144603831d35Sstevel 
144703831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
144803831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
144903831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
145003831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
145103831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
145203831d35Sstevel 
145303831d35Sstevel 		return (0);
145403831d35Sstevel 
145503831d35Sstevel 	}
145603831d35Sstevel 	case HPC_CTRL_DEV_CONFIGURED:
145703831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
145803831d35Sstevel 		    "HPC_CTRL_DEV_CONFIGURED");
145903831d35Sstevel 
146003831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
146103831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
146203831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
146303831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
146403831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
146503831d35Sstevel 
146603831d35Sstevel 		return (0);
146703831d35Sstevel 
146803831d35Sstevel 	case HPC_CTRL_DEV_UNCONFIGURED:
146903831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
147003831d35Sstevel 		    "HPC_CTRL_DEV_UNCONFIGURED");
147103831d35Sstevel 
147203831d35Sstevel 		if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) {
147303831d35Sstevel 			/*
147403831d35Sstevel 			 * When the occupant is unconfigured, power
147503831d35Sstevel 			 * down the slot.
147603831d35Sstevel 			 */
147703831d35Sstevel 			rval = schpc_disconnect((caddr_t)schpc_p,
147803831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
147903831d35Sstevel 			    0, 0);
148003831d35Sstevel 
148103831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
148203831d35Sstevel 			    ~SCHPC_SLOTSTATE_ENUM;
148303831d35Sstevel 		}
148403831d35Sstevel 
148503831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
148603831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
148703831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
148803831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
148903831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
149003831d35Sstevel 
149103831d35Sstevel 		return (0);
149203831d35Sstevel 
149303831d35Sstevel 	case HPC_CTRL_ENABLE_AUTOCFG:
149403831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
149503831d35Sstevel 		    "HPC_CTRL_ENABLE_AUTOCFG");
149603831d35Sstevel 
149703831d35Sstevel 		schpc_p->schpc_slot[slot].state |=
149803831d35Sstevel 		    SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
149903831d35Sstevel 
150003831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
150103831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
150203831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
150303831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
150403831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
150503831d35Sstevel 
150603831d35Sstevel 		return (0);
150703831d35Sstevel 
150803831d35Sstevel 	case HPC_CTRL_DISABLE_AUTOCFG:
150903831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
151003831d35Sstevel 		    "HPC_CTRL_DISABLE_AUTOCFG");
151103831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
151203831d35Sstevel 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
151303831d35Sstevel 
151403831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
151503831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
151603831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
151703831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
151803831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
151903831d35Sstevel 
152003831d35Sstevel 		return (0);
152103831d35Sstevel 
152203831d35Sstevel 	case HPC_CTRL_DISABLE_ENUM:
152303831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
152403831d35Sstevel 		    "HPC_CTRL_DISABLE_ENUM");
152503831d35Sstevel 
152603831d35Sstevel 		setslot.slot_disable_ENUM = PCIMSG_ON;
152703831d35Sstevel 
152803831d35Sstevel 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
152903831d35Sstevel 
153003831d35Sstevel 		if (rval)
153103831d35Sstevel 			rval = HPC_ERR_FAILED;
153203831d35Sstevel 
153303831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
153403831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
153503831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
153603831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
153703831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
153803831d35Sstevel 
153903831d35Sstevel 		return (rval);
154003831d35Sstevel 
154103831d35Sstevel 	case HPC_CTRL_ENABLE_ENUM:
154203831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
154303831d35Sstevel 		    "HPC_CTRL_ENABLE_ENUM");
154403831d35Sstevel 
154503831d35Sstevel 		setslot.slot_enable_ENUM = PCIMSG_ON;
154603831d35Sstevel 
154703831d35Sstevel 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
154803831d35Sstevel 
154903831d35Sstevel 		if (rval)
155003831d35Sstevel 			rval = HPC_ERR_FAILED;
155103831d35Sstevel 
155203831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
155303831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
155403831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
155503831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
155603831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
155703831d35Sstevel 
155803831d35Sstevel 		return (rval);
155903831d35Sstevel 
156003831d35Sstevel 	default:
156103831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
156203831d35Sstevel 		    "****NOT SUPPORTED CONTROL CMD");
156303831d35Sstevel 
156403831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
156503831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
156603831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
156703831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
156803831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
156903831d35Sstevel 
157003831d35Sstevel 		return (HPC_ERR_NOTSUPPORTED);
157103831d35Sstevel 	}
157203831d35Sstevel }
157303831d35Sstevel 
157403831d35Sstevel /*
157503831d35Sstevel  * schpc_pci_control
157603831d35Sstevel  *
157703831d35Sstevel  * Called by Hot Plug Services to perform a attachment point specific
157803831d35Sstevel  * on a Hot Pluggable Standard PCI Slot.
157903831d35Sstevel  */
158003831d35Sstevel /*ARGSUSED*/
158103831d35Sstevel static int
schpc_pci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)158203831d35Sstevel schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
158303831d35Sstevel     caddr_t arg)
158403831d35Sstevel {
158503831d35Sstevel 	int		rval;
158603831d35Sstevel 	int		expander, board, slot;
158703831d35Sstevel 	pci_setslot_t	setslot;
158803831d35Sstevel 	pci_getslot_t   slotstatus;
158903831d35Sstevel 	hpc_led_info_t	*hpc_led_info;
159003831d35Sstevel 
159103831d35Sstevel 	SCHPC_DEBUG3(D_IOC_CONTROL,
159203831d35Sstevel 	    "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)",
1593*07d06da5SSurya Prakki 	    (void *)ops_arg, (void *)slot_hdl, request);
159403831d35Sstevel 
159503831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
159603831d35Sstevel 
159703831d35Sstevel 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
159803831d35Sstevel 
159903831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
160003831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONNECT,
160103831d35Sstevel 		    "schpc_disconnect - HPC Not Inited");
160203831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
160303831d35Sstevel 		return (HPC_ERR_FAILED);
160403831d35Sstevel 	}
160503831d35Sstevel 
160603831d35Sstevel 	/*
160703831d35Sstevel 	 * Block if another thread is executing a HPC command.
160803831d35Sstevel 	 */
160903831d35Sstevel 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
161003831d35Sstevel 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
161103831d35Sstevel 	}
161203831d35Sstevel 
161303831d35Sstevel 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
161403831d35Sstevel 
161503831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
161603831d35Sstevel 
161703831d35Sstevel 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
161803831d35Sstevel 	board = schpc_p->schpc_slot[slot].board; /* get board */
161903831d35Sstevel 
162003831d35Sstevel 	/*
162103831d35Sstevel 	 * Initialize Set Slot Command.
162203831d35Sstevel 	 */
162303831d35Sstevel 	schpc_init_setslot_message(&setslot);
162403831d35Sstevel 
162503831d35Sstevel 	/*
162603831d35Sstevel 	 * Initialize LED to last know state.
162703831d35Sstevel 	 */
162803831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_power) {
162903831d35Sstevel 	case LED_ON:
163003831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_ON;
163103831d35Sstevel 		break;
163203831d35Sstevel 	case LED_OFF:
163303831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_OFF;
163403831d35Sstevel 		break;
163503831d35Sstevel 	case LED_FLASH:
163603831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_FLASH;
163703831d35Sstevel 		break;
163803831d35Sstevel 	}
163903831d35Sstevel 
164003831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_service) {
164103831d35Sstevel 	case LED_ON:
164203831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_ON;
164303831d35Sstevel 		break;
164403831d35Sstevel 	case LED_OFF:
164503831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_OFF;
164603831d35Sstevel 		break;
164703831d35Sstevel 	case LED_FLASH:
164803831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_FLASH;
164903831d35Sstevel 		break;
165003831d35Sstevel 	}
165103831d35Sstevel 
165203831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
165303831d35Sstevel 	case LED_ON:
165403831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_ON;
165503831d35Sstevel 		break;
165603831d35Sstevel 	case LED_OFF:
165703831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_OFF;
165803831d35Sstevel 		break;
165903831d35Sstevel 	case LED_FLASH:
166003831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
166103831d35Sstevel 		break;
166203831d35Sstevel 	}
166303831d35Sstevel 
166403831d35Sstevel 	switch (request) {
166503831d35Sstevel 
166603831d35Sstevel 
166703831d35Sstevel 	case HPC_CTRL_GET_SLOT_STATE: {
166803831d35Sstevel 		hpc_slot_state_t	*hpc_slot_state;
166903831d35Sstevel 
167003831d35Sstevel 		hpc_slot_state = (hpc_slot_state_t *)arg;
167103831d35Sstevel 
167203831d35Sstevel 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
167303831d35Sstevel 		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1674*07d06da5SSurya Prakki 		    (void *)hpc_slot_state);
167503831d35Sstevel 
167603831d35Sstevel 		rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
167703831d35Sstevel 
167803831d35Sstevel 		if (!rval) {
167903831d35Sstevel 
168003831d35Sstevel 			if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
168103831d35Sstevel 
168203831d35Sstevel 				mutex_enter(&schpc_p->schpc_mutex);
168303831d35Sstevel 				schpc_p->schpc_slot[slot].state &=
168403831d35Sstevel 				    ~SCHPC_SLOTSTATE_EXECUTING;
168503831d35Sstevel 				cv_signal(&schpc_p->schpc_cv);
168603831d35Sstevel 				mutex_exit(&schpc_p->schpc_mutex);
168703831d35Sstevel 
168803831d35Sstevel 				return (HPC_ERR_FAILED);
168903831d35Sstevel 			}
169003831d35Sstevel 
169103831d35Sstevel 			if (slotstatus.slot_empty == PCIMSG_ON) {
169203831d35Sstevel 				*hpc_slot_state = HPC_SLOT_EMPTY;
169303831d35Sstevel 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
169403831d35Sstevel 			} else if (slotstatus.slot_power_on == PCIMSG_ON) {
169503831d35Sstevel 				*hpc_slot_state = HPC_SLOT_CONNECTED;
169603831d35Sstevel 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
169703831d35Sstevel 				schpc_p->schpc_slot[slot].state |=
169803831d35Sstevel 				    SCHPC_SLOTSTATE_CONNECTED;
169903831d35Sstevel 			} else {
170003831d35Sstevel 				*hpc_slot_state = HPC_SLOT_DISCONNECTED;
170103831d35Sstevel 				SCHPC_DEBUG0(D_IOC_CONTROL,
170203831d35Sstevel 				    "Slot Disconnected");
170303831d35Sstevel 				schpc_p->schpc_slot[slot].state &=
170403831d35Sstevel 				    ~SCHPC_SLOTSTATE_CONNECTED;
170503831d35Sstevel 			}
170603831d35Sstevel 		} else {
170703831d35Sstevel 			SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
170803831d35Sstevel 
170903831d35Sstevel 			mutex_enter(&schpc_p->schpc_mutex);
171003831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
171103831d35Sstevel 			    ~SCHPC_SLOTSTATE_EXECUTING;
171203831d35Sstevel 			cv_signal(&schpc_p->schpc_cv);
171303831d35Sstevel 			mutex_exit(&schpc_p->schpc_mutex);
171403831d35Sstevel 
171503831d35Sstevel 			return (HPC_ERR_FAILED);
171603831d35Sstevel 		}
171703831d35Sstevel 
171803831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
171903831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
172003831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
172103831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
172203831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
172303831d35Sstevel 
172403831d35Sstevel 		return (0);
172503831d35Sstevel 	}
172603831d35Sstevel 	case HPC_CTRL_GET_BOARD_TYPE: {
172703831d35Sstevel 		hpc_board_type_t	*hpc_board_type;
172803831d35Sstevel 
172903831d35Sstevel 		hpc_board_type = (hpc_board_type_t *)arg;
173003831d35Sstevel 
173103831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
173203831d35Sstevel 		    "HPC_CTRL_GET_BOARD_TYPE");
173303831d35Sstevel 
173403831d35Sstevel 
173503831d35Sstevel 		/*
173603831d35Sstevel 		 * The HPC driver does not know what board type
173703831d35Sstevel 		 * is plugged in.
173803831d35Sstevel 		 */
173903831d35Sstevel 		*hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
174003831d35Sstevel 
174103831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
174203831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
174303831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
174403831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
174503831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
174603831d35Sstevel 
174703831d35Sstevel 		return (0);
174803831d35Sstevel 
174903831d35Sstevel 	}
175003831d35Sstevel 	case HPC_CTRL_DEV_UNCONFIG_START:
175103831d35Sstevel 	case HPC_CTRL_DEV_CONFIG_START:
175203831d35Sstevel 	case HPC_CTRL_DEV_CONFIGURED:
175303831d35Sstevel 	case HPC_CTRL_DEV_UNCONFIGURED:
175403831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
175503831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
175603831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
175703831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
175803831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
175903831d35Sstevel 
176003831d35Sstevel 		return (0);
176103831d35Sstevel 
176203831d35Sstevel 	case HPC_CTRL_GET_LED_STATE:
176303831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
176403831d35Sstevel 		    "HPC_CTRL_GET_LED_STATE");
176503831d35Sstevel 		hpc_led_info = (hpc_led_info_t *)arg;
176603831d35Sstevel 
176703831d35Sstevel 		switch (hpc_led_info->led) {
176803831d35Sstevel 		case HPC_FAULT_LED:
176903831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
177003831d35Sstevel 			case LED_OFF:
177103831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
177203831d35Sstevel 				break;
177303831d35Sstevel 			case LED_ON:
177403831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
177503831d35Sstevel 				break;
177603831d35Sstevel 			case LED_FLASH:
177703831d35Sstevel 				hpc_led_info->state = HPC_LED_BLINK;
177803831d35Sstevel 				break;
177903831d35Sstevel 			}
178003831d35Sstevel 			break;
178103831d35Sstevel 
178203831d35Sstevel 		case HPC_POWER_LED:
178303831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_power) {
178403831d35Sstevel 			case LED_OFF:
178503831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
178603831d35Sstevel 				break;
178703831d35Sstevel 			case LED_ON:
178803831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
178903831d35Sstevel 				break;
179003831d35Sstevel 			case LED_FLASH:
179103831d35Sstevel 				hpc_led_info->state = HPC_LED_BLINK;
179203831d35Sstevel 				break;
179303831d35Sstevel 			}
179403831d35Sstevel 			break;
179503831d35Sstevel 		case HPC_ATTN_LED:
179603831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
179703831d35Sstevel 			case LED_OFF:
179803831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
179903831d35Sstevel 				break;
180003831d35Sstevel 			case LED_ON:
180103831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
180203831d35Sstevel 				break;
180303831d35Sstevel 			case LED_FLASH:
180403831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
180503831d35Sstevel 				break;
180603831d35Sstevel 			}
180703831d35Sstevel 			break;
180803831d35Sstevel 		case HPC_ACTIVE_LED:
180903831d35Sstevel 			switch (schpc_p->schpc_slot[slot].led.led_service) {
181003831d35Sstevel 			case LED_OFF:
181103831d35Sstevel 				hpc_led_info->state = HPC_LED_OFF;
181203831d35Sstevel 				break;
181303831d35Sstevel 			case LED_ON:
181403831d35Sstevel 				hpc_led_info->state = HPC_LED_ON;
181503831d35Sstevel 				break;
181603831d35Sstevel 			case LED_FLASH:
181703831d35Sstevel 				hpc_led_info->state = HPC_LED_BLINK;
181803831d35Sstevel 				break;
181903831d35Sstevel 			}
182003831d35Sstevel 			break;
182103831d35Sstevel 		default:
182203831d35Sstevel 			SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
182303831d35Sstevel 			    "Invalid LED %x", hpc_led_info->led);
182403831d35Sstevel 
182503831d35Sstevel 			mutex_enter(&schpc_p->schpc_mutex);
182603831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
182703831d35Sstevel 			    ~SCHPC_SLOTSTATE_EXECUTING;
182803831d35Sstevel 			cv_signal(&schpc_p->schpc_cv);
182903831d35Sstevel 			mutex_exit(&schpc_p->schpc_mutex);
183003831d35Sstevel 
183103831d35Sstevel 			return (HPC_ERR_FAILED);
183203831d35Sstevel 		}
183303831d35Sstevel 
183403831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
183503831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
183603831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
183703831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
183803831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
183903831d35Sstevel 
184003831d35Sstevel 		return (0);
184103831d35Sstevel 
184203831d35Sstevel 	case HPC_CTRL_SET_LED_STATE:
184303831d35Sstevel 		hpc_led_info = (hpc_led_info_t *)arg;
184403831d35Sstevel 
184503831d35Sstevel 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1846*07d06da5SSurya Prakki 		    "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1847*07d06da5SSurya Prakki 		    (void *)hpc_led_info);
184803831d35Sstevel 
184903831d35Sstevel 		switch (hpc_led_info->led) {
185003831d35Sstevel 		case HPC_FAULT_LED:
185103831d35Sstevel 			switch (hpc_led_info->state) {
185203831d35Sstevel 			case HPC_LED_OFF:
185303831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
185403831d35Sstevel 				    LED_OFF;
185503831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_OFF;
185603831d35Sstevel 				break;
185703831d35Sstevel 			case HPC_LED_ON:
185803831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
185903831d35Sstevel 				    LED_ON;
186003831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_ON;
186103831d35Sstevel 				break;
186203831d35Sstevel 			case HPC_LED_BLINK:
186303831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
186403831d35Sstevel 				    LED_FLASH;
186503831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
186603831d35Sstevel 				break;
186703831d35Sstevel 			}
186803831d35Sstevel 			break;
186903831d35Sstevel 		case HPC_POWER_LED:
187003831d35Sstevel 			switch (hpc_led_info->state) {
187103831d35Sstevel 			case HPC_LED_OFF:
187203831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_power =
187303831d35Sstevel 				    LED_OFF;
187403831d35Sstevel 				setslot.slot_led_power = PCIMSG_LED_OFF;
187503831d35Sstevel 				break;
187603831d35Sstevel 			case HPC_LED_ON:
187703831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_power =
187803831d35Sstevel 				    LED_ON;
187903831d35Sstevel 				setslot.slot_led_power = PCIMSG_LED_ON;
188003831d35Sstevel 				break;
188103831d35Sstevel 			case HPC_LED_BLINK:
188203831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_power =
188303831d35Sstevel 				    LED_FLASH;
188403831d35Sstevel 				setslot.slot_led_power = PCIMSG_LED_FLASH;
188503831d35Sstevel 				break;
188603831d35Sstevel 			}
188703831d35Sstevel 			break;
188803831d35Sstevel 		case HPC_ATTN_LED:
188903831d35Sstevel 			switch (hpc_led_info->state) {
189003831d35Sstevel 			case HPC_LED_OFF:
189103831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
189203831d35Sstevel 				    LED_OFF;
189303831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_OFF;
189403831d35Sstevel 				break;
189503831d35Sstevel 			case HPC_LED_ON:
189603831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
189703831d35Sstevel 				    LED_FLASH;
189803831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
189903831d35Sstevel 				break;
190003831d35Sstevel 			case HPC_LED_BLINK:
190103831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_fault =
190203831d35Sstevel 				    LED_FLASH;
190303831d35Sstevel 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
190403831d35Sstevel 				break;
190503831d35Sstevel 			}
190603831d35Sstevel 			break;
190703831d35Sstevel 		case HPC_ACTIVE_LED:
190803831d35Sstevel 			switch (hpc_led_info->state) {
190903831d35Sstevel 			case HPC_LED_OFF:
191003831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_service =
191103831d35Sstevel 				    LED_OFF;
191203831d35Sstevel 				setslot.slot_led_service = PCIMSG_LED_OFF;
191303831d35Sstevel 				break;
191403831d35Sstevel 			case HPC_LED_ON:
191503831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_service =
191603831d35Sstevel 				    LED_ON;
191703831d35Sstevel 				setslot.slot_led_service = PCIMSG_LED_ON;
191803831d35Sstevel 				break;
191903831d35Sstevel 			case HPC_LED_BLINK:
192003831d35Sstevel 				schpc_p->schpc_slot[slot].led.led_service =
192103831d35Sstevel 				    LED_FLASH;
192203831d35Sstevel 				setslot.slot_led_service = PCIMSG_LED_FLASH;
192303831d35Sstevel 				break;
192403831d35Sstevel 			}
192503831d35Sstevel 			break;
192603831d35Sstevel 		default:
192703831d35Sstevel 			mutex_enter(&schpc_p->schpc_mutex);
192803831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
192903831d35Sstevel 			    ~SCHPC_SLOTSTATE_EXECUTING;
193003831d35Sstevel 			cv_signal(&schpc_p->schpc_cv);
193103831d35Sstevel 			mutex_exit(&schpc_p->schpc_mutex);
193203831d35Sstevel 
193303831d35Sstevel 			return (0);
193403831d35Sstevel 		}
193503831d35Sstevel 
193603831d35Sstevel 		(void) schpc_setslotstatus(expander, board, slot, &setslot);
193703831d35Sstevel 
193803831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
193903831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
194003831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
194103831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
194203831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
194303831d35Sstevel 
194403831d35Sstevel 		return (0);
194503831d35Sstevel 
194603831d35Sstevel 	case HPC_CTRL_ENABLE_AUTOCFG:
194703831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
194803831d35Sstevel 		    "HPC_CTRL_ENABLE_AUTOCFG");
194903831d35Sstevel 
195003831d35Sstevel 		schpc_p->schpc_slot[slot].state |=
195103831d35Sstevel 		    SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
195203831d35Sstevel 
195303831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
195403831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
195503831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
195603831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
195703831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
195803831d35Sstevel 
195903831d35Sstevel 		return (0);
196003831d35Sstevel 
196103831d35Sstevel 	case HPC_CTRL_DISABLE_AUTOCFG:
196203831d35Sstevel 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
196303831d35Sstevel 		    "HPC_CTRL_DISABLE_AUTOCFG");
196403831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
196503831d35Sstevel 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
196603831d35Sstevel 
196703831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
196803831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
196903831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
197003831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
197103831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
197203831d35Sstevel 
197303831d35Sstevel 		return (0);
197403831d35Sstevel 
197503831d35Sstevel 	case HPC_CTRL_DISABLE_ENUM:
197603831d35Sstevel 	case HPC_CTRL_ENABLE_ENUM:
197703831d35Sstevel 	default:
197803831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
197903831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
198003831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
198103831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
198203831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
198303831d35Sstevel 
198403831d35Sstevel 		return (HPC_ERR_NOTSUPPORTED);
198503831d35Sstevel 	}
198603831d35Sstevel }
198703831d35Sstevel 
198803831d35Sstevel /*
198903831d35Sstevel  * schpc_test
199003831d35Sstevel  *
199103831d35Sstevel  * Tests the slot.
199203831d35Sstevel  */
199303831d35Sstevel /*ARGSUSED*/
199403831d35Sstevel static void
schpc_test(caddr_t ops_arg,int slot,void * data,uint_t flags)199503831d35Sstevel schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags)
199603831d35Sstevel {
199703831d35Sstevel 	pci_getslot_t	slotstatus;
199803831d35Sstevel 	pci_setslot_t	setslot;
199903831d35Sstevel 	int		expander, board;
200003831d35Sstevel 	int		rval;
200103831d35Sstevel 	int		retry = 1;
200203831d35Sstevel 
200303831d35Sstevel 	SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)",
2004*07d06da5SSurya Prakki 	    (void *)ops_arg, SCHPC_SLOT_NUM(slot));
200503831d35Sstevel 
200603831d35Sstevel 	SCHPC_DEBUG3(D_IOC_TEST,
200703831d35Sstevel 	    "    schpc_test() Expander=%d Board=%d Slot=%d",
200803831d35Sstevel 	    schpc_p->schpc_slot[slot].expander,
200903831d35Sstevel 	    schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot));
201003831d35Sstevel 
201103831d35Sstevel 	expander = schpc_p->schpc_slot[slot].expander;
201203831d35Sstevel 	board = schpc_p->schpc_slot[slot].board;
201303831d35Sstevel 
201403831d35Sstevel restart_test:
201503831d35Sstevel 	/*
201603831d35Sstevel 	 * Initial the slot with its occupant and receptacle in good condition.
201703831d35Sstevel 	 */
201803831d35Sstevel 	schpc_p->schpc_slot[slot].state |=  SCHPC_SLOTSTATE_REC_GOOD;
201903831d35Sstevel 	schpc_p->schpc_slot[slot].state |=  SCHPC_SLOTSTATE_OCC_GOOD;
202003831d35Sstevel 
202103831d35Sstevel 
202203831d35Sstevel 	rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
202303831d35Sstevel 
202403831d35Sstevel 	if (rval) {
202503831d35Sstevel 		/*
202603831d35Sstevel 		 * System Controller/Mailbox failure.
202703831d35Sstevel 		 */
202803831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
202903831d35Sstevel 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
203003831d35Sstevel 		    "Communicate with System Controller", expander, board,
203103831d35Sstevel 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
203203831d35Sstevel 
203303831d35Sstevel 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
203403831d35Sstevel 		return;
203503831d35Sstevel 	}
203603831d35Sstevel 
203703831d35Sstevel 	if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
203803831d35Sstevel 
203903831d35Sstevel 		cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
204003831d35Sstevel 		    "is not hot pluggable\n", expander, board,
204103831d35Sstevel 		    SCHPC_SLOT_NUM(slot));
204203831d35Sstevel 
204303831d35Sstevel 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
204403831d35Sstevel 		return;
204503831d35Sstevel 	}
204603831d35Sstevel 
204703831d35Sstevel 	switch (slotstatus.slot_condition) {
204803831d35Sstevel 	case PCIMSG_SLOTCOND_OCC_FAIL:
204903831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
205003831d35Sstevel 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
205103831d35Sstevel 		    "System Controller/Occupant Failed",
205203831d35Sstevel 		    expander, board, SCHPC_SLOT_NUM(slot),
205303831d35Sstevel 		    schpc_p->schpc_slot[slot].ap_id);
205403831d35Sstevel 
205503831d35Sstevel 		schpc_setslotled(expander, board, slot,
205603831d35Sstevel 		    (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON));
205703831d35Sstevel 
205803831d35Sstevel 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_OCC_GOOD;
205903831d35Sstevel 		return;
206003831d35Sstevel 	case PCIMSG_SLOTCOND_REC_FAIL:
206103831d35Sstevel 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
206203831d35Sstevel 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
206303831d35Sstevel 		    "System Controller/Receptacle Failed",
206403831d35Sstevel 		    expander, board, SCHPC_SLOT_NUM(slot),
206503831d35Sstevel 		    schpc_p->schpc_slot[slot].ap_id);
206603831d35Sstevel 
206703831d35Sstevel 		schpc_setslotled(expander, board, slot,
206803831d35Sstevel 		    (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON));
206903831d35Sstevel 
207003831d35Sstevel 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
207103831d35Sstevel 		return;
207203831d35Sstevel 	}
207303831d35Sstevel 
207403831d35Sstevel 	if (slotstatus.slot_power_on) {
207503831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
207603831d35Sstevel 
207703831d35Sstevel 		if (!slotstatus.slot_HEALTHY) {
207803831d35Sstevel 			/*
207903831d35Sstevel 			 * cPCI Adapter is not asserting HEALTHY#.
208003831d35Sstevel 			 */
208103831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
208203831d35Sstevel 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
208303831d35Sstevel 			    "PCI adapter not HEALTHY", expander, board,
208403831d35Sstevel 			    SCHPC_SLOT_NUM(slot),
208503831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
208603831d35Sstevel 
208703831d35Sstevel 			schpc_setslotled(expander, board, slot,
208803831d35Sstevel 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
208903831d35Sstevel 
209003831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
209103831d35Sstevel 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
209203831d35Sstevel 
209303831d35Sstevel 			return;
209403831d35Sstevel 		}
209503831d35Sstevel 
209603831d35Sstevel 		if (!slotstatus.slot_powergood) {
209703831d35Sstevel 			/*
209803831d35Sstevel 			 * PCI Power Input is not good.
209903831d35Sstevel 			 */
210003831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
210103831d35Sstevel 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
210203831d35Sstevel 			    "System Controller PCI Power Input Not Good",
210303831d35Sstevel 			    expander, board, SCHPC_SLOT_NUM(slot),
210403831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
210503831d35Sstevel 
210603831d35Sstevel 			schpc_setslotled(expander, board, slot,
210703831d35Sstevel 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
210803831d35Sstevel 
210903831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
211003831d35Sstevel 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
211103831d35Sstevel 
211203831d35Sstevel 			return;
211303831d35Sstevel 		}
211403831d35Sstevel 
211503831d35Sstevel 		if (slotstatus.slot_powerfault) {
211603831d35Sstevel 			/*
211703831d35Sstevel 			 * PCI Power Fault.
211803831d35Sstevel 			 */
211903831d35Sstevel 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
212003831d35Sstevel 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
212103831d35Sstevel 			    "System Controller PCI Power Fault",
212203831d35Sstevel 			    expander, board, SCHPC_SLOT_NUM(slot),
212303831d35Sstevel 			    schpc_p->schpc_slot[slot].ap_id);
212403831d35Sstevel 
212503831d35Sstevel 			schpc_setslotled(expander, board, slot,
212603831d35Sstevel 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
212703831d35Sstevel 
212803831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
212903831d35Sstevel 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
213003831d35Sstevel 
213103831d35Sstevel 			return;
213203831d35Sstevel 		}
213303831d35Sstevel 	}
213403831d35Sstevel 
213503831d35Sstevel 	SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0");
213603831d35Sstevel 
213703831d35Sstevel 	/*
213803831d35Sstevel 	 * Is the slot empty?
213903831d35Sstevel 	 */
214003831d35Sstevel 	if (slotstatus.slot_empty) {
214103831d35Sstevel 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty");
214203831d35Sstevel 
214303831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
214403831d35Sstevel 		    ~SCHPC_SLOTSTATE_PRESENT;
214503831d35Sstevel 
214603831d35Sstevel 		if (slotstatus.slot_power_on) {
214703831d35Sstevel 
214803831d35Sstevel 			SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot "
214903831d35Sstevel 			    "is powered ON");
215003831d35Sstevel 
215103831d35Sstevel 			/*
215203831d35Sstevel 			 * Tests will be retried once after powering off
215303831d35Sstevel 			 * an empty slot.
215403831d35Sstevel 			 */
215503831d35Sstevel 			if (retry) {
215603831d35Sstevel 
215703831d35Sstevel 				/*
215803831d35Sstevel 				 * Turn off the slot and restart test.
215903831d35Sstevel 				 */
216003831d35Sstevel 				SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() "
216103831d35Sstevel 				    "Turning Empty Slot OFF");
216203831d35Sstevel 
216303831d35Sstevel 				schpc_init_setslot_message(&setslot);
216403831d35Sstevel 				setslot.slot_power_off = PCIMSG_ON;
216503831d35Sstevel 				(void) schpc_setslotstatus(
216603831d35Sstevel 				    expander, board, slot, &setslot);
216703831d35Sstevel 
216803831d35Sstevel 				retry = 0;
216903831d35Sstevel 
217003831d35Sstevel 				goto restart_test;
217103831d35Sstevel 			}
217203831d35Sstevel 		}
217303831d35Sstevel 	} else {
217403831d35Sstevel 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present");
217503831d35Sstevel 
217603831d35Sstevel 		if (!slotstatus.slot_power_on) {
217703831d35Sstevel 			if (retry) {
217803831d35Sstevel 				/*
217903831d35Sstevel 				 * If there is a cassette present and the
218003831d35Sstevel 				 * power is off, try turning the power on and
218103831d35Sstevel 				 * restart the test. This allows access to
218203831d35Sstevel 				 * the FRUID when an empty cassette is
218303831d35Sstevel 				 * installed.
218403831d35Sstevel 				 */
218503831d35Sstevel 				SCHPC_DEBUG0(D_IOC_TEST,
218603831d35Sstevel 				    "schpc_test() Power On Adapter");
218703831d35Sstevel 				schpc_init_setslot_message(&setslot);
218803831d35Sstevel 				setslot.slot_power_on = PCIMSG_ON;
218903831d35Sstevel 				(void) schpc_setslotstatus(
219003831d35Sstevel 				    expander, board, slot, &setslot);
219103831d35Sstevel 				retry = 0;
219203831d35Sstevel 				goto restart_test;
219303831d35Sstevel 			}
219403831d35Sstevel 		}
219503831d35Sstevel 
219603831d35Sstevel 		schpc_p->schpc_slot[slot].state |=
219703831d35Sstevel 		    SCHPC_SLOTSTATE_PRESENT;
219803831d35Sstevel 	}
219903831d35Sstevel 
220003831d35Sstevel 	/*
220103831d35Sstevel 	 * Is the slot powered up?
220203831d35Sstevel 	 */
220303831d35Sstevel 	schpc_init_setslot_message(&setslot);
220403831d35Sstevel 
220503831d35Sstevel 	if (slotstatus.slot_power_on) {
220603831d35Sstevel 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On");
220703831d35Sstevel 
220803831d35Sstevel 		schpc_p->schpc_slot[slot].state |=
220903831d35Sstevel 		    SCHPC_SLOTSTATE_CONNECTED;
221003831d35Sstevel 
221103831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_ON;
221203831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_OFF;
221303831d35Sstevel 		setslot.slot_enable_ENUM = PCIMSG_ON;
221403831d35Sstevel 		setslot.slot_enable_HEALTHY = PCIMSG_ON;
221503831d35Sstevel 	} else {
221603831d35Sstevel 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off");
221703831d35Sstevel 
221803831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
221903831d35Sstevel 		    ~SCHPC_SLOTSTATE_CONNECTED;
222003831d35Sstevel 
222103831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_OFF;
222203831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_ON;
222303831d35Sstevel 		setslot.slot_disable_ENUM = PCIMSG_ON;
222403831d35Sstevel 		setslot.slot_disable_HEALTHY = PCIMSG_ON;
222503831d35Sstevel 	}
222603831d35Sstevel 
222703831d35Sstevel 	setslot.slot_led_fault = PCIMSG_LED_OFF;
222803831d35Sstevel 
222903831d35Sstevel 	(void) schpc_setslotstatus(expander, board, slot, &setslot);
223003831d35Sstevel 
223103831d35Sstevel 	/*
223203831d35Sstevel 	 * Save LED State.
223303831d35Sstevel 	 */
223403831d35Sstevel 	switch (setslot.slot_led_power) {
223503831d35Sstevel 	case PCIMSG_LED_ON:
223603831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_power = LED_ON;
223703831d35Sstevel 		break;
223803831d35Sstevel 	case PCIMSG_LED_OFF:
223903831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_power = LED_OFF;
224003831d35Sstevel 		break;
224103831d35Sstevel 	case PCIMSG_LED_FLASH:
224203831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_power = LED_FLASH;
224303831d35Sstevel 		break;
224403831d35Sstevel 	}
224503831d35Sstevel 	switch (setslot.slot_led_service) {
224603831d35Sstevel 	case PCIMSG_LED_ON:
224703831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_service = LED_ON;
224803831d35Sstevel 		break;
224903831d35Sstevel 	case PCIMSG_LED_OFF:
225003831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_service = LED_OFF;
225103831d35Sstevel 		break;
225203831d35Sstevel 	case PCIMSG_LED_FLASH:
225303831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_service = LED_FLASH;
225403831d35Sstevel 		break;
225503831d35Sstevel 	}
225603831d35Sstevel 	switch (setslot.slot_led_fault) {
225703831d35Sstevel 	case PCIMSG_LED_ON:
225803831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_fault = LED_ON;
225903831d35Sstevel 		break;
226003831d35Sstevel 	case PCIMSG_LED_OFF:
226103831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_fault = LED_OFF;
226203831d35Sstevel 		break;
226303831d35Sstevel 	case PCIMSG_LED_FLASH:
226403831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH;
226503831d35Sstevel 		break;
226603831d35Sstevel 	}
226703831d35Sstevel }
226803831d35Sstevel 
226903831d35Sstevel 
227003831d35Sstevel /*
227103831d35Sstevel  * schpc_event_handler
227203831d35Sstevel  *
227303831d35Sstevel  * Placed on the schpc_event_taskq by schpc_event_filter when an
227403831d35Sstevel  * unsolicited MBOXSC_MSG_EVENT is received from the SC.  It handles
227503831d35Sstevel  * things like power insertion/removal, ENUM#, etc.
227603831d35Sstevel  */
227703831d35Sstevel static void
schpc_event_handler(void * arg)227803831d35Sstevel schpc_event_handler(void *arg)
227903831d35Sstevel {
228003831d35Sstevel 	pci_getslot_t	slotstatus;
228103831d35Sstevel 	uint8_t		expander, board, slot;
228203831d35Sstevel 	int		rval;
228303831d35Sstevel 	pcimsg_t *event = (pcimsg_t *)arg;
228403831d35Sstevel 
228503831d35Sstevel 	/*
228603831d35Sstevel 	 * OK, we got an event message. Since the event message only tells
228703831d35Sstevel 	 * us something has changed and not changed to what, we need to get
228803831d35Sstevel 	 * the current slot status to find how WHAT was change to WHAT.
228903831d35Sstevel 	 */
229003831d35Sstevel 
229103831d35Sstevel 	slot = event->pcimsg_slot;
229203831d35Sstevel 	expander = event->pcimsg_node; /* get expander */
229303831d35Sstevel 	board = event->pcimsg_board; /* get board */
229403831d35Sstevel 
229503831d35Sstevel 	SCHPC_DEBUG3(D_EVENT,
229603831d35Sstevel 	    "schpc_event_handler() - exp=%d board=%d slot=%d",
229703831d35Sstevel 	    expander, board, slot);
229803831d35Sstevel 
229903831d35Sstevel 	/* create a slot table index */
230003831d35Sstevel 	slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot);
230103831d35Sstevel 
230203831d35Sstevel 	SCHPC_DEBUG1(D_EVENT,
230303831d35Sstevel 	    "schpc_event_handler() - expanded slot %d", slot);
230403831d35Sstevel 
230503831d35Sstevel 	if (schpc_p == NULL) {
230603831d35Sstevel 		cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc");
230703831d35Sstevel 		kmem_free(event, sizeof (pcimsg_t));
230803831d35Sstevel 		return;
230903831d35Sstevel 	}
231003831d35Sstevel 
231103831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
231203831d35Sstevel 
231303831d35Sstevel 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
231403831d35Sstevel 		SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited");
231503831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
231603831d35Sstevel 		kmem_free(event, sizeof (pcimsg_t));
231703831d35Sstevel 		return;
231803831d35Sstevel 	}
231903831d35Sstevel 	/*
232003831d35Sstevel 	 * Block if another thread is executing a HPC command.
232103831d35Sstevel 	 */
232203831d35Sstevel 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
232303831d35Sstevel 		SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy");
232403831d35Sstevel 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
232503831d35Sstevel 	}
232603831d35Sstevel 
232703831d35Sstevel 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
232803831d35Sstevel 
232903831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
233003831d35Sstevel 
233103831d35Sstevel 	rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
233203831d35Sstevel 
233303831d35Sstevel 	if (rval) {
233403831d35Sstevel 		cmn_err(CE_WARN, "schpc/Event Handler - Can not get status "
233503831d35Sstevel 		    "for expander=%d board=%d slot=%d\n",
233603831d35Sstevel 		    expander, board, SCHPC_SLOT_NUM(slot));
233703831d35Sstevel 
233803831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
233903831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
234003831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
234103831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
234203831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
234303831d35Sstevel 		kmem_free(event, sizeof (pcimsg_t));
234403831d35Sstevel 		return;
234503831d35Sstevel 	}
234603831d35Sstevel 
234703831d35Sstevel 	if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
234803831d35Sstevel 		cmn_err(CE_WARN, "schpc/Event Handler - Can not get good "
234903831d35Sstevel 		    "status for expander=%d board=%d slot=%d\n",
235003831d35Sstevel 		    expander, board, SCHPC_SLOT_NUM(slot));
235103831d35Sstevel 
235203831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
235303831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
235403831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
235503831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
235603831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
235703831d35Sstevel 
235803831d35Sstevel 		kmem_free(event, sizeof (pcimsg_t));
235903831d35Sstevel 		return;
236003831d35Sstevel 	}
236103831d35Sstevel 
236203831d35Sstevel 	SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d",
236303831d35Sstevel 	    expander, board, SCHPC_SLOT_NUM(slot));
236403831d35Sstevel 
236503831d35Sstevel 	if (schpc_p->schpc_slot[slot].slot_ops == NULL) {
236603831d35Sstevel 		SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event "
236703831d35Sstevel 		    "for unregistered slot for expander=%d board=%d slot=%d",
236803831d35Sstevel 		    expander, board, SCHPC_SLOT_NUM(slot));
236903831d35Sstevel 
237003831d35Sstevel 		mutex_enter(&schpc_p->schpc_mutex);
237103831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
237203831d35Sstevel 		    ~SCHPC_SLOTSTATE_EXECUTING;
237303831d35Sstevel 		cv_signal(&schpc_p->schpc_cv);
237403831d35Sstevel 		mutex_exit(&schpc_p->schpc_mutex);
237503831d35Sstevel 
237603831d35Sstevel 		kmem_free(event, sizeof (pcimsg_t));
237703831d35Sstevel 		return;
237803831d35Sstevel 	}
237903831d35Sstevel 
238003831d35Sstevel 	/* Slot Power Event */
238103831d35Sstevel 
238203831d35Sstevel 	if (event->pcimsg_type.pcimsg_slotevent.slot_power) {
238303831d35Sstevel 		SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event");
238403831d35Sstevel 		/*
238503831d35Sstevel 		 * The SC may have changed to slot power status.
238603831d35Sstevel 		 */
238703831d35Sstevel 		if (slotstatus.slot_power_on) {
238803831d35Sstevel 			schpc_p->schpc_slot[slot].state |=
238903831d35Sstevel 			    SCHPC_SLOTSTATE_CONNECTED;
239003831d35Sstevel 
2391*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
239203831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
239303831d35Sstevel 			    HPC_EVENT_SLOT_POWER_ON, 0);
239403831d35Sstevel 		} else {
239503831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
239603831d35Sstevel 			    ~SCHPC_SLOTSTATE_CONNECTED;
239703831d35Sstevel 
2398*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
239903831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
240003831d35Sstevel 			    HPC_EVENT_SLOT_POWER_OFF, 0);
240103831d35Sstevel 		}
240203831d35Sstevel 	}
240303831d35Sstevel 
240403831d35Sstevel 	/* Adapter Insertion/Removal Event */
240503831d35Sstevel 
240603831d35Sstevel 	if (event->pcimsg_type.pcimsg_slotevent.slot_presence) {
240703831d35Sstevel 		if (slotstatus.slot_empty == PCIMSG_ON) {
240803831d35Sstevel 
240903831d35Sstevel 			/* Adapter Removed */
241003831d35Sstevel 
241103831d35Sstevel 			SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed");
241203831d35Sstevel 
241303831d35Sstevel 			if (schpc_p->schpc_slot[slot].state &
241403831d35Sstevel 			    SCHPC_SLOTSTATE_CONNECTED) {
241503831d35Sstevel 				/*
241603831d35Sstevel 				 * If the adapter has been removed while
241703831d35Sstevel 				 * there the slot is connected, it could be
241803831d35Sstevel 				 * due to a ENUM handling.
241903831d35Sstevel 				 */
242003831d35Sstevel 				cmn_err(CE_WARN, "Card removed from "
242103831d35Sstevel 				    "powered on slot at "
242203831d35Sstevel 				    "expander=%d board=%d slot=%d\n",
242303831d35Sstevel 				    expander, board, SCHPC_SLOT_NUM(slot));
242403831d35Sstevel 
242503831d35Sstevel 				schpc_p->schpc_slot[slot].state &=
242603831d35Sstevel 				    ~SCHPC_SLOTSTATE_EXECUTING;
242703831d35Sstevel 				rval = schpc_disconnect((caddr_t)schpc_p,
242803831d35Sstevel 				    schpc_p->schpc_slot[slot].slot_handle,
242903831d35Sstevel 				    0, 0);
243003831d35Sstevel 				mutex_enter(&schpc_p->schpc_mutex);
243103831d35Sstevel 				while (schpc_p->schpc_slot[slot].state &
243203831d35Sstevel 				    SCHPC_SLOTSTATE_EXECUTING) {
243303831d35Sstevel 					SCHPC_DEBUG0(D_EVENT,
243403831d35Sstevel 					    "schpc_event_handler - "
243503831d35Sstevel 					    "Slot is busy");
243603831d35Sstevel 					cv_wait(&schpc_p->schpc_cv,
243703831d35Sstevel 					    &schpc_p->schpc_mutex);
243803831d35Sstevel 				}
243903831d35Sstevel 
244003831d35Sstevel 				schpc_p->schpc_slot[slot].state |=
244103831d35Sstevel 				    SCHPC_SLOTSTATE_EXECUTING;
244203831d35Sstevel 
244303831d35Sstevel 				mutex_exit(&schpc_p->schpc_mutex);
244403831d35Sstevel 			}
244503831d35Sstevel 			schpc_p->schpc_slot[slot].state |=
244603831d35Sstevel 			    SCHPC_SLOTSTATE_OCC_GOOD;
244703831d35Sstevel 
244803831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
244903831d35Sstevel 			    ~SCHPC_SLOTSTATE_PRESENT;
245003831d35Sstevel 
2451*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
245203831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
245303831d35Sstevel 			    HPC_EVENT_SLOT_REMOVAL, 0);
245403831d35Sstevel 		} else {
245503831d35Sstevel 
245603831d35Sstevel 			/* Adapter Inserted */
245703831d35Sstevel 
245803831d35Sstevel 			SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted");
245903831d35Sstevel 
246003831d35Sstevel 			if (schpc_p->schpc_slot[slot].state &
246103831d35Sstevel 			    SCHPC_SLOTSTATE_PRESENT) {
246203831d35Sstevel 				/*
246303831d35Sstevel 				 * If the adapter is already present
246403831d35Sstevel 				 * throw the this event away.
246503831d35Sstevel 				 */
246603831d35Sstevel 
246703831d35Sstevel 				SCHPC_DEBUG0(D_EVENT,
246803831d35Sstevel 				    "Adapter is already present");
246903831d35Sstevel 
247003831d35Sstevel 				mutex_enter(&schpc_p->schpc_mutex);
247103831d35Sstevel 				schpc_p->schpc_slot[slot].state &=
247203831d35Sstevel 				    ~SCHPC_SLOTSTATE_EXECUTING;
247303831d35Sstevel 				cv_signal(&schpc_p->schpc_cv);
247403831d35Sstevel 				mutex_exit(&schpc_p->schpc_mutex);
247503831d35Sstevel 
247603831d35Sstevel 				kmem_free(event, sizeof (pcimsg_t));
247703831d35Sstevel 				return;
247803831d35Sstevel 			}
247903831d35Sstevel 
248003831d35Sstevel 			schpc_p->schpc_slot[slot].state |=
248103831d35Sstevel 			    SCHPC_SLOTSTATE_PRESENT;
248203831d35Sstevel 
248303831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
248403831d35Sstevel 			    ~SCHPC_SLOTSTATE_CONNECTED;
248503831d35Sstevel 
2486*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
248703831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
248803831d35Sstevel 			    HPC_EVENT_SLOT_INSERTION, 0);
248903831d35Sstevel 
249003831d35Sstevel 			if (schpc_p->schpc_slot[slot].state &
249103831d35Sstevel 			    SCHPC_SLOTSTATE_AUTOCFG_ENABLE) {
249203831d35Sstevel 				SCHPC_DEBUG0(D_EVENT, "Auto Configuration "
249303831d35Sstevel 				    "(Connect/Configure) Started");
249403831d35Sstevel 
249503831d35Sstevel 				schpc_p->schpc_slot[slot].state &=
249603831d35Sstevel 				    ~SCHPC_SLOTSTATE_EXECUTING;
249703831d35Sstevel 
249803831d35Sstevel 				rval = schpc_connect((caddr_t)schpc_p,
249903831d35Sstevel 				    schpc_p->schpc_slot[slot].slot_handle,
250003831d35Sstevel 				    0, 0);
250103831d35Sstevel 
250203831d35Sstevel 				if (rval) {
250303831d35Sstevel 					cmn_err(CE_WARN, "schpc/Event Handler -"
250403831d35Sstevel 					    " Can not connect");
250503831d35Sstevel 
250603831d35Sstevel 					mutex_enter(&schpc_p->schpc_mutex);
250703831d35Sstevel 					schpc_p->schpc_slot[slot].state &=
250803831d35Sstevel 					    ~SCHPC_SLOTSTATE_EXECUTING;
250903831d35Sstevel 					cv_signal(&schpc_p->schpc_cv);
251003831d35Sstevel 					mutex_exit(&schpc_p->schpc_mutex);
251103831d35Sstevel 
251203831d35Sstevel 					kmem_free(event, sizeof (pcimsg_t));
251303831d35Sstevel 					return;
251403831d35Sstevel 				}
251503831d35Sstevel 				mutex_enter(&schpc_p->schpc_mutex);
251603831d35Sstevel 				while (schpc_p->schpc_slot[slot].state &
251703831d35Sstevel 				    SCHPC_SLOTSTATE_EXECUTING) {
251803831d35Sstevel 					SCHPC_DEBUG0(D_EVENT,
251903831d35Sstevel 					    "schpc_event_handler - "
252003831d35Sstevel 					    "Slot is busy");
252103831d35Sstevel 					cv_wait(&schpc_p->schpc_cv,
252203831d35Sstevel 					    &schpc_p->schpc_mutex);
252303831d35Sstevel 				}
252403831d35Sstevel 
252503831d35Sstevel 				schpc_p->schpc_slot[slot].state |=
252603831d35Sstevel 				    SCHPC_SLOTSTATE_EXECUTING;
252703831d35Sstevel 
252803831d35Sstevel 				mutex_exit(&schpc_p->schpc_mutex);
252903831d35Sstevel 
2530*07d06da5SSurya Prakki 				(void) hpc_slot_event_notify(
253103831d35Sstevel 				    schpc_p->schpc_slot[slot].slot_handle,
253203831d35Sstevel 				    HPC_EVENT_SLOT_CONFIGURE, 0);
253303831d35Sstevel 			} else {
253403831d35Sstevel 				schpc_setslotled(expander, board, slot,
253503831d35Sstevel 				    SERVICE_LED_ON);
253603831d35Sstevel 			}
253703831d35Sstevel 		}
253803831d35Sstevel 	}
253903831d35Sstevel 
254003831d35Sstevel 	/* ENUM# signal change event */
254103831d35Sstevel 
254203831d35Sstevel 	if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) {
254303831d35Sstevel 		/*
254403831d35Sstevel 		 * ENUM should only be received to the adapter remove
254503831d35Sstevel 		 * procedure.
254603831d35Sstevel 		 */
254703831d35Sstevel 
254803831d35Sstevel 		SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted");
254903831d35Sstevel 
255003831d35Sstevel 		schpc_setslotled(expander, board, slot, FAULT_LED_FLASH);
255103831d35Sstevel 
255203831d35Sstevel 		schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM;
255303831d35Sstevel 
2554*07d06da5SSurya Prakki 		(void) hpc_slot_event_notify(
255503831d35Sstevel 		    schpc_p->schpc_slot[slot].slot_handle,
255603831d35Sstevel 		    HPC_EVENT_SLOT_ENUM, 0);
255703831d35Sstevel 	}
255803831d35Sstevel 
255903831d35Sstevel 	/* HEALTHY# signal change event */
256003831d35Sstevel 
256103831d35Sstevel 	if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) {
256203831d35Sstevel 
256303831d35Sstevel 		if (!slotstatus.slot_HEALTHY) {
256403831d35Sstevel 
256503831d35Sstevel 			SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED");
256603831d35Sstevel 
256703831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
256803831d35Sstevel 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
256903831d35Sstevel 
2570*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
257103831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
257203831d35Sstevel 			    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
257303831d35Sstevel 
257403831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
257503831d35Sstevel 		} else {
257603831d35Sstevel 			SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK");
257703831d35Sstevel 
257803831d35Sstevel 			schpc_p->schpc_slot[slot].state |=
257903831d35Sstevel 			    SCHPC_SLOTSTATE_OCC_GOOD;
258003831d35Sstevel 
2581*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
258203831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
258303831d35Sstevel 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
258403831d35Sstevel 
258503831d35Sstevel 			schpc_setslotled(expander, board, slot,
258603831d35Sstevel 			    FAULT_LED_OFF);
258703831d35Sstevel 		}
258803831d35Sstevel 	}
258903831d35Sstevel 
259003831d35Sstevel 	/* Good Power change event */
259103831d35Sstevel 
259203831d35Sstevel 	if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) {
259303831d35Sstevel 		if (slotstatus.slot_powergood == PCIMSG_ON) {
259403831d35Sstevel 
259503831d35Sstevel 			SCHPC_DEBUG0(D_EVENT,
259603831d35Sstevel 			    "Event Type: Slot Power Good Detected");
259703831d35Sstevel 
259803831d35Sstevel 			schpc_p->schpc_slot[slot].state |=
259903831d35Sstevel 			    SCHPC_SLOTSTATE_OCC_GOOD;
260003831d35Sstevel 
2601*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
260203831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
260303831d35Sstevel 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
260403831d35Sstevel 
260503831d35Sstevel 			schpc_setslotled(expander, board, slot,
260603831d35Sstevel 			    FAULT_LED_OFF);
260703831d35Sstevel 		} else {
260803831d35Sstevel 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good "
260903831d35Sstevel 			    "Detected");
261003831d35Sstevel 
261103831d35Sstevel 			if (schpc_p->schpc_slot[slot].state &
261203831d35Sstevel 			    SCHPC_SLOTSTATE_CONNECTED) {
261303831d35Sstevel 
261403831d35Sstevel 				SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: "
261503831d35Sstevel 				    "power failed");
261603831d35Sstevel 
261703831d35Sstevel 				schpc_p->schpc_slot[slot].state &=
261803831d35Sstevel 				    ~SCHPC_SLOTSTATE_OCC_GOOD;
261903831d35Sstevel 
2620*07d06da5SSurya Prakki 				(void) hpc_slot_event_notify(
262103831d35Sstevel 				    schpc_p->schpc_slot[slot].slot_handle,
262203831d35Sstevel 				    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
262303831d35Sstevel 
262403831d35Sstevel 				schpc_setslotled(expander, board, slot,
262503831d35Sstevel 				    FAULT_LED_ON);
262603831d35Sstevel 			}
262703831d35Sstevel 		}
262803831d35Sstevel 	}
262903831d35Sstevel 
263003831d35Sstevel 	/* Power Fault change event */
263103831d35Sstevel 
263203831d35Sstevel 	if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) {
263303831d35Sstevel 		if (slotstatus.slot_powerfault == PCIMSG_ON) {
263403831d35Sstevel 
263503831d35Sstevel 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
263603831d35Sstevel 			    "Detected");
263703831d35Sstevel 
263803831d35Sstevel 			schpc_p->schpc_slot[slot].state &=
263903831d35Sstevel 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
264003831d35Sstevel 
2641*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
264203831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
264303831d35Sstevel 			    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
264403831d35Sstevel 
264503831d35Sstevel 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
264603831d35Sstevel 		} else {
264703831d35Sstevel 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
264803831d35Sstevel 			    "Cleared");
264903831d35Sstevel 
265003831d35Sstevel 			schpc_p->schpc_slot[slot].state |=
265103831d35Sstevel 			    SCHPC_SLOTSTATE_OCC_GOOD;
265203831d35Sstevel 
2653*07d06da5SSurya Prakki 			(void) hpc_slot_event_notify(
265403831d35Sstevel 			    schpc_p->schpc_slot[slot].slot_handle,
265503831d35Sstevel 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
265603831d35Sstevel 
265703831d35Sstevel 			schpc_setslotled(expander, board, slot,
265803831d35Sstevel 			    FAULT_LED_OFF);
265903831d35Sstevel 		}
266003831d35Sstevel 	}
266103831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
266203831d35Sstevel 	schpc_p->schpc_slot[slot].state &=
266303831d35Sstevel 	    ~SCHPC_SLOTSTATE_EXECUTING;
266403831d35Sstevel 	cv_signal(&schpc_p->schpc_cv);
266503831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
266603831d35Sstevel 
266703831d35Sstevel 	kmem_free(event, sizeof (pcimsg_t));
266803831d35Sstevel }
266903831d35Sstevel 
267003831d35Sstevel 
267103831d35Sstevel /*
267203831d35Sstevel  * schpc_event_filter
267303831d35Sstevel  *
267403831d35Sstevel  * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the
267503831d35Sstevel  * schpc_event_taskq for processing by the schpc_event_handler _if_
267603831d35Sstevel  * hotpluggable pci slots have been registered; otherwise, the
267703831d35Sstevel  * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox
267803831d35Sstevel  * open for future messages.
267903831d35Sstevel  */
268003831d35Sstevel static void
schpc_event_filter(pcimsg_t * pmsg)268103831d35Sstevel schpc_event_filter(pcimsg_t *pmsg)
268203831d35Sstevel {
268303831d35Sstevel 	if (slots_registered == B_TRUE) {
268403831d35Sstevel 
268503831d35Sstevel 		pcimsg_t *pevent;
268603831d35Sstevel 
268703831d35Sstevel 		/*
268803831d35Sstevel 		 * If hotpluggable pci slots have been registered then enqueue
268903831d35Sstevel 		 * the event onto the schpc_event_taskq for processing.
269003831d35Sstevel 		 */
269103831d35Sstevel 
269203831d35Sstevel 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
269303831d35Sstevel 		    "slots_registered = B_TRUE");
269403831d35Sstevel 
269503831d35Sstevel 		pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP);
269603831d35Sstevel 		bcopy(pmsg, pevent, sizeof (pcimsg_t));
269703831d35Sstevel 
269803831d35Sstevel 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
269903831d35Sstevel 		    "event alloc'd");
270003831d35Sstevel 
270103831d35Sstevel 		if (taskq_dispatch(schpc_event_taskq, schpc_event_handler,
270203831d35Sstevel 		    (void *)pevent, TQ_SLEEP) == NULL) {
270303831d35Sstevel 			cmn_err(CE_WARN, "schpc: schpc_event_filter - "
270403831d35Sstevel 			    "taskq_dispatch failed to enqueue event");
270503831d35Sstevel 			kmem_free(pevent, sizeof (pcimsg_t));
270603831d35Sstevel 			return;
270703831d35Sstevel 		}
270803831d35Sstevel 
270903831d35Sstevel 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
271003831d35Sstevel 		    "event was taskq_dispatch'ed to schpc_event_handler");
271103831d35Sstevel 	} else {
271203831d35Sstevel 		/*
271303831d35Sstevel 		 * Oops, schpc received an event _before_ the slots have been
271403831d35Sstevel 		 * registered. In that case there is no choice but to toss
271503831d35Sstevel 		 * the event.
271603831d35Sstevel 		 */
271703831d35Sstevel 		cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding "
271803831d35Sstevel 		    "premature event");
271903831d35Sstevel 	}
272003831d35Sstevel }
272103831d35Sstevel 
272203831d35Sstevel 
272303831d35Sstevel /*
272403831d35Sstevel  * schpc_msg_thread
272503831d35Sstevel  * A stand-alone thread that monitors the incoming mailbox for
272603831d35Sstevel  * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from
272703831d35Sstevel  * the mailbox for processing.
272803831d35Sstevel  *
272903831d35Sstevel  * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the
273003831d35Sstevel  * schpc_replylist, and the waiting thread is notified that its REPLY
273103831d35Sstevel  * message has arrived; otherwise, if no REPLY match is found, then it is
273203831d35Sstevel  * discarded.
273303831d35Sstevel  *
273403831d35Sstevel  * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed
273503831d35Sstevel  * by the schpc_event_handler.
273603831d35Sstevel  *
273703831d35Sstevel  * The schpc_msg_thread is started in _init().
273803831d35Sstevel  */
273903831d35Sstevel void
schpc_msg_thread(void)274003831d35Sstevel schpc_msg_thread(void)
274103831d35Sstevel {
274203831d35Sstevel 	int			err;
274303831d35Sstevel 	uint32_t		type;
274403831d35Sstevel 	uint32_t		cmd;
274503831d35Sstevel 	uint64_t		transid;
274603831d35Sstevel 	uint32_t		length;
274703831d35Sstevel 	pcimsg_t		msg;
274803831d35Sstevel 
274903831d35Sstevel 	SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running");
275003831d35Sstevel 
275103831d35Sstevel 	/* CONSTCOND */
275203831d35Sstevel 	while (1) {
275303831d35Sstevel 
275403831d35Sstevel 		/* setup wildcard arguments */
275503831d35Sstevel 		type = 0;
275603831d35Sstevel 		cmd = 0;
275703831d35Sstevel 		transid = 0;
275803831d35Sstevel 		length = sizeof (pcimsg_t);
275903831d35Sstevel 		bzero(&msg, sizeof (pcimsg_t));
276003831d35Sstevel 
276103831d35Sstevel 		err = mboxsc_getmsg(KEY_SCPC, &type, &cmd,
276203831d35Sstevel 		    &transid, &length, (void *)&msg,
276303831d35Sstevel 		    schpc_timeout_getmsg);
276403831d35Sstevel 
276503831d35Sstevel 		if (err) {
276603831d35Sstevel 			switch (err) {
276703831d35Sstevel 
276803831d35Sstevel 			/*FALLTHROUGH*/
276903831d35Sstevel 			case ETIMEDOUT:
277003831d35Sstevel 			case EAGAIN:
277103831d35Sstevel 				continue;
277203831d35Sstevel 
277303831d35Sstevel 			default:
277403831d35Sstevel 				/*
277503831d35Sstevel 				 * unfortunately, we can't do very much here
277603831d35Sstevel 				 * because we're wildcarding mboxsc_getmsg
277703831d35Sstevel 				 * so if it encounters an error, we can't
277803831d35Sstevel 				 * identify which transid it belongs to.
277903831d35Sstevel 				 */
278003831d35Sstevel 				cmn_err(CE_WARN,
278103831d35Sstevel 				"schpc - mboxsc_getmsg failed, err=0x%x", err);
278203831d35Sstevel 				delay(drv_usectohz(100000));
278303831d35Sstevel 				continue;
278403831d35Sstevel 			}
278503831d35Sstevel 		}
278603831d35Sstevel 
278703831d35Sstevel 		if (msg.pcimsg_revision != PCIMSG_REVISION) {
278803831d35Sstevel 			/*
278903831d35Sstevel 			 * This version of the schpc driver only understands
279003831d35Sstevel 			 * version 1.0 of the PCI Hot Plug Message format.
279103831d35Sstevel 			 */
279203831d35Sstevel 			cmn_err(CE_WARN, " schpc: schpc_msg_thread - "
279303831d35Sstevel 			    "discarding event w/ unknown message version %x",
279403831d35Sstevel 			    msg.pcimsg_revision);
279503831d35Sstevel 			continue;
279603831d35Sstevel 		}
279703831d35Sstevel 
279803831d35Sstevel 		switch (type) {
279903831d35Sstevel 
280003831d35Sstevel 		case MBOXSC_MSG_EVENT:
280103831d35Sstevel 			schpc_event_filter(&msg);
280203831d35Sstevel 			break;
280303831d35Sstevel 
280403831d35Sstevel 		case MBOXSC_MSG_REPLY:
280503831d35Sstevel 			schpc_reply_handler(&msg, type, cmd, transid, length);
280603831d35Sstevel 			break;
280703831d35Sstevel 
280803831d35Sstevel 		default:
280903831d35Sstevel 			cmn_err(CE_WARN,
281003831d35Sstevel 			    "schpc - mboxsc_getmsg unknown msg"
281103831d35Sstevel 			    " type=0x%x", type);
281203831d35Sstevel 			break;
281303831d35Sstevel 		}
281403831d35Sstevel 	}
281503831d35Sstevel 	/* this thread never exits */
281603831d35Sstevel }
281703831d35Sstevel 
281803831d35Sstevel 
281903831d35Sstevel void
schpc_reply_handler(pcimsg_t * pmsg,uint32_t type,uint32_t cmd,uint64_t transid,uint32_t length)282003831d35Sstevel schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
282103831d35Sstevel 			uint64_t transid, uint32_t length)
282203831d35Sstevel {
282303831d35Sstevel 	schpc_replylist_t	*entry;
282403831d35Sstevel 
282503831d35Sstevel 	mutex_enter(&schpc_replylist_mutex);
282603831d35Sstevel 	entry = schpc_replylist_first;
282703831d35Sstevel 	while (entry != NULL) {
282803831d35Sstevel 		if (entry->transid == transid) {
282903831d35Sstevel 			break;
283003831d35Sstevel 		} else
283103831d35Sstevel 			entry = entry->next;
283203831d35Sstevel 	}
283303831d35Sstevel 	if (entry) {
283403831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
283503831d35Sstevel 		    "schpc_reply_handler() - 0x%lx transid reply "
283603831d35Sstevel 		    "received", transid);
283703831d35Sstevel 
283803831d35Sstevel 		mutex_enter(&entry->reply_lock);
283903831d35Sstevel 		if (entry->reply_cexit == B_FALSE) {
284003831d35Sstevel 			SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
284103831d35Sstevel 			    "schpc_reply_handler() - 0x%lx transid"
284203831d35Sstevel 			    " cv_signal waiting thread", transid);
284303831d35Sstevel 
284403831d35Sstevel 			/*
284503831d35Sstevel 			 * emulate mboxsc_getmsg by copying the reply
284603831d35Sstevel 			 */
284703831d35Sstevel 			entry->type = type;
284803831d35Sstevel 			entry->cmd = cmd;
284903831d35Sstevel 			entry->transid = transid;
285003831d35Sstevel 			entry->length = length;
285103831d35Sstevel 			bcopy((caddr_t)pmsg, &entry->reply, length);
285203831d35Sstevel 
285303831d35Sstevel 			/* reply was received */
285403831d35Sstevel 			entry->reply_recvd = B_TRUE;
285503831d35Sstevel 
285603831d35Sstevel 			/*
285703831d35Sstevel 			 * wake up thread waiting for reply with transid
285803831d35Sstevel 			 */
285903831d35Sstevel 			cv_signal(&entry->reply_cv);
286003831d35Sstevel 		}
286103831d35Sstevel 		mutex_exit(&entry->reply_lock);
286203831d35Sstevel 	} else {
286303831d35Sstevel 		cmn_err(CE_WARN, "schpc - no match for transid 0x%lx",
286403831d35Sstevel 		    transid);
286503831d35Sstevel 	}
286603831d35Sstevel 	mutex_exit(&schpc_replylist_mutex);
286703831d35Sstevel }
286803831d35Sstevel 
286903831d35Sstevel 
287003831d35Sstevel /*
287103831d35Sstevel  * schpc_putrequest
287203831d35Sstevel  *
287303831d35Sstevel  * A wrapper around the synchronous call mboxsc_putmsg().
287403831d35Sstevel  */
287503831d35Sstevel 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)287603831d35Sstevel schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
287703831d35Sstevel 		uint32_t length, void *datap, clock_t timeout,
287803831d35Sstevel 		schpc_replylist_t **entryp)
287903831d35Sstevel {
288003831d35Sstevel 	int rval;
288103831d35Sstevel 
288203831d35Sstevel 	/* add the request to replylist to keep track of outstanding requests */
288303831d35Sstevel 	*entryp = schpc_replylist_link(cmd, *transidp, length);
288403831d35Sstevel 
288503831d35Sstevel 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
288603831d35Sstevel 	    "0x%lx transid mboxsc_putmsg called", *transidp);
288703831d35Sstevel 
288803831d35Sstevel 	/* wait synchronously for request to be sent */
288903831d35Sstevel 	rval = mboxsc_putmsg(key, type, cmd, transidp, length,
289003831d35Sstevel 	    (void *)datap, timeout);
289103831d35Sstevel 
289203831d35Sstevel 	SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
289303831d35Sstevel 	    "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval);
289403831d35Sstevel 
289503831d35Sstevel 	/* if problem is encountered then remove the request from replylist */
289603831d35Sstevel 	if (rval)
289703831d35Sstevel 		schpc_replylist_unlink(*entryp);
289803831d35Sstevel 
289903831d35Sstevel 	return (rval);
290003831d35Sstevel }
290103831d35Sstevel 
290203831d35Sstevel 
290303831d35Sstevel /*
290403831d35Sstevel  * schpc_getreply
290503831d35Sstevel  *
290603831d35Sstevel  * Wait for the schpc_msg_thread to respond that a matching reply has
290703831d35Sstevel  * arrived; otherwise, timeout and remove the entry from the schpc_replylist.
290803831d35Sstevel  */
290903831d35Sstevel /*ARGSUSED*/
291003831d35Sstevel 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)291103831d35Sstevel schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
291203831d35Sstevel 		uint64_t *transidp, uint32_t *lengthp, void *datap,
291303831d35Sstevel 		clock_t timeout, schpc_replylist_t *listp)
291403831d35Sstevel {
291503831d35Sstevel 	int rc = 0;
291603831d35Sstevel 
291703831d35Sstevel 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
291803831d35Sstevel 	    "schpc_getreply() - 0x%lx transid waiting for reply",
291903831d35Sstevel 	    *transidp);
292003831d35Sstevel 
292103831d35Sstevel 	/*
292203831d35Sstevel 	 * wait here until schpc_msg_thread because it's always
292303831d35Sstevel 	 * looking for reply messages
292403831d35Sstevel 	 */
292503831d35Sstevel 	mutex_enter(&listp->reply_lock);
292603831d35Sstevel 
292703831d35Sstevel 	while (listp->reply_recvd == B_FALSE) {
292803831d35Sstevel 		/*
292903831d35Sstevel 		 * wait for reply or timeout
293003831d35Sstevel 		 */
293103831d35Sstevel 		rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock,
293203831d35Sstevel 		    ddi_get_lbolt() + drv_usectohz(timeout * 1000));
293303831d35Sstevel 		switch (rc) {
293403831d35Sstevel 		case -1: /* most likely a timeout, but check anyway */
293503831d35Sstevel 
293603831d35Sstevel 			/* message was received after all */
293703831d35Sstevel 			if (listp->reply_recvd == B_TRUE)
293803831d35Sstevel 				break;
293903831d35Sstevel 
294003831d35Sstevel 			/* no, it's really a timeout */
294103831d35Sstevel 			listp->reply_cexit = B_TRUE;
294203831d35Sstevel 			mutex_exit(&listp->reply_lock);
294303831d35Sstevel 			cmn_err(CE_WARN,
294403831d35Sstevel 			"schpc - 0x%lx transid reply timed out", *transidp);
294503831d35Sstevel 			schpc_replylist_unlink(listp);
294603831d35Sstevel 			return (ETIMEDOUT);
294703831d35Sstevel 
294803831d35Sstevel 		default:
294903831d35Sstevel 			break;
295003831d35Sstevel 		}
295103831d35Sstevel 	}
295203831d35Sstevel 
295303831d35Sstevel 	*typep = listp->type;
295403831d35Sstevel 	*cmdp = listp->cmd;
295503831d35Sstevel 	*transidp = listp->transid;
295603831d35Sstevel 	*lengthp = listp->length;
295703831d35Sstevel 	bcopy((caddr_t)&listp->reply, datap, *lengthp);
295803831d35Sstevel 	mutex_exit(&listp->reply_lock);
295903831d35Sstevel 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
296003831d35Sstevel 	    "schpc_getreply() - 0x%lx transid received", *transidp);
296103831d35Sstevel 	schpc_replylist_unlink(listp);
296203831d35Sstevel 	return (0);
296303831d35Sstevel }
296403831d35Sstevel 
296503831d35Sstevel 
296603831d35Sstevel /*
296703831d35Sstevel  * schpc_replylist_unlink
296803831d35Sstevel  *
296903831d35Sstevel  * Deallocate a schpc_replylist_t element.
297003831d35Sstevel  */
297103831d35Sstevel void
schpc_replylist_unlink(schpc_replylist_t * entry)297203831d35Sstevel schpc_replylist_unlink(schpc_replylist_t *entry)
297303831d35Sstevel {
297403831d35Sstevel #if DEBUG
297503831d35Sstevel 	schpc_replylist_t *dbg_entry;
297603831d35Sstevel #endif	/* DEBUG */
297703831d35Sstevel 
297803831d35Sstevel 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
297903831d35Sstevel 	    "schpc_replylist_unlink() - 0x%lx transid deleted from replylist",
298003831d35Sstevel 	    entry->transid);
298103831d35Sstevel 
298203831d35Sstevel 	mutex_enter(&schpc_replylist_mutex);
298303831d35Sstevel 	if (entry->prev) {
298403831d35Sstevel 		entry->prev->next = entry->next;
298503831d35Sstevel 		if (entry->next)
298603831d35Sstevel 			entry->next->prev = entry->prev;
298703831d35Sstevel 	} else {
298803831d35Sstevel 		schpc_replylist_first = entry->next;
298903831d35Sstevel 		if (entry->next)
299003831d35Sstevel 			entry->next->prev = NULL;
299103831d35Sstevel 	}
299203831d35Sstevel 	if (entry == schpc_replylist_last) {
299303831d35Sstevel 		schpc_replylist_last = entry->prev;
299403831d35Sstevel 	}
299503831d35Sstevel 	kmem_free(entry, sizeof (schpc_replylist_t));
299603831d35Sstevel 	schpc_replylist_count--;
299703831d35Sstevel 
299803831d35Sstevel #if DEBUG
299903831d35Sstevel 	if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
300003831d35Sstevel 		dbg_entry = schpc_replylist_first;
300103831d35Sstevel 		cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist "
300203831d35Sstevel 		    "count = %d\n", schpc_replylist_count);
300303831d35Sstevel 		while (dbg_entry != NULL) {
300403831d35Sstevel 			cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - "
300503831d35Sstevel 			    "0x%lx transid\n", dbg_entry->transid);
300603831d35Sstevel 			dbg_entry = dbg_entry->next;
300703831d35Sstevel 		}
300803831d35Sstevel 	}
300903831d35Sstevel #endif	/* DEBUG  */
301003831d35Sstevel 
301103831d35Sstevel 	mutex_exit(&schpc_replylist_mutex);
301203831d35Sstevel }
301303831d35Sstevel 
301403831d35Sstevel 
301503831d35Sstevel /*
301603831d35Sstevel  * schpc_replylist_link
301703831d35Sstevel  *
301803831d35Sstevel  * Allocate and initialize a schpc_replylist_t element.
301903831d35Sstevel  */
302003831d35Sstevel schpc_replylist_t *
schpc_replylist_link(uint32_t cmd,uint64_t transid,uint32_t length)302103831d35Sstevel schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length)
302203831d35Sstevel {
302303831d35Sstevel 	schpc_replylist_t *entry;
302403831d35Sstevel #if DEBUG
302503831d35Sstevel 	schpc_replylist_t *dbg_entry;
302603831d35Sstevel #endif	/* DEBUG */
302703831d35Sstevel 
302803831d35Sstevel 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
302903831d35Sstevel 	    "schpc_replylist_link() - 0x%lx transid inserting into replylist",
303003831d35Sstevel 	    transid);
303103831d35Sstevel 
303203831d35Sstevel 	entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP);
303303831d35Sstevel 	mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL);
303403831d35Sstevel 	cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL);
303503831d35Sstevel 	entry->type = MBOXSC_MSG_REPLY;
303603831d35Sstevel 	entry->cmd  = cmd;
303703831d35Sstevel 	entry->transid  = transid;
303803831d35Sstevel 	entry->length  = length;
303903831d35Sstevel 	entry->reply_recvd = B_FALSE;
304003831d35Sstevel 	entry->reply_cexit = B_FALSE;
304103831d35Sstevel 
304203831d35Sstevel 	mutex_enter(&schpc_replylist_mutex);
304303831d35Sstevel 	if (schpc_replylist_last) {
304403831d35Sstevel 		entry->prev = schpc_replylist_last;
304503831d35Sstevel 		schpc_replylist_last->next = entry;
304603831d35Sstevel 		schpc_replylist_last = entry;
304703831d35Sstevel 	} else {
304803831d35Sstevel 		schpc_replylist_last = schpc_replylist_first = entry;
304903831d35Sstevel 	}
305003831d35Sstevel 
305103831d35Sstevel 	schpc_replylist_count++;
305203831d35Sstevel 
305303831d35Sstevel #if DEBUG
305403831d35Sstevel 	if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
305503831d35Sstevel 		dbg_entry = schpc_replylist_first;
305603831d35Sstevel 		cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist "
305703831d35Sstevel 		    "count = %d\n", schpc_replylist_count);
305803831d35Sstevel 		while (dbg_entry != NULL) {
305903831d35Sstevel 			cmn_err(CE_CONT, "schpc: schpc_replylist_link() - "
306003831d35Sstevel 			    "0x%lx transid\n", dbg_entry->transid);
306103831d35Sstevel 			dbg_entry = dbg_entry->next;
306203831d35Sstevel 		}
306303831d35Sstevel 	}
306403831d35Sstevel #endif	/* DEBUG  */
306503831d35Sstevel 
306603831d35Sstevel 	mutex_exit(&schpc_replylist_mutex);
306703831d35Sstevel 
306803831d35Sstevel 	return (entry);
306903831d35Sstevel }
307003831d35Sstevel 
307103831d35Sstevel 
307203831d35Sstevel /*
307303831d35Sstevel  * schpc_getslotstatus
307403831d35Sstevel  *
307503831d35Sstevel  * Issues a Get Slot Status command to the System Controller
307603831d35Sstevel  * for a specific slot.
307703831d35Sstevel  */
307803831d35Sstevel static int
schpc_getslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_getslot_t * slotstatus)307903831d35Sstevel schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
308003831d35Sstevel     pci_getslot_t *slotstatus)
308103831d35Sstevel {
308203831d35Sstevel 	pcimsg_t	request;
308303831d35Sstevel 	pcimsg_t	reply;
308403831d35Sstevel 	int		rval;
308503831d35Sstevel 	uint32_t	type, cmd, length;
308603831d35Sstevel 	uint64_t	transid;
308703831d35Sstevel 	schpc_replylist_t *entry;
308803831d35Sstevel 
308903831d35Sstevel 	SCHPC_DEBUG4(D_GETSLOTSTATUS,
309003831d35Sstevel 	    "schpc_getslotstatus(expander=%d board=%d "
309103831d35Sstevel 	    "slot=%d slotstatus=0x%p", expander, board,
3092*07d06da5SSurya Prakki 	    SCHPC_SLOT_NUM(slot), (void *)slotstatus);
309303831d35Sstevel 
309403831d35Sstevel 	if (schpc_p == NULL) {
309503831d35Sstevel 		return (1);
309603831d35Sstevel 	}
309703831d35Sstevel 
309803831d35Sstevel 	bzero(&request, sizeof (pcimsg_t));
309903831d35Sstevel 
310003831d35Sstevel 	request.pcimsg_node = expander;
310103831d35Sstevel 	request.pcimsg_board = board;
310203831d35Sstevel 	request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
310303831d35Sstevel 	request.pcimsg_revision = PCIMSG_REVISION;
310403831d35Sstevel 	request.pcimsg_command = PCIMSG_GETSLOTSTATUS;
310503831d35Sstevel 
310603831d35Sstevel 	type = MBOXSC_MSG_REQUEST;
310703831d35Sstevel 	cmd = PCIMSG_GETSLOTSTATUS;
310803831d35Sstevel 	transid =  schpc_gettransid(schpc_p, slot);
310903831d35Sstevel 	length = sizeof (pcimsg_t);
311003831d35Sstevel 
311103831d35Sstevel 	SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
311203831d35Sstevel 	    "0x%lx transid schpc_putrequest called", transid);
311303831d35Sstevel 
311403831d35Sstevel 	rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
311503831d35Sstevel 	    (void *)&request, schpc_timeout_putmsg, &entry);
311603831d35Sstevel 
311703831d35Sstevel 	SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
311803831d35Sstevel 	    "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
311903831d35Sstevel 
312003831d35Sstevel 	if (rval) {
312103831d35Sstevel 		return (rval);
312203831d35Sstevel 	}
312303831d35Sstevel 
312403831d35Sstevel 	bzero(&reply, sizeof (pcimsg_t));
312503831d35Sstevel 	type = MBOXSC_MSG_REPLY;
312603831d35Sstevel 
312703831d35Sstevel 	SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
312803831d35Sstevel 	    "0x%lx transid schpc_getreply called", transid);
312903831d35Sstevel 
313003831d35Sstevel 	rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
313103831d35Sstevel 	    (void *)&reply, schpc_timeout_getmsg, entry);
313203831d35Sstevel 
313303831d35Sstevel 	SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
313403831d35Sstevel 	    "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
313503831d35Sstevel 
313603831d35Sstevel 	if (rval == 0) {
313703831d35Sstevel 		*slotstatus = reply.pcimsg_type.pcimsg_getslot;
313803831d35Sstevel 
313903831d35Sstevel 		SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()");
314003831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_power_on %x",
314103831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_power_on);
314203831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_powergood %x",
314303831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_powergood);
314403831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_powerfault %x",
314503831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_powerfault);
314603831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_empty %x",
314703831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_empty);
314803831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_freq_cap %x",
314903831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_freq_cap);
315003831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_freq_setting %x",
315103831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_freq_setting);
315203831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_condition %x",
315303831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_condition);
315403831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_HEALTHY %x",
315503831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY);
315603831d35Sstevel 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_ENUM %x",
315703831d35Sstevel 		    reply.pcimsg_type.pcimsg_getslot.slot_ENUM);
315803831d35Sstevel 	}
315903831d35Sstevel 
316003831d35Sstevel 	return (rval);
316103831d35Sstevel }
316203831d35Sstevel 
316303831d35Sstevel 
316403831d35Sstevel /*
316503831d35Sstevel  * schpc_setslotstatus
316603831d35Sstevel  *
316703831d35Sstevel  * Issues a Set Slot Status command to the System Controller
316803831d35Sstevel  * for a specific slot.
316903831d35Sstevel  */
317003831d35Sstevel static int
schpc_setslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_setslot_t * slotstatus)317103831d35Sstevel schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
317203831d35Sstevel     pci_setslot_t *slotstatus)
317303831d35Sstevel {
317403831d35Sstevel 	pcimsg_t	request;
317503831d35Sstevel 	pcimsg_t	reply;
317603831d35Sstevel 	int		rval;
317703831d35Sstevel 	uint32_t	type, cmd, length;
317803831d35Sstevel 	uint64_t	transid;
317903831d35Sstevel 	schpc_replylist_t *entry;
318003831d35Sstevel 
318103831d35Sstevel 	SCHPC_DEBUG4(D_SETSLOTSTATUS,
318203831d35Sstevel 	    "schpc_setslotstatus(expander=%d board=%d "
318303831d35Sstevel 	    "slot=%d slotstatus=0x%p", expander, board,
3184*07d06da5SSurya Prakki 	    SCHPC_SLOT_NUM(slot), (void *)slotstatus);
318503831d35Sstevel 
318603831d35Sstevel 	bzero(&request, sizeof (pcimsg_t));
318703831d35Sstevel 
318803831d35Sstevel 	if (schpc_p == NULL) {
318903831d35Sstevel 		return (1);
319003831d35Sstevel 	}
319103831d35Sstevel 
319203831d35Sstevel 	request.pcimsg_node = expander;
319303831d35Sstevel 	request.pcimsg_board = board;
319403831d35Sstevel 	request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
319503831d35Sstevel 	request.pcimsg_revision = PCIMSG_REVISION;
319603831d35Sstevel 	request.pcimsg_command = PCIMSG_SETSLOTSTATUS;
319703831d35Sstevel 
319803831d35Sstevel 	request.pcimsg_type.pcimsg_setslot = *slotstatus;
319903831d35Sstevel 
320003831d35Sstevel 	SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change");
320103831d35Sstevel 	SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d",
320203831d35Sstevel 	    slotstatus->slot_led_power,
320303831d35Sstevel 	    slotstatus->slot_led_service,
320403831d35Sstevel 	    slotstatus->slot_led_fault);
320503831d35Sstevel 
320603831d35Sstevel 	type = MBOXSC_MSG_REQUEST;
320703831d35Sstevel 	cmd = PCIMSG_SETSLOTSTATUS;
320803831d35Sstevel 	transid =  schpc_gettransid(schpc_p, slot);
320903831d35Sstevel 	length = sizeof (pcimsg_t);
321003831d35Sstevel 
321103831d35Sstevel 	SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
321203831d35Sstevel 	    "0x%lx transid schpc_putrequest called", transid);
321303831d35Sstevel 
321403831d35Sstevel 	rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
321503831d35Sstevel 	    (void *)&request, schpc_timeout_putmsg, &entry);
321603831d35Sstevel 
321703831d35Sstevel 	SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
321803831d35Sstevel 	    "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
321903831d35Sstevel 
322003831d35Sstevel 	if (rval) {
322103831d35Sstevel 		return (rval);
322203831d35Sstevel 	}
322303831d35Sstevel 
322403831d35Sstevel 	bzero(&reply, sizeof (pcimsg_t));
322503831d35Sstevel 	type = MBOXSC_MSG_REPLY;
322603831d35Sstevel 
322703831d35Sstevel 	SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
322803831d35Sstevel 	    "0x%lx transid schpc_getreply called", transid);
322903831d35Sstevel 
323003831d35Sstevel 	rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
323103831d35Sstevel 	    (void *)&reply, schpc_timeout_getmsg, entry);
323203831d35Sstevel 
323303831d35Sstevel 	SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
323403831d35Sstevel 	    "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
323503831d35Sstevel 
323603831d35Sstevel 	if (rval == 0) {
323703831d35Sstevel 		slotstatus->slot_replystatus =
323803831d35Sstevel 		    reply.pcimsg_type.pcimsg_setslot.slot_replystatus;
323903831d35Sstevel 	}
324003831d35Sstevel 
324103831d35Sstevel 	return (rval);
324203831d35Sstevel }
324303831d35Sstevel 
324403831d35Sstevel /*
324503831d35Sstevel  * schpc_setslotled
324603831d35Sstevel  *
324703831d35Sstevel  * Changes the attention indicators for a given slot.
324803831d35Sstevel  */
324903831d35Sstevel static void
schpc_setslotled(int expander,int board,int slot,uint32_t led_state)325003831d35Sstevel schpc_setslotled(int expander, int board, int slot, uint32_t led_state)
325103831d35Sstevel {
325203831d35Sstevel 
325303831d35Sstevel 	pci_setslot_t	setslot;
325403831d35Sstevel 
325503831d35Sstevel 	if (schpc_p == NULL) {
325603831d35Sstevel 		return;
325703831d35Sstevel 	}
325803831d35Sstevel 
325903831d35Sstevel 	schpc_init_setslot_message(&setslot);
326003831d35Sstevel 
326103831d35Sstevel 	if (led_state & POWER_LED_ON) {
326203831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
326303831d35Sstevel 	}
326403831d35Sstevel 	if (led_state & POWER_LED_OFF) {
326503831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF;
326603831d35Sstevel 	}
326703831d35Sstevel 	if (led_state & POWER_LED_FLASH) {
326803831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH;
326903831d35Sstevel 	}
327003831d35Sstevel 	if (led_state & SERVICE_LED_ON) {
327103831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON;
327203831d35Sstevel 	}
327303831d35Sstevel 	if (led_state & SERVICE_LED_OFF) {
327403831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF;
327503831d35Sstevel 	}
327603831d35Sstevel 	if (led_state & SERVICE_LED_FLASH) {
327703831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH;
327803831d35Sstevel 	}
327903831d35Sstevel 	if (led_state & FAULT_LED_ON) {
328003831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON;
328103831d35Sstevel 	}
328203831d35Sstevel 	if (led_state & FAULT_LED_OFF) {
328303831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF;
328403831d35Sstevel 	}
328503831d35Sstevel 	if (led_state & FAULT_LED_FLASH) {
328603831d35Sstevel 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH;
328703831d35Sstevel 	}
328803831d35Sstevel 
328903831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_power) {
329003831d35Sstevel 	case PCIMSG_LED_ON:
329103831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_ON;
329203831d35Sstevel 		break;
329303831d35Sstevel 	case PCIMSG_LED_OFF:
329403831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_OFF;
329503831d35Sstevel 		break;
329603831d35Sstevel 	case PCIMSG_LED_FLASH:
329703831d35Sstevel 		setslot.slot_led_power = PCIMSG_LED_FLASH;
329803831d35Sstevel 		break;
329903831d35Sstevel 	}
330003831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_service) {
330103831d35Sstevel 	case PCIMSG_LED_ON:
330203831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_ON;
330303831d35Sstevel 		break;
330403831d35Sstevel 	case PCIMSG_LED_OFF:
330503831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_OFF;
330603831d35Sstevel 		break;
330703831d35Sstevel 	case PCIMSG_LED_FLASH:
330803831d35Sstevel 		setslot.slot_led_service = PCIMSG_LED_FLASH;
330903831d35Sstevel 		break;
331003831d35Sstevel 	}
331103831d35Sstevel 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
331203831d35Sstevel 	case PCIMSG_LED_ON:
331303831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_ON;
331403831d35Sstevel 		break;
331503831d35Sstevel 	case PCIMSG_LED_OFF:
331603831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_OFF;
331703831d35Sstevel 		break;
331803831d35Sstevel 	case PCIMSG_LED_FLASH:
331903831d35Sstevel 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
332003831d35Sstevel 		break;
332103831d35Sstevel 	}
332203831d35Sstevel 
332303831d35Sstevel 	(void) schpc_setslotstatus(expander, board, slot, &setslot);
332403831d35Sstevel }
332503831d35Sstevel 
332603831d35Sstevel /*
332703831d35Sstevel  * schpc_init_setslot_message
332803831d35Sstevel  *
332903831d35Sstevel  * Initialize Set Slot Message before using it.
333003831d35Sstevel  */
333103831d35Sstevel static void
schpc_init_setslot_message(pci_setslot_t * setslot)333203831d35Sstevel schpc_init_setslot_message(pci_setslot_t *setslot)
333303831d35Sstevel {
333403831d35Sstevel 	/*
333503831d35Sstevel 	 * Initialize Set Slot Command.
333603831d35Sstevel 	 */
333703831d35Sstevel 	setslot->slot_power_on = PCIMSG_OFF;
333803831d35Sstevel 	setslot->slot_power_off = PCIMSG_OFF;
333903831d35Sstevel 	setslot->slot_led_power = PCIMSG_LED_OFF;
334003831d35Sstevel 	setslot->slot_led_service = PCIMSG_LED_OFF;
334103831d35Sstevel 	setslot->slot_led_fault = PCIMSG_LED_OFF;
334203831d35Sstevel 	setslot->slot_disable_ENUM = PCIMSG_OFF;
334303831d35Sstevel 	setslot->slot_enable_ENUM = PCIMSG_OFF;
334403831d35Sstevel 	setslot->slot_disable_HEALTHY = PCIMSG_OFF;
334503831d35Sstevel 	setslot->slot_enable_HEALTHY = PCIMSG_OFF;
334603831d35Sstevel }
334703831d35Sstevel 
334803831d35Sstevel /*
334903831d35Sstevel  * schpc_gettransid
335003831d35Sstevel  *
335103831d35Sstevel  * Builds a unique transaction ID.
335203831d35Sstevel  */
335303831d35Sstevel static uint64_t
schpc_gettransid(schpc_t * schpc_p,int slot)335403831d35Sstevel schpc_gettransid(schpc_t *schpc_p, int slot)
335503831d35Sstevel {
335603831d35Sstevel 	uint64_t	trans_id;
335703831d35Sstevel 
335803831d35Sstevel 	mutex_enter(&schpc_p->schpc_mutex);
335903831d35Sstevel 
336003831d35Sstevel 	if (++schpc_p->schpc_transid == 0)
336103831d35Sstevel 		schpc_p->schpc_transid = 1;
336203831d35Sstevel 
336303831d35Sstevel 	trans_id = (schpc_p->schpc_slot[slot].expander<<24) |
336403831d35Sstevel 	    (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid;
336503831d35Sstevel 
336603831d35Sstevel 	mutex_exit(&schpc_p->schpc_mutex);
336703831d35Sstevel 
336803831d35Sstevel 	SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning",
336903831d35Sstevel 	    trans_id);
337003831d35Sstevel 
337103831d35Sstevel 	return (trans_id);
337203831d35Sstevel }
337303831d35Sstevel 
337403831d35Sstevel /*
337503831d35Sstevel  * schpc_slot_get_index
337603831d35Sstevel  *
337703831d35Sstevel  * get slot table index from the slot handle
337803831d35Sstevel  */
337903831d35Sstevel static int
schpc_slot_get_index(schpc_t * schpc_p,hpc_slot_t slot)338003831d35Sstevel schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot)
338103831d35Sstevel {
338203831d35Sstevel 	int	i;
338303831d35Sstevel 	int	rval = -1;
338403831d35Sstevel 
338503831d35Sstevel 	ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex));
338603831d35Sstevel 
338703831d35Sstevel 	for (i = 0; i < schpc_p->schpc_number_of_slots; i++) {
338803831d35Sstevel 		if (schpc_p->schpc_slot[i].slot_handle == slot)
338903831d35Sstevel 			return (i);
339003831d35Sstevel 	}
339103831d35Sstevel 
339203831d35Sstevel 	return (rval);
339303831d35Sstevel }
339403831d35Sstevel 
339503831d35Sstevel /*
339603831d35Sstevel  * schpc_register_all_slots
339703831d35Sstevel  *
339803831d35Sstevel  * Search device tree for pci nodes and register attachment points
339903831d35Sstevel  * for all hot pluggable slots.
340003831d35Sstevel  */
340103831d35Sstevel /*ARGSUSED*/
340203831d35Sstevel static void
schpc_register_all_slots(schpc_t * schpc_p)340303831d35Sstevel schpc_register_all_slots(schpc_t *schpc_p)
340403831d35Sstevel {
340503831d35Sstevel 	int		slot = 0;
340603831d35Sstevel 	char		caddr[64];
340703831d35Sstevel 	dev_info_t	*pci_dip = NULL;
340803831d35Sstevel 	find_dev_t	find_dev;
340903831d35Sstevel 	int		leaf, schizo, expander, portid, offset;
341003831d35Sstevel 
341103831d35Sstevel 	SCHPC_DEBUG1(D_ATTACH,
3412*07d06da5SSurya Prakki 	    "schpc_register_all_slots(schpc_p=%p)", (void *)schpc_p);
341303831d35Sstevel 
341403831d35Sstevel 	/*
341503831d35Sstevel 	 * Allow the event_handler to start processing unsolicited
341603831d35Sstevel 	 * events now that slots are about to be registered.
341703831d35Sstevel 	 */
341803831d35Sstevel 	slots_registered = B_TRUE;
341903831d35Sstevel 
342003831d35Sstevel 	for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) {
342103831d35Sstevel 
342203831d35Sstevel 		leaf = SCHPC_SLOT_LEAF(slot);
342303831d35Sstevel 		schizo = SCHPC_SLOT_SCHIZO(slot);
342403831d35Sstevel 		expander = SCHPC_SLOT_EXPANDER(slot);
342503831d35Sstevel 
342603831d35Sstevel 		if (schizo == 0)
342703831d35Sstevel 			portid = 0x1c;
342803831d35Sstevel 		else
342903831d35Sstevel 			portid = 0x1d;
343003831d35Sstevel 
343103831d35Sstevel 		if (leaf == 0)
343203831d35Sstevel 			offset = 0x600000;
343303831d35Sstevel 		else
343403831d35Sstevel 			offset = 0x700000;
343503831d35Sstevel 
343603831d35Sstevel 		portid = (expander << 5) | portid;
343703831d35Sstevel 
343803831d35Sstevel 		(void) sprintf(caddr, "%x,%x", portid, offset);
343903831d35Sstevel 
344003831d35Sstevel 		SCHPC_DEBUG3(D_ATTACH,
344103831d35Sstevel 		    "schpc_register_all_slots: searching for pci@%s"
344203831d35Sstevel 		    " schizo=%d, leaf=%d", caddr, schizo, leaf);
344303831d35Sstevel 
344403831d35Sstevel 		find_dev.cname = "pci";
344503831d35Sstevel 		find_dev.caddr = caddr;
344603831d35Sstevel 		find_dev.schizo = schizo;
344703831d35Sstevel 		find_dev.leaf = leaf;
344803831d35Sstevel 		find_dev.dip = NULL;
344903831d35Sstevel 
345003831d35Sstevel 		/* root node doesn't have to be held */
345103831d35Sstevel 		ddi_walk_devs(ddi_root_node(), schpc_match_dip,
345203831d35Sstevel 		    &find_dev);
345303831d35Sstevel 
345403831d35Sstevel 		pci_dip = find_dev.dip;
345503831d35Sstevel 
345603831d35Sstevel 		if (pci_dip == NULL) {
345703831d35Sstevel 
345803831d35Sstevel 			SCHPC_DEBUG1(D_ATTACH,
345903831d35Sstevel 			    "schpc_register_all_slots: pci@%s NOT FOUND",
346003831d35Sstevel 			    caddr);
346103831d35Sstevel 
346203831d35Sstevel 			continue;
346303831d35Sstevel 		}
346403831d35Sstevel 
346503831d35Sstevel 		SCHPC_DEBUG2(D_ATTACH,
346603831d35Sstevel 		    "schpc_register_all_slots: pci@%s FOUND dip=0x%p",
3467*07d06da5SSurya Prakki 		    caddr, (void *)pci_dip);
346803831d35Sstevel 
346903831d35Sstevel 		(void) schpc_add_pci(pci_dip);
347003831d35Sstevel 
347103831d35Sstevel 		/*
347203831d35Sstevel 		 * Release hold acquired in schpc_match_dip()
347303831d35Sstevel 		 */
347403831d35Sstevel 		ndi_rele_devi(pci_dip);
347503831d35Sstevel 	}
347603831d35Sstevel 
347703831d35Sstevel 	SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit");
347803831d35Sstevel 
347903831d35Sstevel 	thread_exit();
348003831d35Sstevel }
348103831d35Sstevel 
348203831d35Sstevel /*
348303831d35Sstevel  * schpc_add_pci
348403831d35Sstevel  *
348503831d35Sstevel  * Routine to add attachments points associated with a pci node.
348603831d35Sstevel  * Can be call externally by DR when configuring a PCI I/O Board.
348703831d35Sstevel  */
348803831d35Sstevel int
schpc_add_pci(dev_info_t * bdip)348903831d35Sstevel schpc_add_pci(dev_info_t *bdip)
349003831d35Sstevel {
349103831d35Sstevel 	int		portid;
349203831d35Sstevel 	int		expander, board, schizo, leaf, slot, status;
349303831d35Sstevel 	char		ap_id[MAXNAMELEN];
349403831d35Sstevel 	char		caddr[64];
349503831d35Sstevel 	char		*naddr;
349603831d35Sstevel 	hpc_slot_info_t	slot_info;
349703831d35Sstevel 	hpc_slot_ops_t	*slot_ops;
349803831d35Sstevel 	dev_info_t 	*sdip = bdip;
349903831d35Sstevel 
3500*07d06da5SSurya Prakki 	SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", (void *)sdip);
350103831d35Sstevel 
350203831d35Sstevel 	if (schpc_p == NULL) {
350303831d35Sstevel 		/*
350403831d35Sstevel 		 * The schpc driver has not been attached yet.
350503831d35Sstevel 		 */
350603831d35Sstevel 		return (DDI_SUCCESS);
350703831d35Sstevel 	}
350803831d35Sstevel 
350903831d35Sstevel 	if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) {
3510*07d06da5SSurya Prakki 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n",
3511*07d06da5SSurya Prakki 		    (void *)sdip);
351203831d35Sstevel 		return (DDI_FAILURE);
351303831d35Sstevel 	}
351403831d35Sstevel 
351503831d35Sstevel 	expander = schpc_getexpander(sdip);
351603831d35Sstevel 	board = schpc_getboard(sdip);
351703831d35Sstevel 
351803831d35Sstevel 	switch (portid & 0x1f) {
351903831d35Sstevel 
352003831d35Sstevel 	case 0x1c:
352103831d35Sstevel 		schizo = 0;
352203831d35Sstevel 		break;
352303831d35Sstevel 	case 0x1d:
352403831d35Sstevel 		schizo = 1;
352503831d35Sstevel 		break;
352603831d35Sstevel 	default:
352703831d35Sstevel 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3528*07d06da5SSurya Prakki 		    "Invalid pci portid 0x%x\n", (void *)sdip, portid);
352903831d35Sstevel 		return (DDI_FAILURE);
353003831d35Sstevel 	}
353103831d35Sstevel 
353203831d35Sstevel 	naddr = ddi_get_name_addr(sdip);
353303831d35Sstevel 	if (naddr == NULL) {
353403831d35Sstevel 		SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr"
3535*07d06da5SSurya Prakki 		    "(0x%p) returns null", (void *)sdip);
353603831d35Sstevel 		return (DDI_FAILURE);
353703831d35Sstevel 	}
353803831d35Sstevel 
353903831d35Sstevel 	(void) sprintf(caddr, "%x,600000", portid);
354003831d35Sstevel 
354103831d35Sstevel 	if (strcmp(caddr, naddr) == 0) {
354203831d35Sstevel 		leaf = 0;
354303831d35Sstevel 	} else {
354403831d35Sstevel 		(void) sprintf(caddr, "%x,700000", portid);
354503831d35Sstevel 		if (strcmp(caddr, naddr) == 0) {
354603831d35Sstevel 			char *name;
354703831d35Sstevel 
354803831d35Sstevel 			leaf = 1;
354903831d35Sstevel 			name = ddi_binding_name(sdip);
355003831d35Sstevel 			if ((strcmp(name, "pci108e,8002") == 0) &&
355103831d35Sstevel 			    (schizo == 0)) {
355203831d35Sstevel 				int circ;
355303831d35Sstevel 				dev_info_t *cdip;
355403831d35Sstevel 				/*
355503831d35Sstevel 				 * XMITS 0 Leaf B will have its hot
355603831d35Sstevel 				 * pluggable slot off a PCI-PCI bridge,
355703831d35Sstevel 				 * which is the only child.
355803831d35Sstevel 				 */
355903831d35Sstevel 				ndi_devi_enter(sdip, &circ);
356003831d35Sstevel 				cdip = ddi_get_child(sdip);
356103831d35Sstevel 				if (cdip == NULL) {
356203831d35Sstevel 					cmn_err(CE_WARN,
356303831d35Sstevel 					    "schpc_add_pci(dip=0x%p) - "
356403831d35Sstevel 					    "Invalid pci name addr %s\n",
3565*07d06da5SSurya Prakki 					    (void *)sdip, naddr);
356603831d35Sstevel 					ndi_devi_exit(sdip, circ);
356703831d35Sstevel 					return (DDI_FAILURE);
356803831d35Sstevel 				}
356903831d35Sstevel 				ndi_devi_exit(sdip, circ);
357003831d35Sstevel 				sdip = cdip;
357103831d35Sstevel 			}
357203831d35Sstevel 		} else {
357303831d35Sstevel 			cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3574*07d06da5SSurya Prakki 			    "Invalid pci name addr %s\n", (void *)sdip, naddr);
357503831d35Sstevel 			return (DDI_FAILURE);
357603831d35Sstevel 		}
357703831d35Sstevel 	}
357803831d35Sstevel 
357903831d35Sstevel 	/* create a slot table index */
358003831d35Sstevel 	slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf);
358103831d35Sstevel 
358203831d35Sstevel 	if (schpc_p->schpc_slot[slot].devi) {
358303831d35Sstevel 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3584*07d06da5SSurya Prakki 		    "pci node already registered\n", (void *)sdip);
358503831d35Sstevel 		return (DDI_FAILURE);
358603831d35Sstevel 	}
358703831d35Sstevel 
358803831d35Sstevel 	/*
358903831d35Sstevel 	 * There is no need to hold the dip while saving it in
359003831d35Sstevel 	 * the devi field below. The dip is never dereferenced.
359103831d35Sstevel 	 * (If that changes, this code should be modified).
359203831d35Sstevel 	 * We want to avoid holding the dip here because it
359303831d35Sstevel 	 * prevents DR.
359403831d35Sstevel 	 *
359503831d35Sstevel 	 * NOTE: Even though the slot on XMITS0 Leaf-B
359603831d35Sstevel 	 * is connected to a pci_pci bridge, we will be saving
359703831d35Sstevel 	 * the busdip in this datastructure. This will make
359803831d35Sstevel 	 * it easier to identify the dip being removed in
359903831d35Sstevel 	 * schpc_remove_pci().
360003831d35Sstevel 	 */
360103831d35Sstevel 	schpc_p->schpc_slot[slot].devi = bdip;
360203831d35Sstevel 
360303831d35Sstevel 	schpc_p->schpc_slot[slot].expander = expander;
360403831d35Sstevel 	schpc_p->schpc_slot[slot].board = board;
360503831d35Sstevel 	schpc_p->schpc_slot[slot].schizo = schizo;
360603831d35Sstevel 	schpc_p->schpc_slot[slot].leaf = leaf;
360703831d35Sstevel 
360803831d35Sstevel 	/*
360903831d35Sstevel 	 * Starcat PCI slots are always PCI device 1.
361003831d35Sstevel 	 */
361103831d35Sstevel 	schpc_p->schpc_slot[slot].pci_id = 1;
361203831d35Sstevel 
361303831d35Sstevel 	schpc_buildapid(sdip, slot, (char *)&ap_id);
361403831d35Sstevel 
361503831d35Sstevel 	(void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id);
361603831d35Sstevel 
361703831d35Sstevel 	/* safe to call ddi_pathname(): bdip is held */
361803831d35Sstevel 	(void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path);
361903831d35Sstevel 
362003831d35Sstevel 	status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot));
362103831d35Sstevel 	switch (status) {
362203831d35Sstevel 		case RSV_UNKNOWN:
362303831d35Sstevel 		case RSV_PRESENT:
362403831d35Sstevel 		case RSV_MISS:
362503831d35Sstevel 		case RSV_PASS:
362603831d35Sstevel 		case RSV_EMPTY_CASSETTE:
362703831d35Sstevel 
362803831d35Sstevel 			/*
362903831d35Sstevel 			 * Test the condition of the slot.
363003831d35Sstevel 			 */
363103831d35Sstevel 			schpc_test((caddr_t)schpc_p, slot, 0, 0);
363203831d35Sstevel 			break;
363303831d35Sstevel 		case RSV_BLACK:
363403831d35Sstevel 			schpc_p->schpc_slot[slot].state = 0;
363503831d35Sstevel 			cmn_err(CE_WARN, "schpc: PCI card blacklisted: "
363603831d35Sstevel 			    "expander=%d board=%d slot=%d\n", expander,
363703831d35Sstevel 			    board, SCHPC_SLOT_NUM(slot));
363803831d35Sstevel 			break;
363903831d35Sstevel 		default:
364003831d35Sstevel 			schpc_p->schpc_slot[slot].state = 0;
364103831d35Sstevel 			cmn_err(CE_WARN, "schpc: PCI card failed by POST: "
364203831d35Sstevel 			    "expander=%d board=%d slot=%d failure=0x%x\n",
364303831d35Sstevel 			    expander, board, SCHPC_SLOT_NUM(slot), status);
364403831d35Sstevel 			break;
364503831d35Sstevel 	}
364603831d35Sstevel 
364703831d35Sstevel 	if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) {
364803831d35Sstevel 
364903831d35Sstevel 		/* allocate slot ops */
365003831d35Sstevel 
365103831d35Sstevel 		slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
365203831d35Sstevel 		schpc_p->schpc_slot[slot].slot_ops = slot_ops;
365303831d35Sstevel 
365403831d35Sstevel 		/*
365503831d35Sstevel 		 * Default to Autoconfiguration disabled.
365603831d35Sstevel 		 */
365703831d35Sstevel 		schpc_p->schpc_slot[slot].state &=
365803831d35Sstevel 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
365903831d35Sstevel 
366003831d35Sstevel 		/*
366103831d35Sstevel 		 * Fill in the slot information structure that
366203831d35Sstevel 		 * describes the slot.
366303831d35Sstevel 		 */
366403831d35Sstevel 		slot_info.version = HPC_SLOT_OPS_VERSION;
366503831d35Sstevel 
366603831d35Sstevel 		if (schpc_p->schpc_hotplugmodel ==
366703831d35Sstevel 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG)
366803831d35Sstevel 			slot_info.slot_type = HPC_SLOT_TYPE_PCI;
366903831d35Sstevel 		else
367003831d35Sstevel 			slot_info.slot_type = HPC_SLOT_TYPE_CPCI;
367103831d35Sstevel 
367203831d35Sstevel 		slot_info.slot.pci.device_number =
367303831d35Sstevel 		    schpc_p->schpc_slot[slot].pci_id;
367403831d35Sstevel 
367503831d35Sstevel 		slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
367603831d35Sstevel 
367703831d35Sstevel 		if (schpc_use_legacy_apid)
367803831d35Sstevel 			slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE;
367903831d35Sstevel 		else
368003831d35Sstevel 			slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
368103831d35Sstevel 			    HPC_SLOT_CREATE_DEVLINK;
368203831d35Sstevel 
3683*07d06da5SSurya Prakki 		(void) strcpy(slot_info.slot.pci.slot_logical_name,
368403831d35Sstevel 		    schpc_p->schpc_slot[slot].ap_id);
368503831d35Sstevel 
368603831d35Sstevel 		/*
368703831d35Sstevel 		 * Fill in the slot ops structure that tells
368803831d35Sstevel 		 * the Hot Plug Services what function we
368903831d35Sstevel 		 * support.
369003831d35Sstevel 		 */
369103831d35Sstevel 		slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
369203831d35Sstevel 		if (schpc_p->schpc_hotplugmodel ==
369303831d35Sstevel 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
369403831d35Sstevel 			slot_ops->hpc_op_connect = schpc_connect;
369503831d35Sstevel 			slot_ops->hpc_op_disconnect = schpc_disconnect;
369603831d35Sstevel 			slot_ops->hpc_op_insert = NULL;
369703831d35Sstevel 			slot_ops->hpc_op_remove = NULL;
369803831d35Sstevel 			slot_ops->hpc_op_control = schpc_pci_control;
369903831d35Sstevel 		} else {
370003831d35Sstevel 			slot_ops->hpc_op_connect = NULL;
370103831d35Sstevel 			slot_ops->hpc_op_disconnect = NULL;
370203831d35Sstevel 			slot_ops->hpc_op_insert = NULL;
370303831d35Sstevel 			slot_ops->hpc_op_remove = NULL;
370403831d35Sstevel 			slot_ops->hpc_op_control = schpc_cpci_control;
370503831d35Sstevel 		}
370603831d35Sstevel 
370703831d35Sstevel 		SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC "
370803831d35Sstevel 		    "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s",
370903831d35Sstevel 		    schpc_p->schpc_slot[slot].nexus_path,
3710*07d06da5SSurya Prakki 		    (void *)schpc_p, SCHPC_SLOT_NUM(slot),
371103831d35Sstevel 		    slot_info.slot.pci.device_number,
371203831d35Sstevel 		    slot_info.slot.pci.slot_logical_name);
371303831d35Sstevel 
371403831d35Sstevel 		if (hpc_slot_register(schpc_p->schpc_devi,
371503831d35Sstevel 		    schpc_p->schpc_slot[slot].nexus_path, &slot_info,
371603831d35Sstevel 		    &schpc_p->schpc_slot[slot].slot_handle,
371703831d35Sstevel 		    slot_ops, (caddr_t)schpc_p, 0) != 0) {
371803831d35Sstevel 
371903831d35Sstevel 			/*
372003831d35Sstevel 			 * If the slot can not be registered,
372103831d35Sstevel 			 * then the slot_ops need to be freed.
372203831d35Sstevel 			 */
372303831d35Sstevel 			cmn_err(CE_WARN, "schpc%d Unable to Register "
372403831d35Sstevel 			    "Slot %s", schpc_p->schpc_instance,
372503831d35Sstevel 			    slot_info.slot.pci.slot_logical_name);
372603831d35Sstevel 
372703831d35Sstevel 			hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops);
372803831d35Sstevel 
372903831d35Sstevel 			schpc_p->schpc_slot[slot].slot_ops = NULL;
373003831d35Sstevel 
373103831d35Sstevel 			return (DDI_FAILURE);
373203831d35Sstevel 		}
373303831d35Sstevel 
373403831d35Sstevel 		/*
373503831d35Sstevel 		 * We are ready to take commands from the HPC Services.
373603831d35Sstevel 		 */
373703831d35Sstevel 		schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED;
373803831d35Sstevel 	}
373903831d35Sstevel 
374003831d35Sstevel 	return (DDI_SUCCESS);
374103831d35Sstevel }
374203831d35Sstevel 
374303831d35Sstevel /*
374403831d35Sstevel  * schpc_remove_pci
374503831d35Sstevel  *
374603831d35Sstevel  * Routine to remove attachments points associated with a pci node.
374703831d35Sstevel  * Can be call externally by DR when unconfiguring a PCI I/O Board.
374803831d35Sstevel  */
374903831d35Sstevel int
schpc_remove_pci(dev_info_t * dip)375003831d35Sstevel schpc_remove_pci(dev_info_t *dip)
375103831d35Sstevel {
375203831d35Sstevel 	int slot;
375303831d35Sstevel 
3754*07d06da5SSurya Prakki 	SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", (void *)dip);
375503831d35Sstevel 
375603831d35Sstevel 	if (schpc_p == NULL) {
375703831d35Sstevel 		/*
375803831d35Sstevel 		 * The schpc driver has not been attached yet.
375903831d35Sstevel 		 */
376003831d35Sstevel 		return (DDI_SUCCESS);
376103831d35Sstevel 	}
376203831d35Sstevel 
376303831d35Sstevel 	for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) {
376403831d35Sstevel 		if (schpc_p->schpc_slot[slot].devi == dip) {
376503831d35Sstevel 
376603831d35Sstevel 			if (schpc_p->schpc_slot[slot].slot_ops) {
376703831d35Sstevel 				if (hpc_slot_unregister(
376803831d35Sstevel 				    &schpc_p->schpc_slot[slot].slot_handle)) {
376903831d35Sstevel 					cmn_err(CE_WARN,
377003831d35Sstevel 					    "schpc_remove_pci(dip=0x%p) - "
377103831d35Sstevel 					    "unable to unregister pci slots\n",
3772*07d06da5SSurya Prakki 					    (void *)dip);
377303831d35Sstevel 					return (DDI_FAILURE);
377403831d35Sstevel 				} else {
377503831d35Sstevel 					hpc_free_slot_ops(
377603831d35Sstevel 					    schpc_p->schpc_slot[slot].slot_ops);
377703831d35Sstevel 
377803831d35Sstevel 					schpc_p->schpc_slot[slot].slot_ops =
377903831d35Sstevel 					    NULL;
378003831d35Sstevel 
378103831d35Sstevel 					schpc_p->schpc_slot[slot].devi = NULL;
378203831d35Sstevel 
378303831d35Sstevel 					return (DDI_SUCCESS);
378403831d35Sstevel 				}
378503831d35Sstevel 			} else {
378603831d35Sstevel 				schpc_p->schpc_slot[slot].devi = NULL;
378703831d35Sstevel 
378803831d35Sstevel 				return (DDI_SUCCESS);
378903831d35Sstevel 			}
379003831d35Sstevel 		}
379103831d35Sstevel 	}
379203831d35Sstevel 
379303831d35Sstevel 	cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) "
3794*07d06da5SSurya Prakki 	    "dip not found\n", (void *)dip);
379503831d35Sstevel 
379603831d35Sstevel 	return (DDI_SUCCESS);
379703831d35Sstevel }
379803831d35Sstevel 
379903831d35Sstevel /*
380003831d35Sstevel  * schpc_match_dip
380103831d35Sstevel  *
380203831d35Sstevel  * Used by ddi_walk_devs to find PCI Nexus nodes associated with
380303831d35Sstevel  * Hot Plug Controllers.
380403831d35Sstevel  */
380503831d35Sstevel static int
schpc_match_dip(dev_info_t * dip,void * arg)380603831d35Sstevel schpc_match_dip(dev_info_t *dip, void *arg)
380703831d35Sstevel {
380803831d35Sstevel 	char		*naddr;
380903831d35Sstevel 	find_dev_t	*find_dev = (find_dev_t *)arg;
381003831d35Sstevel 
381103831d35Sstevel 	if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 &&
381203831d35Sstevel 	    ((((naddr = ddi_get_name_addr(dip)) != NULL) &&
381303831d35Sstevel 	    (strcmp(find_dev->caddr, naddr) == 0)) ||
381403831d35Sstevel 	    ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) {
381503831d35Sstevel 		/*
381603831d35Sstevel 		 * While ddi_walk_devs() holds dips when invoking this
381703831d35Sstevel 		 * callback, this dip is being saved and will be accessible
381803831d35Sstevel 		 * to the caller outside ddi_walk_devs(). Therefore it must be
381903831d35Sstevel 		 * held.
382003831d35Sstevel 		 */
382103831d35Sstevel 		ndi_hold_devi(dip);
382203831d35Sstevel 		find_dev->dip = dip;
382303831d35Sstevel 
382403831d35Sstevel 		SCHPC_DEBUG2(D_ATTACH,
382503831d35Sstevel 		    "schpc_match_dip: pci@%s FOUND dip=0x%p",
3826*07d06da5SSurya Prakki 		    find_dev->caddr, (void *)find_dev->dip);
382703831d35Sstevel 
382803831d35Sstevel 		return (DDI_WALK_TERMINATE);
382903831d35Sstevel 	}
383003831d35Sstevel 
383103831d35Sstevel 	ASSERT(find_dev->dip == NULL);
383203831d35Sstevel 	return (DDI_WALK_CONTINUE);
383303831d35Sstevel }
383403831d35Sstevel 
383503831d35Sstevel /*
383603831d35Sstevel  * schpc_buildapid
383703831d35Sstevel  *
383803831d35Sstevel  * Takes a component address and translates it into a ap_id prefix.
383903831d35Sstevel  */
384003831d35Sstevel static void
schpc_buildapid(dev_info_t * dip,int slot,char * ap_id)384103831d35Sstevel schpc_buildapid(dev_info_t *dip, int slot, char *ap_id)
384203831d35Sstevel {
384303831d35Sstevel 	int r, pci_id_cnt, pci_id_bit;
384403831d35Sstevel 	int slots_before, found;
384503831d35Sstevel 	unsigned char *slot_names_data, *s;
384603831d35Sstevel 	int slot_names_size;
384703831d35Sstevel 	int slot_num;
384803831d35Sstevel 	unsigned int bit_mask;
384903831d35Sstevel 
385003831d35Sstevel 	slot_num = SCHPC_SLOT_NUM(slot);
385103831d35Sstevel 
385203831d35Sstevel 	if (schpc_use_legacy_apid) {
385303831d35Sstevel 		SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot);
385403831d35Sstevel 
3855*07d06da5SSurya Prakki 		(void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
385603831d35Sstevel 		    schpc_getboard(dip), slot_num);
385703831d35Sstevel 
385803831d35Sstevel 		SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
385903831d35Sstevel 
386003831d35Sstevel 		return;
386103831d35Sstevel 	}
386203831d35Sstevel 
386303831d35Sstevel 	r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
386403831d35Sstevel 	    "slot-names", (caddr_t)&slot_names_data,
386503831d35Sstevel 	    &slot_names_size);
386603831d35Sstevel 
386703831d35Sstevel 	if (r == DDI_PROP_SUCCESS) {
386803831d35Sstevel 
386903831d35Sstevel 		/*
387003831d35Sstevel 		 * We can try to use the slot-names property to
387103831d35Sstevel 		 * build our ap-id.
387203831d35Sstevel 		 */
387303831d35Sstevel 		bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) |
387403831d35Sstevel 		    (slot_names_data[1] << 16) | (slot_names_data[0] << 24);
387503831d35Sstevel 
387603831d35Sstevel 		pci_id_bit = 1;
387703831d35Sstevel 		pci_id_cnt = slots_before = found = 0;
387803831d35Sstevel 
387903831d35Sstevel 		SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x",
388003831d35Sstevel 		    slot, bit_mask);
388103831d35Sstevel 
388203831d35Sstevel 		/*
388303831d35Sstevel 		 * Walk the bit mask until we find the bit that corresponds
388403831d35Sstevel 		 * to our slots device number.  We count how many bits
388503831d35Sstevel 		 * we find before we find our slot's bit.
388603831d35Sstevel 		 */
388703831d35Sstevel 		while (!found && (pci_id_cnt < 32)) {
388803831d35Sstevel 
388903831d35Sstevel 			while (schpc_p->schpc_slot[slot].pci_id
389003831d35Sstevel 			    != pci_id_cnt) {
389103831d35Sstevel 
389203831d35Sstevel 				/*
389303831d35Sstevel 				 * Find the next bit set.
389403831d35Sstevel 				 */
389503831d35Sstevel 				while (!(bit_mask & pci_id_bit) &&
389603831d35Sstevel 				    (pci_id_cnt < 32)) {
389703831d35Sstevel 					pci_id_bit = pci_id_bit << 1;
389803831d35Sstevel 					pci_id_cnt++;
389903831d35Sstevel 				}
390003831d35Sstevel 
390103831d35Sstevel 				if (schpc_p->schpc_slot[slot].pci_id !=
390203831d35Sstevel 				    pci_id_cnt)
390303831d35Sstevel 					slots_before++;
390403831d35Sstevel 				else
390503831d35Sstevel 					found = 1;
390603831d35Sstevel 			}
390703831d35Sstevel 		}
390803831d35Sstevel 
390903831d35Sstevel 		if (pci_id_cnt < 32) {
391003831d35Sstevel 
391103831d35Sstevel 			/*
391203831d35Sstevel 			 * Set ptr to first string.
391303831d35Sstevel 			 */
391403831d35Sstevel 			s = slot_names_data + 4;
391503831d35Sstevel 
391603831d35Sstevel 			/*
391703831d35Sstevel 			 * Increment past all the strings for the slots
391803831d35Sstevel 			 * before ours.
391903831d35Sstevel 			 */
392003831d35Sstevel 			while (slots_before) {
392103831d35Sstevel 				while (*s != NULL)
392203831d35Sstevel 					s++;
392303831d35Sstevel 				s++;
392403831d35Sstevel 				slots_before--;
392503831d35Sstevel 			}
392603831d35Sstevel 
392703831d35Sstevel 			/*
392803831d35Sstevel 			 * We should be at our string.
392903831d35Sstevel 			 */
393003831d35Sstevel 
3931*07d06da5SSurya Prakki 			(void) sprintf(ap_id, "IO%d_%s",
3932*07d06da5SSurya Prakki 			    schpc_getexpander(dip), s);
393303831d35Sstevel 
393403831d35Sstevel 			SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s",
393503831d35Sstevel 			    slot, ap_id);
393603831d35Sstevel 
393703831d35Sstevel 			kmem_free(slot_names_data, slot_names_size);
393803831d35Sstevel 			return;
393903831d35Sstevel 		}
394003831d35Sstevel 
394103831d35Sstevel 		SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found",
394203831d35Sstevel 		    slot);
394303831d35Sstevel 
394403831d35Sstevel 		kmem_free(slot_names_data, slot_names_size);
394503831d35Sstevel 	} else
394603831d35Sstevel 		SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found",
394703831d35Sstevel 		    slot);
394803831d35Sstevel 
394903831d35Sstevel 	/*
395003831d35Sstevel 	 * Build the ap-id using the legacy naming scheme.
395103831d35Sstevel 	 */
3952*07d06da5SSurya Prakki 	(void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
395303831d35Sstevel 	    schpc_getboard(dip), slot_num);
395403831d35Sstevel 
395503831d35Sstevel 	SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
395603831d35Sstevel }
395703831d35Sstevel 
395803831d35Sstevel /*
395903831d35Sstevel  * schpc_getexpander
396003831d35Sstevel  *
396103831d35Sstevel  * Returns the Expander Number (0-17) for the dip passed in. The Expander
396203831d35Sstevel  * Number is extracted from the portid property of the pci node. Portid
396303831d35Sstevel  * consists of <Expbrd#><1110x>, where x is the schizo number.
396403831d35Sstevel  */
396503831d35Sstevel static int
schpc_getexpander(dev_info_t * dip)396603831d35Sstevel schpc_getexpander(dev_info_t *dip)
396703831d35Sstevel {
396803831d35Sstevel 	int	id;
396903831d35Sstevel 
397003831d35Sstevel 	id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1);
397103831d35Sstevel 
397203831d35Sstevel 	if (id != -1)
397303831d35Sstevel 		return (id >> 5);
397403831d35Sstevel 	else {
397503831d35Sstevel 		id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1);
397603831d35Sstevel 		return (id);
397703831d35Sstevel 	}
397803831d35Sstevel }
397903831d35Sstevel 
398003831d35Sstevel /*
398103831d35Sstevel  * schpc_getboard
398203831d35Sstevel  *
398303831d35Sstevel  * Returns the board number (0 or 1) for the dip passed in.
398403831d35Sstevel  */
398503831d35Sstevel static int
schpc_getboard(dev_info_t * dip)398603831d35Sstevel schpc_getboard(dev_info_t *dip)
398703831d35Sstevel {
398803831d35Sstevel 	_NOTE(ARGUNUSED(dip))
398903831d35Sstevel 
399003831d35Sstevel 	/*
399103831d35Sstevel 	 * Hot Pluggable PCI/cPCI slots are only available on
399203831d35Sstevel 	 * Board 1 (half-bandwidth slot).
399303831d35Sstevel 	 */
399403831d35Sstevel 	return (1);
399503831d35Sstevel }
399603831d35Sstevel 
399703831d35Sstevel /*ARGSUSED*/
399803831d35Sstevel static int
schpc_get_slot_status(uint_t expander,uint_t board,uint_t slot)399903831d35Sstevel schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot)
400003831d35Sstevel {
400103831d35Sstevel 	gdcd_t *gdcd;
400203831d35Sstevel 	int prd_slot, status, bus;
400303831d35Sstevel 
400403831d35Sstevel 	SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
400503831d35Sstevel 	    "exp=%d board=%d slot=%d", expander, board, slot);
400603831d35Sstevel 
400703831d35Sstevel 	if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t),
400803831d35Sstevel 	    KM_SLEEP)) == NULL) {
400903831d35Sstevel 		return (RSV_UNDEFINED);
401003831d35Sstevel 	}
401103831d35Sstevel 
401203831d35Sstevel 	/*
401303831d35Sstevel 	 * Get the Starcat Specific Global DCD Structure from the golden
401403831d35Sstevel 	 * IOSRAM.
401503831d35Sstevel 	 */
401603831d35Sstevel 	if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
401703831d35Sstevel 		cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
401803831d35Sstevel 		    "From IOSRAM\n");
401903831d35Sstevel 		kmem_free(gdcd, sizeof (gdcd_t));
402003831d35Sstevel 		return (RSV_UNDEFINED);
402103831d35Sstevel 	}
402203831d35Sstevel 
402303831d35Sstevel 	if (gdcd->h.dcd_magic != GDCD_MAGIC) {
402403831d35Sstevel 
402503831d35Sstevel 		cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n",
402603831d35Sstevel 		    gdcd->h.dcd_magic);
402703831d35Sstevel 
402803831d35Sstevel 		kmem_free(gdcd, sizeof (gdcd_t));
402903831d35Sstevel 		return (RSV_UNDEFINED);
403003831d35Sstevel 	}
403103831d35Sstevel 
403203831d35Sstevel 	if (gdcd->h.dcd_version != DCD_VERSION) {
403303831d35Sstevel 		cmn_err(CE_WARN, "schpc: GDCD Bad Version: "
403403831d35Sstevel 		    "GDCD Version 0x%x Expecting 0x%x\n",
403503831d35Sstevel 		    gdcd->h.dcd_version, DCD_VERSION);
403603831d35Sstevel 
403703831d35Sstevel 		kmem_free(gdcd, sizeof (gdcd_t));
403803831d35Sstevel 		return (RSV_UNDEFINED);
403903831d35Sstevel 	}
404003831d35Sstevel 
404103831d35Sstevel 	if (slot < 2)
404203831d35Sstevel 		prd_slot = 4;
404303831d35Sstevel 	else
404403831d35Sstevel 		prd_slot = 5;
404503831d35Sstevel 
404603831d35Sstevel 	bus = slot & 0x1;
404703831d35Sstevel 
404803831d35Sstevel 	status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0];
404903831d35Sstevel 
405003831d35Sstevel 	kmem_free(gdcd, sizeof (gdcd_t));
405103831d35Sstevel 
405203831d35Sstevel 	SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
405303831d35Sstevel 	    "prd_slot=%d bus=%d status=%d", prd_slot, bus, status);
405403831d35Sstevel 
405503831d35Sstevel 	return (status);
405603831d35Sstevel }
405703831d35Sstevel 
405803831d35Sstevel #define	LEAF_SAVE_END			0xff
405903831d35Sstevel 
406003831d35Sstevel typedef struct {
406103831d35Sstevel 	int	reg;
406203831d35Sstevel 	int	offset;
406303831d35Sstevel 	int	access_size;
406403831d35Sstevel 	int	number;
406503831d35Sstevel } save_reg_list_t;
406603831d35Sstevel 
406703831d35Sstevel /*
406803831d35Sstevel  * Save List Array.  Describes the leaf registers that need to
406903831d35Sstevel  * be restored after a leaf reset.
407003831d35Sstevel  *
407103831d35Sstevel  * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space
407203831d35Sstevel  * Entry 2 - Offset Start
407303831d35Sstevel  * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit
407403831d35Sstevel  * Entry 4 - # of registers to be saved starting at offset,
407503831d35Sstevel  */
407603831d35Sstevel save_reg_list_t	save_reg_list[] = {	0, 0x110, 8, 1,
407703831d35Sstevel 					0, 0x200, 8, 2,
407803831d35Sstevel 					0, 0x1000, 8, 0x18,
407903831d35Sstevel 					0, 0x1a00, 8, 1,
408003831d35Sstevel 					0, 0x2000, 8, 1,
408103831d35Sstevel 					0, 0x2020, 8, 1,
408203831d35Sstevel 					0, 0x2040, 8, 1,
408303831d35Sstevel 					0, 0x2308, 8, 2,
408403831d35Sstevel 					0, 0x2800, 8, 1,
408503831d35Sstevel 					2, 0x04, 2, 1,		/* Command */
408603831d35Sstevel 					2, 0x0d, 1, 1,		/* Latency */
408703831d35Sstevel 					2, 0x40, 1, 1,		/* Bus # */
408803831d35Sstevel 					2, 0x41, 1, 1,		/* Sub. Bus # */
408903831d35Sstevel 					LEAF_SAVE_END, 0, 0, 0};
409003831d35Sstevel 
409103831d35Sstevel static int
schpc_save_leaf(int slot)409203831d35Sstevel schpc_save_leaf(int slot)
409303831d35Sstevel {
409403831d35Sstevel 	int		save_entry, list_entry, reg;
409503831d35Sstevel 	caddr_t		leaf_regs;
409603831d35Sstevel 	ddi_device_acc_attr_t attr;
409703831d35Sstevel 
409803831d35Sstevel 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
409903831d35Sstevel 
410003831d35Sstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
410103831d35Sstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
410203831d35Sstevel 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
410303831d35Sstevel 
410403831d35Sstevel 	/*
410503831d35Sstevel 	 * Map in the 3 addresses spaces defined for XMITS.
410603831d35Sstevel 	 */
410703831d35Sstevel 	for (reg = 0; reg < 3; reg++) {
410803831d35Sstevel 		if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg,
410903831d35Sstevel 		    &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot].
411003831d35Sstevel 		    saved_handle[reg]) != DDI_SUCCESS) {
411103831d35Sstevel 			cmn_err(CE_WARN, "Mapin failed\n");
411203831d35Sstevel 			schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
411303831d35Sstevel 			return (1);
411403831d35Sstevel 		}
411503831d35Sstevel 
411603831d35Sstevel 		schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs;
411703831d35Sstevel 	}
411803831d35Sstevel 
411903831d35Sstevel 
412003831d35Sstevel 	/*
412103831d35Sstevel 	 * Determine how many entries are in the list so we can
412203831d35Sstevel 	 * allocate the save space.
412303831d35Sstevel 	 */
412403831d35Sstevel 	list_entry = 0;
412503831d35Sstevel 	save_entry = 0;
412603831d35Sstevel 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
412703831d35Sstevel 		save_entry += save_reg_list[list_entry].number;
412803831d35Sstevel 		list_entry++;
412903831d35Sstevel 	}
413003831d35Sstevel 
413103831d35Sstevel 	schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t));
413203831d35Sstevel 
413303831d35Sstevel 	if (schpc_p->schpc_slot[slot].saved_size == 0)
413403831d35Sstevel 		return (0);
413503831d35Sstevel 
413603831d35Sstevel 	schpc_p->schpc_slot[slot].saved_regs =
413703831d35Sstevel 	    (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size,
413803831d35Sstevel 	    KM_SLEEP);
413903831d35Sstevel 
414003831d35Sstevel 	/*
414103831d35Sstevel 	 * Walk through the register list and save contents.
414203831d35Sstevel 	 */
414303831d35Sstevel 	list_entry = 0;
414403831d35Sstevel 	save_entry = 0;
414503831d35Sstevel 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
414603831d35Sstevel 		schpc_save_entry(slot, list_entry, save_entry);
414703831d35Sstevel 		save_entry += save_reg_list[list_entry].number;
414803831d35Sstevel 		list_entry ++;
414903831d35Sstevel 	}
415003831d35Sstevel 
415103831d35Sstevel 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
415203831d35Sstevel 
415303831d35Sstevel 	return (0);
415403831d35Sstevel }
415503831d35Sstevel 
415603831d35Sstevel static void
schpc_restore_leaf(int slot)415703831d35Sstevel schpc_restore_leaf(int slot)
415803831d35Sstevel {
415903831d35Sstevel 	int	save_entry, list_entry, reg;
416003831d35Sstevel 
416103831d35Sstevel 	if (schpc_p->schpc_slot[slot].saved_regs == NULL)
416203831d35Sstevel 		return;
416303831d35Sstevel 
416403831d35Sstevel 	/*
416503831d35Sstevel 	 * Walk through the register list and restore contents.
416603831d35Sstevel 	 */
416703831d35Sstevel 	list_entry = 0;
416803831d35Sstevel 	save_entry = 0;
416903831d35Sstevel 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
417003831d35Sstevel 
417103831d35Sstevel 		schpc_restore_entry(slot, list_entry, save_entry);
417203831d35Sstevel 
417303831d35Sstevel 		save_entry += save_reg_list[list_entry].number;
417403831d35Sstevel 		list_entry ++;
417503831d35Sstevel 	}
417603831d35Sstevel 
417703831d35Sstevel 	/*
417803831d35Sstevel 	 * Free the mapped in registers.
417903831d35Sstevel 	 */
418003831d35Sstevel 	for (reg = 0; reg < 3; reg++) {
418103831d35Sstevel 		if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) {
418203831d35Sstevel 
418303831d35Sstevel 			ddi_regs_map_free(
418403831d35Sstevel 			    &schpc_p->schpc_slot[slot].saved_handle[reg]);
418503831d35Sstevel 
418603831d35Sstevel 			schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
418703831d35Sstevel 		}
418803831d35Sstevel 	}
418903831d35Sstevel 
419003831d35Sstevel 	kmem_free(schpc_p->schpc_slot[slot].saved_regs,
419103831d35Sstevel 	    schpc_p->schpc_slot[slot].saved_size);
419203831d35Sstevel 
419303831d35Sstevel 	schpc_p->schpc_slot[slot].saved_size = 0;
419403831d35Sstevel 	schpc_p->schpc_slot[slot].saved_regs = NULL;
419503831d35Sstevel 
419603831d35Sstevel 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot);
419703831d35Sstevel }
419803831d35Sstevel 
419903831d35Sstevel static void
schpc_save_entry(int slot,int list_entry,int save_entry)420003831d35Sstevel schpc_save_entry(int slot, int list_entry, int save_entry)
420103831d35Sstevel {
420203831d35Sstevel 	int reg, reads = 0;
420303831d35Sstevel 
420403831d35Sstevel 	reg = save_reg_list[list_entry].reg;
420503831d35Sstevel 
420603831d35Sstevel 	while (reads < save_reg_list[list_entry].number) {
420703831d35Sstevel 		switch (save_reg_list[list_entry].access_size) {
420803831d35Sstevel 		case 8:
420903831d35Sstevel 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
421003831d35Sstevel 			    ddi_get64(
421103831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_handle[reg],
421203831d35Sstevel 			    (uint64_t *)(schpc_p->schpc_slot[slot].
421303831d35Sstevel 			    saved_regs_va[reg]
421403831d35Sstevel 			    + save_reg_list[list_entry].offset +
421503831d35Sstevel 			    (reads * sizeof (uint64_t))));
421603831d35Sstevel #ifdef DEBUG
421703831d35Sstevel 			if (schpc_dump_save_regs)
421803831d35Sstevel 				cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg,
421903831d35Sstevel 				    save_reg_list[list_entry].offset +
422003831d35Sstevel 				    (reads * sizeof (uint64_t)),
422103831d35Sstevel 				    schpc_p->schpc_slot[slot].
422203831d35Sstevel 				    saved_regs[save_entry]);
422303831d35Sstevel #endif
422403831d35Sstevel 
422503831d35Sstevel 			break;
422603831d35Sstevel 		case 4:
422703831d35Sstevel 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
422803831d35Sstevel 			    ddi_get32(
422903831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_handle[reg],
423003831d35Sstevel 			    (uint32_t *)(schpc_p->schpc_slot[slot].
423103831d35Sstevel 			    saved_regs_va[reg]
423203831d35Sstevel 			    + save_reg_list[list_entry].offset +
423303831d35Sstevel 			    (reads * sizeof (uint32_t))));
423403831d35Sstevel 
423503831d35Sstevel #ifdef DEBUG
423603831d35Sstevel 			if (schpc_dump_save_regs)
423703831d35Sstevel 				cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg,
423803831d35Sstevel 				    save_reg_list[list_entry].offset +
423903831d35Sstevel 				    (reads * sizeof (uint32_t)),
424003831d35Sstevel 				    schpc_p->schpc_slot[slot].
424103831d35Sstevel 				    saved_regs[save_entry]);
424203831d35Sstevel #endif
424303831d35Sstevel 
424403831d35Sstevel 			break;
424503831d35Sstevel 		case 2:
424603831d35Sstevel 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
424703831d35Sstevel 			    ddi_get16(
424803831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_handle[reg],
424903831d35Sstevel 			    (uint16_t *)(schpc_p->schpc_slot[slot].
425003831d35Sstevel 			    saved_regs_va[reg]
425103831d35Sstevel 			    + save_reg_list[list_entry].offset +
425203831d35Sstevel 			    (reads * sizeof (uint16_t))));
425303831d35Sstevel 
425403831d35Sstevel #ifdef DEBUG
425503831d35Sstevel 			if (schpc_dump_save_regs)
425603831d35Sstevel 				cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg,
425703831d35Sstevel 				    save_reg_list[list_entry].offset +
425803831d35Sstevel 				    (reads * sizeof (uint16_t)),
425903831d35Sstevel 				    schpc_p->schpc_slot[slot].
426003831d35Sstevel 				    saved_regs[save_entry]);
426103831d35Sstevel #endif
426203831d35Sstevel 
426303831d35Sstevel 			break;
426403831d35Sstevel 		case 1:
426503831d35Sstevel 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
426603831d35Sstevel 			    ddi_get8(
426703831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_handle[reg],
426803831d35Sstevel 			    (uint8_t *)(schpc_p->schpc_slot[slot].
426903831d35Sstevel 			    saved_regs_va[reg]
427003831d35Sstevel 			    + save_reg_list[list_entry].offset +
427103831d35Sstevel 			    (reads * sizeof (uint8_t))));
427203831d35Sstevel 
427303831d35Sstevel #ifdef DEBUG
427403831d35Sstevel 			if (schpc_dump_save_regs)
427503831d35Sstevel 				cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg,
427603831d35Sstevel 				    save_reg_list[list_entry].offset +
427703831d35Sstevel 				    (reads * sizeof (uint8_t)),
427803831d35Sstevel 				    schpc_p->schpc_slot[slot].
427903831d35Sstevel 				    saved_regs[save_entry]);
428003831d35Sstevel #endif
428103831d35Sstevel 
428203831d35Sstevel 			break;
428303831d35Sstevel 		default:
428403831d35Sstevel 			cmn_err(CE_WARN,
428503831d35Sstevel 			    "schpc: Illegal List Entry\n");
428603831d35Sstevel 		}
428703831d35Sstevel 		reads++;
428803831d35Sstevel 		save_entry++;
428903831d35Sstevel 	}
429003831d35Sstevel }
429103831d35Sstevel 
429203831d35Sstevel static void
schpc_restore_entry(int slot,int list_entry,int save_entry)429303831d35Sstevel schpc_restore_entry(int slot, int list_entry, int save_entry)
429403831d35Sstevel {
429503831d35Sstevel 	int reg, writes = 0;
429603831d35Sstevel 
429703831d35Sstevel 	reg = save_reg_list[list_entry].reg;
429803831d35Sstevel 
429903831d35Sstevel 	while (writes < save_reg_list[list_entry].number) {
430003831d35Sstevel 		switch (save_reg_list[list_entry].access_size) {
430103831d35Sstevel 		case 8:
430203831d35Sstevel #ifdef DEBUG
430303831d35Sstevel 			if (schpc_dump_save_regs)
430403831d35Sstevel 				cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg,
430503831d35Sstevel 				    save_reg_list[list_entry].offset +
430603831d35Sstevel 				    (writes * sizeof (uint64_t)),
430703831d35Sstevel 				    schpc_p->schpc_slot[slot].
430803831d35Sstevel 				    saved_regs[save_entry]);
430903831d35Sstevel #endif
431003831d35Sstevel 
431103831d35Sstevel 			ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg],
431203831d35Sstevel 			    (uint64_t *)(schpc_p->schpc_slot[slot].
431303831d35Sstevel 			    saved_regs_va[reg]
431403831d35Sstevel 			    + save_reg_list[list_entry].offset +
431503831d35Sstevel 			    (writes * sizeof (uint64_t))),
431603831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
431703831d35Sstevel 
431803831d35Sstevel 			break;
431903831d35Sstevel 		case 4:
432003831d35Sstevel #ifdef DEBUG
432103831d35Sstevel 			if (schpc_dump_save_regs)
432203831d35Sstevel 				cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg,
432303831d35Sstevel 				    save_reg_list[list_entry].offset +
432403831d35Sstevel 				    (writes * sizeof (uint32_t)),
432503831d35Sstevel 				    schpc_p->schpc_slot[slot].
432603831d35Sstevel 				    saved_regs[save_entry]);
432703831d35Sstevel #endif
432803831d35Sstevel 
432903831d35Sstevel 			ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg],
433003831d35Sstevel 			    (uint32_t *)(schpc_p->schpc_slot[slot].
433103831d35Sstevel 			    saved_regs_va[reg]
433203831d35Sstevel 			    + save_reg_list[list_entry].offset +
433303831d35Sstevel 			    (writes * sizeof (uint32_t))),
433403831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
433503831d35Sstevel 
433603831d35Sstevel 			break;
433703831d35Sstevel 		case 2:
433803831d35Sstevel #ifdef DEBUG
433903831d35Sstevel 			if (schpc_dump_save_regs)
434003831d35Sstevel 				cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg,
434103831d35Sstevel 				    save_reg_list[list_entry].offset +
434203831d35Sstevel 				    (writes * sizeof (uint16_t)),
434303831d35Sstevel 				    schpc_p->schpc_slot[slot].
434403831d35Sstevel 				    saved_regs[save_entry]);
434503831d35Sstevel #endif
434603831d35Sstevel 
434703831d35Sstevel 			ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg],
434803831d35Sstevel 			    (uint16_t *)(schpc_p->schpc_slot[slot].
434903831d35Sstevel 			    saved_regs_va[reg]
435003831d35Sstevel 			    + save_reg_list[list_entry].offset +
435103831d35Sstevel 			    (writes * sizeof (uint16_t))),
435203831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
435303831d35Sstevel 
435403831d35Sstevel 			break;
435503831d35Sstevel 		case 1:
435603831d35Sstevel #ifdef DEBUG
435703831d35Sstevel 			if (schpc_dump_save_regs)
435803831d35Sstevel 				cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg,
435903831d35Sstevel 				    save_reg_list[list_entry].offset +
436003831d35Sstevel 				    (writes * sizeof (uint8_t)),
436103831d35Sstevel 				    schpc_p->schpc_slot[slot].
436203831d35Sstevel 				    saved_regs[save_entry]);
436303831d35Sstevel #endif
436403831d35Sstevel 
436503831d35Sstevel 			ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg],
436603831d35Sstevel 			    (uint8_t *)(schpc_p->schpc_slot[slot].
436703831d35Sstevel 			    saved_regs_va[reg]
436803831d35Sstevel 			    + save_reg_list[list_entry].offset +
436903831d35Sstevel 			    (writes * sizeof (uint8_t))),
437003831d35Sstevel 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
437103831d35Sstevel 
437203831d35Sstevel 			break;
437303831d35Sstevel 		default:
437403831d35Sstevel 			cmn_err(CE_WARN,
437503831d35Sstevel 			    "schpc: Illegal List Entry\n");
437603831d35Sstevel 		}
437703831d35Sstevel 		writes++;
437803831d35Sstevel 		save_entry++;
437903831d35Sstevel 	}
438003831d35Sstevel }
438103831d35Sstevel 
438203831d35Sstevel /*
438303831d35Sstevel  * Returns TRUE if a leaf reset is required to change frequencies/mode.
438403831d35Sstevel  */
438503831d35Sstevel static int
schpc_is_leaf_reset_required(int slot)438603831d35Sstevel schpc_is_leaf_reset_required(int slot)
438703831d35Sstevel {
438803831d35Sstevel 	char *name;
438903831d35Sstevel 	int32_t mod_rev;
439003831d35Sstevel 
439103831d35Sstevel 	/*
439203831d35Sstevel 	 * Only XMITS 3.0 and greater connected slots will require a
439303831d35Sstevel 	 * reset to switch frequency and/or mode.
439403831d35Sstevel 	 */
439503831d35Sstevel 	name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
439603831d35Sstevel 
439703831d35Sstevel 	if (strcmp(name, "pci108e,8002") == 0) {
439803831d35Sstevel 		mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
439903831d35Sstevel 		    schpc_p->schpc_slot[slot].devi,
440003831d35Sstevel 		    DDI_PROP_DONTPASS, "module-revision#", 0);
440103831d35Sstevel 
440203831d35Sstevel 		SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
440303831d35Sstevel 
440403831d35Sstevel 		/*
440503831d35Sstevel 		 * Check for XMITS 3.0 or greater.
440603831d35Sstevel 		 */
440703831d35Sstevel 		if (mod_rev >= XMITS_30) {
440803831d35Sstevel 
440903831d35Sstevel 			/*
441003831d35Sstevel 			 * The leaf attached to C5V0 (slot 1) should
441103831d35Sstevel 			 * not be reset.
441203831d35Sstevel 			 */
441303831d35Sstevel 			if ((slot & 3) == 1) {
441403831d35Sstevel 
441503831d35Sstevel 				SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
441603831d35Sstevel 				    "Not Required - C5V0", slot);
441703831d35Sstevel 
441803831d35Sstevel 				return (0);
441903831d35Sstevel 			}
442003831d35Sstevel 
442103831d35Sstevel 			SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
442203831d35Sstevel 			    "Required", slot);
442303831d35Sstevel 
442403831d35Sstevel 			return (1);
442503831d35Sstevel 		}
442603831d35Sstevel 	}
442703831d35Sstevel 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot);
442803831d35Sstevel 
442903831d35Sstevel 	return (0);
443003831d35Sstevel }
443103831d35Sstevel 
443203831d35Sstevel /*
443303831d35Sstevel  * Returns TRUE if the bus can change frequencies.
443403831d35Sstevel  */
443503831d35Sstevel static int
schpc_is_freq_switchable(int slot)443603831d35Sstevel schpc_is_freq_switchable(int slot)
443703831d35Sstevel {
443803831d35Sstevel 	char *name;
443903831d35Sstevel 	int32_t mod_rev;
444003831d35Sstevel 
444103831d35Sstevel 	name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
444203831d35Sstevel 
444303831d35Sstevel 	if (strcmp(name, "pci108e,8002") == 0) {
444403831d35Sstevel 		mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
444503831d35Sstevel 		    schpc_p->schpc_slot[slot].devi,
444603831d35Sstevel 		    DDI_PROP_DONTPASS, "module-revision#", 0);
444703831d35Sstevel 
444803831d35Sstevel 		SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
444903831d35Sstevel 
445003831d35Sstevel 		/*
445103831d35Sstevel 		 * We will only report back that XMITS 2.0 (mod_rev = 2)
445203831d35Sstevel 		 * or greater will have the ability to switch frequencies.
445303831d35Sstevel 		 */
445403831d35Sstevel 		if (mod_rev >= XMITS_20) {
445503831d35Sstevel 			SCHPC_DEBUG1(D_FREQCHG, "Slot %d - "
445603831d35Sstevel 			    "Frequency is switchable", slot);
445703831d35Sstevel 			return (1);
445803831d35Sstevel 		}
445903831d35Sstevel 	}
446003831d35Sstevel 
446103831d35Sstevel 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot);
446203831d35Sstevel 	return (0);
446303831d35Sstevel }
446403831d35Sstevel 
446503831d35Sstevel /*
446603831d35Sstevel  * schpc_slot_freq
446703831d35Sstevel  *
446803831d35Sstevel  * Convert the slot frequency setting to integer value.
446903831d35Sstevel  */
447003831d35Sstevel static int
schpc_slot_freq(pci_getslot_t * getslotp)447103831d35Sstevel schpc_slot_freq(pci_getslot_t *getslotp)
447203831d35Sstevel {
447303831d35Sstevel 	switch (getslotp->slot_freq_setting) {
447403831d35Sstevel 	case PCIMSG_FREQ_33MHZ:
447503831d35Sstevel 		return (SCHPC_33MHZ);
447603831d35Sstevel 	case PCIMSG_FREQ_66MHZ:
447703831d35Sstevel 		return (SCHPC_66MHZ);
447803831d35Sstevel 	case PCIMSG_FREQ_90MHZ:
447903831d35Sstevel 		return (SCHPC_90MHZ);
448003831d35Sstevel 	case PCIMSG_FREQ_133MHZ:
448103831d35Sstevel 		return (SCHPC_133MHZ);
448203831d35Sstevel 	default:
448303831d35Sstevel 		return (0);
448403831d35Sstevel 	}
448503831d35Sstevel }
448603831d35Sstevel 
448703831d35Sstevel /*
448803831d35Sstevel  * schpc_find_dip
448903831d35Sstevel  *
449003831d35Sstevel  * Used by ddi_walk_devs to find the dip which belongs
449103831d35Sstevel  * to a certain slot.
449203831d35Sstevel  *
449303831d35Sstevel  * When this function returns, the dip is held.  It is the
449403831d35Sstevel  * responsibility of the caller to release the dip.
449503831d35Sstevel  */
449603831d35Sstevel static int
schpc_find_dip(dev_info_t * dip,void * arg)449703831d35Sstevel schpc_find_dip(dev_info_t *dip, void *arg)
449803831d35Sstevel {
449903831d35Sstevel 	find_dev_t	*find_dev = (find_dev_t *)arg;
450003831d35Sstevel 	char		*pathname = find_dev->caddr;
450103831d35Sstevel 
450203831d35Sstevel 	(void) ddi_pathname(dip, pathname);
450303831d35Sstevel 	if (strcmp(find_dev->cname, pathname) == 0) {
450403831d35Sstevel 		ndi_hold_devi(dip);
450503831d35Sstevel 		find_dev->dip = dip;
450603831d35Sstevel 		return (DDI_WALK_TERMINATE);
450703831d35Sstevel 	}
450803831d35Sstevel 	return (DDI_WALK_CONTINUE);
450903831d35Sstevel }
4510