xref: /titanic_50/usr/src/uts/sun4u/starcat/io/schpc.c (revision 5a57ddbbc80b8fbfbb5b30c31ccbca268c5c056d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 /*
29  * Starcat IOSRAM/Tunnel PCI Hot Plug Controller Driver
30  */
31 
32 #define	CPCI_ENUM
33 
34 #include <sys/note.h>
35 #include <sys/types.h>
36 #include <sys/cmn_err.h>
37 #include <sys/kmem.h>
38 #include <sys/errno.h>
39 #include <sys/open.h>
40 #include <sys/stat.h>
41 #include <sys/conf.h>
42 #include <sys/ddi.h>
43 #include <sys/cmn_err.h>
44 #include <sys/sunddi.h>
45 #include <sys/sunndi.h>
46 #include <sys/ddi_impldefs.h>
47 #include <sys/ndi_impldefs.h>
48 #include <sys/modctl.h>
49 #include <sys/disp.h>
50 #include <sys/async.h>
51 #include <sys/hotplug/hpcsvc.h>
52 #include <sys/mboxsc.h>
53 #include <sys/schpc_msg.h>
54 #include <sys/schpc.h>
55 #include <post/scat_dcd.h>
56 #include <sys/taskq.h>
57 
58 #ifdef DEBUG
59 int schpc_dump_save_regs = 0;
60 static uint_t schpc_debug_flags = 0;
61 #define	SCHPC_DEBUG0(f, s) if ((f)& schpc_debug_flags) \
62 	cmn_err(CE_CONT, "schpc: " s "\n")
63 #define	SCHPC_DEBUG1(f, s, a) if ((f)& schpc_debug_flags) \
64 	cmn_err(CE_CONT, "schpc: " s "\n", a)
65 #define	SCHPC_DEBUG2(f, s, a, b) if ((f)& schpc_debug_flags) \
66 	cmn_err(CE_CONT, "schpc: " s "\n", a, b)
67 #define	SCHPC_DEBUG3(f, s, a, b, c) if ((f)& schpc_debug_flags) \
68 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c)
69 #define	SCHPC_DEBUG4(f, s, a, b, c, d) if ((f)& schpc_debug_flags) \
70 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d)
71 #define	SCHPC_DEBUG5(f, s, a, b, c, d, e) if ((f)& schpc_debug_flags) \
72 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e)
73 #define	SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& schpc_debug_flags) \
74 	cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e, ff)
75 #else
76 
77 #define	SCHPC_DEBUG0(f, s)
78 #define	SCHPC_DEBUG1(f, s, a)
79 #define	SCHPC_DEBUG2(f, s, a, b)
80 #define	SCHPC_DEBUG3(f, s, a, b, c)
81 #define	SCHPC_DEBUG4(f, s, a, b, c, d)
82 #define	SCHPC_DEBUG5(f, s, a, b, c, d, e)
83 #define	SCHPC_DEBUG6(f, s, a, b, c, d, e, ff)
84 
85 #endif
86 
87 #define	D_IDENTIFY	0x00000001
88 #define	D_ATTACH	0x00000002
89 #define	D_DETACH	0x00000004
90 #define	D_OPEN		0x00000008
91 #define	D_GETSLOTSTATUS	0x00000010
92 #define	D_SETSLOTSTATUS	0x00000020
93 #define	D_IOCTL		0x00010000
94 #define	D_IOC_CONNECT	0x00020000
95 #define	D_IOC_CONTROL	0x00040000
96 #define	D_IOC_CONFIG	0x00080000
97 #define	D_IOC_STATUS	0x00100000
98 #define	D_IOC_MSG	0x00200000
99 #define	D_IOC_TEST	0x00400000
100 #define	D_IOC_LED	0x00800000
101 #define	D_EVENT		0x01000000
102 #define	D_THREAD	0x02000000
103 #define	D_TRANSID	0x04000000
104 #define	D_SLOTTABLE	0x08000000
105 #define	D_FREQCHG	0x10000000
106 #define	D_APID		0x20000000
107 
108 /*
109  * driver global data:
110  */
111 static void *per_schpc_state;		/* soft state head */
112 dev_info_t *schpc_devi;
113 static schpc_t	*schpc_p;
114 
115 clock_t schpc_timeout_putmsg = 60 * 1000; /* 60 seconds */
116 clock_t schpc_timeout_getmsg = 60 * 1000; /* 60 seconds */
117 clock_t schpc_timeout_event = 60 * 5 * 1000; /* 5 minutes */
118 
119 int schpc_use_legacy_apid = 0;
120 
121 static mboxsc_timeout_range_t schpc_putmsg_timeout_range;
122 static mboxsc_timeout_range_t schpc_getmsg_timeout_range;
123 
124 static taskq_t *schpc_event_taskq = NULL;
125 
126 /*
127  * replies to mboxsc_getmsg() are handled asynchronously by the
128  * schpc_msg_thread using a linked list of schpc_replylist_t
129  * elements
130  */
131 typedef struct schpc_replylist {
132 	struct schpc_replylist	*prev;		/* link to previous entry */
133 	struct schpc_replylist	*next;		/* link to next entry */
134 	kcondvar_t		reply_cv;	/* condvar for getting reply */
135 	kmutex_t		reply_lock;	/* mutex for getting reply */
136 	uint32_t		type;		/* mboxsc_xxxmsg() msg type */
137 	uint32_t		cmd;		/* mboxsc_xxxmsg() cmd */
138 	uint64_t		transid;	/* mboxsc_xxxmsg() trans id */
139 	uint32_t		length;		/* mboxsc_xxxmsg() length */
140 	pcimsg_t		reply;		/* mboxsc_xxxmsg() reply msg */
141 	boolean_t		reply_recvd;	/* msg reply received */
142 	boolean_t		reply_cexit;	/* client early exit */
143 } schpc_replylist_t;
144 
145 static kmutex_t schpc_replylist_mutex; /* replylist mutex */
146 static uint32_t schpc_replylist_count; /* replylist size */
147 static schpc_replylist_t *schpc_replylist_first; /* replylist 1st elem */
148 static schpc_replylist_t *schpc_replylist_last; /* replylist last elem */
149 static boolean_t slots_registered = B_FALSE; /* slots registered? */
150 
151 typedef struct {
152 	char		*cname;
153 	char		*caddr;
154 	char		schizo;
155 	char		leaf;
156 	dev_info_t	*dip;
157 } find_dev_t;
158 
159 /*
160  * Function prototypes for local functions
161  */
162 static int schpc_getexpander(dev_info_t *);
163 static int schpc_getboard(dev_info_t *);
164 static void schpc_event_handler(void *);
165 static void schpc_event_filter(pcimsg_t	*msg);
166 static void schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
167 				uint64_t transid, uint32_t length);
168 static uint64_t schpc_gettransid(schpc_t *, int);
169 static int schpc_slot_get_index(schpc_t *, hpc_slot_t);
170 static void schpc_register_all_slots(schpc_t *);
171 static void schpc_setslotled(int, int, int, uint32_t);
172 static void schpc_init_setslot_message(pci_setslot_t *);
173 static void schpc_test(caddr_t, int, void *, uint_t);
174 static int schpc_getslotstatus(uint32_t, uint32_t, uint32_t, pci_getslot_t *);
175 static int schpc_setslotstatus(uint32_t, uint32_t, uint32_t,  pci_setslot_t *);
176 static int schpc_match_dip(dev_info_t *, void *);
177 static void schpc_buildapid(dev_info_t *, int, char *);
178 static int schpc_get_slot_status(uint_t, uint_t, uint_t);
179 static void schpc_replylist_unlink(schpc_replylist_t *entry);
180 static schpc_replylist_t *schpc_replylist_link(uint32_t cmd, uint64_t transid,
181 						uint32_t length);
182 static void schpc_msg_thread(void);
183 static int schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd,
184 				uint64_t *transidp, uint32_t length,
185 				void *datap, clock_t timeout,
186 				schpc_replylist_t **entryp);
187 static int schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
188 			uint64_t *transidp, uint32_t *lengthp, void *datap,
189 			clock_t timeout, schpc_replylist_t *listp);
190 
191 static int schpc_slot_freq(pci_getslot_t *);
192 static int schpc_find_dip(dev_info_t *, void *);
193 
194 static int schpc_save_leaf(int slot);
195 static void schpc_restore_leaf(int slot);
196 static int schpc_is_leaf_reset_required(int slot);
197 static int schpc_is_freq_switchable(int slot);
198 static void schpc_save_entry(int slot, int list_entry, int save_entry);
199 static void schpc_restore_entry(int slot, int list_entry, int save_entry);
200 
201 /*
202  * Function prototype for Hot Plug Services
203  */
204 static int schpc_connect(caddr_t, hpc_slot_t, void *, uint_t);
205 static int schpc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
206 static int schpc_cpci_control(caddr_t, hpc_slot_t, int, caddr_t);
207 static int schpc_pci_control(caddr_t, hpc_slot_t, int, caddr_t);
208 
209 extern int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t);
210 
211 /*
212  * cb_ops and dev_ops:
213  */
214 static struct cb_ops schpc_cb_ops = {
215 	nodev,			/* open */
216 	nodev,			/* close */
217 	nodev,			/* strategy */
218 	nodev,			/* print */
219 	nodev,			/* dump */
220 	nodev,			/* read */
221 	nodev,			/* write */
222 	nodev,			/* ioctl */
223 	nodev,			/* devmap */
224 	nodev,			/* mmap */
225 	nodev,			/* segmap */
226 	nochpoll,		/* poll */
227 	ddi_prop_op,		/* prop_op */
228 	0,			/* streamtab  */
229 	D_NEW | D_MP | D_HOTPLUG /* Driver compatibility flag */
230 };
231 
232 /*
233  * Function prototype for dev_ops
234  */
235 static int schpc_attach(dev_info_t *, ddi_attach_cmd_t);
236 static int schpc_detach(dev_info_t *, ddi_detach_cmd_t);
237 static int schpc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
238 
239 static struct dev_ops schpc_dev_ops = {
240 	DEVO_REV,			/* devo_rev, */
241 	0,				/* refcnt  */
242 	schpc_info,			/* get_dev_info */
243 	nulldev,			/* identify */
244 	nulldev,			/* probe */
245 	schpc_attach,			/* attach */
246 	schpc_detach,			/* detach */
247 	nodev,				/* reset */
248 	&schpc_cb_ops,			/* driver operations */
249 	(struct bus_ops *)0,		/* no bus operations */
250 	NULL,				/* power */
251 	ddi_quiesce_not_supported,	/* devo_quiesce */
252 };
253 
254 /*
255  * loadable module declarations:
256  */
257 static struct modldrv modldrv = {
258 	&mod_driverops,
259 	"PCI Hot Plug Controller Driver (schpc)",
260 	&schpc_dev_ops,
261 };
262 
263 static struct modlinkage modlinkage = {
264 	MODREV_1,
265 	(void *)&modldrv,
266 	NULL
267 };
268 
269 int
270 _init(void)
271 {
272 	int		ret;
273 	int		rv;
274 
275 	SCHPC_DEBUG0(D_ATTACH, "_init() installing module");
276 
277 	ret = ddi_soft_state_init(&per_schpc_state, sizeof (schpc_t), 1);
278 	if (ret != 0) {
279 		return (ret);
280 	}
281 
282 	/*
283 	 * Initialize Outgoing Mailbox.
284 	 */
285 	ret = mboxsc_init(KEY_PCSC, MBOXSC_MBOX_OUT, NULL);
286 
287 	if (ret != 0) {
288 		ddi_soft_state_fini(&per_schpc_state);
289 		return (ret);
290 	}
291 
292 	ret = mboxsc_ctrl(KEY_PCSC, MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE,
293 	    (void *) &schpc_putmsg_timeout_range);
294 
295 	if (ret != 0) {
296 		ddi_soft_state_fini(&per_schpc_state);
297 		return (ret);
298 	}
299 
300 	if (schpc_timeout_putmsg < schpc_putmsg_timeout_range.min_timeout) {
301 		schpc_timeout_putmsg = schpc_putmsg_timeout_range.min_timeout;
302 		cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
303 		    schpc_timeout_putmsg);
304 	}
305 
306 	if (schpc_timeout_putmsg > schpc_putmsg_timeout_range.max_timeout) {
307 		schpc_timeout_putmsg = schpc_putmsg_timeout_range.max_timeout;
308 		cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
309 		    schpc_timeout_putmsg);
310 	}
311 
312 	/*
313 	 * Create the schpc_event_taskq for MBOXSC_MSG_EVENT processing.
314 	 */
315 	schpc_event_taskq = taskq_create("schpc_event_taskq", 2,
316 	    minclsyspri, 4, 4, TASKQ_PREPOPULATE);
317 
318 	/*
319 	 * Initialize Incoming Mailbox.
320 	 * NOTE: the callback is null because the schpc_msg_thread will
321 	 * handle all incoming MBOXSC_MSG_EVENT and MBOXSC_MSG_REPLY
322 	 * messages.
323 	 */
324 	ret = mboxsc_init(KEY_SCPC, MBOXSC_MBOX_IN, NULL);
325 
326 	if (ret != 0) {
327 		cmn_err(CE_WARN, "schpc: can not initialize KEY_SCPC as "
328 		    "MBOXSC_MBOX_IN");
329 		ddi_soft_state_fini(&per_schpc_state);
330 		return (ret);
331 	}
332 
333 	ret = mboxsc_ctrl(KEY_SCPC, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE,
334 	    (void *) &schpc_getmsg_timeout_range);
335 
336 	if (ret != 0) {
337 		ddi_soft_state_fini(&per_schpc_state);
338 		return (ret);
339 	}
340 
341 	if (schpc_timeout_getmsg < schpc_getmsg_timeout_range.min_timeout) {
342 		schpc_timeout_getmsg = schpc_getmsg_timeout_range.min_timeout;
343 		cmn_err(CE_WARN, " schpc: resetting getmsg timeout to %ld\n",
344 		    schpc_timeout_getmsg);
345 	}
346 
347 	if (schpc_timeout_getmsg > schpc_getmsg_timeout_range.max_timeout) {
348 		schpc_timeout_getmsg = schpc_getmsg_timeout_range.max_timeout;
349 		cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
350 		    schpc_timeout_putmsg);
351 	}
352 
353 	if (schpc_timeout_event < schpc_getmsg_timeout_range.min_timeout) {
354 		schpc_timeout_event = schpc_getmsg_timeout_range.min_timeout;
355 		cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
356 		    schpc_timeout_event);
357 	}
358 
359 	if (schpc_timeout_event > schpc_getmsg_timeout_range.max_timeout) {
360 		schpc_timeout_event = schpc_getmsg_timeout_range.max_timeout;
361 		cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
362 		    schpc_timeout_event);
363 	}
364 
365 	ret = mod_install(&modlinkage);
366 	if (ret != 0) {
367 		if ((rv = mboxsc_fini(KEY_PCSC)) != 0) {
368 			cmn_err(CE_WARN, "schpc: _init() - "
369 			    "mboxsc_fini(KEY_PCSC) failed: 0x%x", rv);
370 		}
371 		if ((rv = mboxsc_fini(KEY_SCPC)) != 0) {
372 			cmn_err(CE_WARN, "schpc: _init() - "
373 			    "mboxsc_fini(KEY_SCPC) failed: 0x%x", rv);
374 		}
375 		taskq_destroy(schpc_event_taskq);
376 		ddi_soft_state_fini(&per_schpc_state);
377 		return (ret);
378 	}
379 
380 	SCHPC_DEBUG0(D_ATTACH, "_init() module installed");
381 
382 	/*
383 	 * Start the schpc_msg_thread to continuously monitor the
384 	 * MBOXSC_MBOX_IN mailbox for incoming MBOXSC_MSG_EVENTs and
385 	 * MBOXSC_MSG_REPLYs.
386 	 */
387 	mutex_init(&schpc_replylist_mutex, NULL, MUTEX_DRIVER, NULL);
388 	(void) thread_create(NULL, 0, schpc_msg_thread,
389 	    NULL, 0, &p0, TS_RUN, minclsyspri);
390 
391 	SCHPC_DEBUG0(D_ATTACH, "_init() started schpc_msg_thread");
392 
393 	return (ret);
394 }
395 
396 int
397 _fini(void)
398 {
399 	SCHPC_DEBUG0(D_ATTACH, "_fini()");
400 
401 	return (DDI_FAILURE);
402 }
403 
404 int
405 _info(struct modinfo *modinfop)
406 {
407 	SCHPC_DEBUG0(D_ATTACH, "_info() called.");
408 
409 	return (mod_info(&modlinkage, modinfop));
410 }
411 
412 static int
413 schpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
414 {
415 	int		instance = ddi_get_instance(devi);
416 	int		rval;
417 
418 	SCHPC_DEBUG1(D_ATTACH, "attach(%x) ATTACH", instance);
419 
420 	switch (cmd) {
421 	case DDI_ATTACH:
422 
423 		/*
424 		 * Allocate the soft state structure for this instance.
425 		 */
426 		rval = ddi_soft_state_zalloc(per_schpc_state, instance);
427 
428 		if (rval != DDI_SUCCESS) {
429 			SCHPC_DEBUG1(D_ATTACH,
430 			    "schpc_attach(%x) Can not allocate "
431 			    "soft state structure", instance);
432 			return (DDI_FAILURE);
433 		}
434 
435 		schpc_p = (schpc_t *)ddi_get_soft_state(per_schpc_state,
436 		    instance);
437 
438 		if (schpc_p == NULL) {
439 			return (DDI_FAILURE);
440 		}
441 
442 		mutex_init(&schpc_p->schpc_mutex, NULL, MUTEX_DRIVER, NULL);
443 		cv_init(&schpc_p->schpc_cv, NULL, CV_DRIVER, NULL);
444 
445 		/*
446 		 * Put schpc structure on global linked list.
447 		 */
448 
449 		/*
450 		 * Initialize starting transaction ID.
451 		 */
452 		schpc_p->schpc_transid = 0;
453 
454 		schpc_p->schpc_number_of_slots = STARCAT_MAX_SLOTS;
455 
456 		SCHPC_DEBUG2(D_ATTACH, "schpc_attach(%x) slot-table property "
457 		    "describes %d slots", instance,
458 		    schpc_p->schpc_number_of_slots);
459 
460 		schpc_p->schpc_hotplugmodel = ddi_getprop(DDI_DEV_T_ANY,
461 		    devi, 0, "hot-plug-model", SCHPC_HOTPLUGTYPE_CPCIHOTPLUG);
462 
463 		SCHPC_DEBUG2(D_ATTACH, "attach(%x) ATTACH - Hot Plug Model=%x",
464 		    instance, schpc_p->schpc_hotplugmodel);
465 
466 		/*
467 		 * What type of hot plug do these slots support?  The only
468 		 * types of slots we support is the cPCI Hot Plug Model
469 		 * and Not Hot Pluggable.
470 		 */
471 		if (schpc_p->schpc_hotplugmodel !=
472 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
473 			schpc_p->schpc_hotplugmodel =
474 			    SCHPC_HOTPLUGTYPE_NOTHOTPLUGGABLE;
475 		}
476 
477 		schpc_p->schpc_slot = (schpc_slot_t *)kmem_zalloc((size_t)
478 		    (schpc_p->schpc_number_of_slots * sizeof (schpc_slot_t)),
479 		    KM_SLEEP);
480 
481 		schpc_p->schpc_devi = devi;
482 		schpc_p->schpc_instance = instance;
483 
484 		/*
485 		 * Start thread to search the device tree and register
486 		 * all found pci slots.
487 		 */
488 		(void) thread_create(NULL, 0, schpc_register_all_slots,
489 		    (void *)schpc_p, 0, &p0, TS_RUN, minclsyspri);
490 
491 		break;
492 
493 	case DDI_PM_RESUME:
494 	case DDI_RESUME:
495 		return (DDI_SUCCESS);
496 	default:
497 		cmn_err(CE_WARN, "schpc%d: Cmd != DDI_ATTACH/DDI_RESUME",
498 		    instance);
499 
500 		return (DDI_FAILURE);
501 	}
502 
503 	SCHPC_DEBUG1(D_ATTACH,
504 	    "schpc_attach(%x) Attach - DDI_SUCCESS", instance);
505 
506 	return (DDI_SUCCESS);
507 }
508 
509 /*ARGSUSED*/
510 static int
511 schpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
512 {
513 	int	instance = ddi_get_instance(devi);
514 
515 	SCHPC_DEBUG1(D_DETACH, "detach(%x) DETACH", instance);
516 
517 	return (DDI_FAILURE);
518 }
519 
520 /*ARGSUSED*/
521 static int
522 schpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
523 	void **result)
524 {
525 	int	error;
526 
527 	switch (infocmd) {
528 	case DDI_INFO_DEVT2DEVINFO:
529 		*result = (void *)schpc_devi;
530 		error = DDI_SUCCESS;
531 		break;
532 	case DDI_INFO_DEVT2INSTANCE:
533 		*result = (void *)0;
534 		error = DDI_SUCCESS;
535 		break;
536 	default:
537 		error = DDI_FAILURE;
538 	}
539 	return (error);
540 }
541 
542 /*
543  * schpc_connect()
544  *
545  * Called by Hot Plug Services to connect a slot to the bus.
546  */
547 
548 /*ARGSUSED*/
549 static int
550 schpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
551 {
552 	int		rval;
553 	int		expander, board;
554 	pci_setslot_t	setslot;
555 	pci_getslot_t	getslot;
556 	int		slot;
557 
558 	SCHPC_DEBUG2(D_IOC_CONNECT, "schpc_connect( ops_arg=%p slot_hdl=%p)",
559 	    ops_arg, slot_hdl);
560 
561 	mutex_enter(&schpc_p->schpc_mutex);
562 
563 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
564 
565 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
566 		SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect - HPC Not Inited");
567 		mutex_exit(&schpc_p->schpc_mutex);
568 		return (HPC_ERR_FAILED);
569 	}
570 
571 	/*
572 	 * Check to see if the slot is already connected.
573 	 */
574 	if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED) {
575 		mutex_exit(&schpc_p->schpc_mutex);
576 		return (0);
577 	}
578 
579 	/*
580 	 * Block if another thread is executing a HPC command.
581 	 */
582 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
583 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
584 	}
585 
586 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
587 
588 	mutex_exit(&schpc_p->schpc_mutex);
589 
590 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
591 	board = schpc_p->schpc_slot[slot].board; /* get board */
592 
593 	SCHPC_DEBUG3(D_IOC_CONNECT,
594 	    "schpc_connect Expander=%x Board=%x Slot=%x",
595 	    expander, board, SCHPC_SLOT_NUM(slot));
596 
597 
598 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_OCC_GOOD)) {
599 		cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
600 		    "connection on Expander %d Board %d Slot %d - "
601 		    "Ap_Id=%s : Occupant is in failed state",
602 		    expander, board, SCHPC_SLOT_NUM(slot),
603 		    schpc_p->schpc_slot[slot].ap_id);
604 
605 		/* Fault LED should already be illuminated */
606 
607 		goto failed;
608 	}
609 
610 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD)) {
611 		cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
612 		    "connection on Expander %d Board %d Slot %d - "
613 		    "Ap_Id=%s : Receptacle is in failed state",
614 		    expander, board, SCHPC_SLOT_NUM(slot),
615 		    schpc_p->schpc_slot[slot].ap_id);
616 
617 		/* Fault LED should already be illuminated */
618 
619 		goto failed;
620 	}
621 
622 	rval = schpc_getslotstatus(expander, board, slot, &getslot);
623 
624 	if (rval) {
625 		/*
626 		 * System Controller/Mailbox failure.
627 		 */
628 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
629 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
630 		    "Communicate with System Controller", expander, board,
631 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
632 
633 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
634 
635 		goto failed;
636 	}
637 
638 	if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
639 
640 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
641 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
642 		    "Read Slot Status", expander, board,
643 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
644 
645 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
646 
647 		goto failed;
648 	}
649 
650 	if (getslot.slot_empty) {
651 		/*
652 		 * If the slot is empty - fail the connection request.
653 		 */
654 		goto failed;
655 	}
656 
657 	SCHPC_DEBUG3(D_FREQCHG, "Slot %d - slot_freq_setting %d "
658 	    "slot_freq_cap %d", slot, getslot.slot_freq_setting,
659 	    getslot.slot_freq_cap);
660 
661 	if (!schpc_is_freq_switchable(slot) &&
662 	    (getslot.slot_freq_setting > getslot.slot_freq_cap)) {
663 
664 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
665 		    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
666 		    "Bus Speed Mismatch", expander,
667 		    board, SCHPC_SLOT_NUM(slot),
668 		    schpc_p->schpc_slot[slot].ap_id);
669 
670 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
671 
672 		goto failed;
673 	}
674 
675 	if (schpc_is_leaf_reset_required(slot) &&
676 	    (schpc_p->schpc_slot[slot].saved_regs == NULL)) {
677 
678 		SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Save Regs before connect",
679 		    slot);
680 
681 		/*
682 		 * A prior disconnect had not saved off the leaf so lets
683 		 * save it now. This is probably due to the domain being
684 		 * booted with a slot with no cassette.
685 		 */
686 		if (schpc_save_leaf(slot) != 0) {
687 			cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
688 
689 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
690 			    expander, board, slot & 3,
691 			    schpc_p->schpc_slot[slot].ap_id);
692 
693 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
694 
695 			goto failed;
696 		}
697 	}
698 
699 	/*
700 	 * Initialize Set Slot Command.
701 	 */
702 	schpc_init_setslot_message(&setslot);
703 
704 	setslot.slot_power_on = PCIMSG_ON;	   /* Turn slot power on */
705 
706 	setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash Fault LED */
707 
708 	rval = schpc_setslotstatus(expander, board, slot, &setslot);
709 
710 	if (rval != 0) {
711 		/*
712 		 * System Controller/Mailbox failure.
713 		 */
714 		cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
715 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
716 		    "Communicate with System Controller", expander, board,
717 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
718 
719 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
720 
721 		goto failed;
722 	}
723 
724 	if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
725 
726 		/*
727 		 * The Request was successfully completed.
728 		 */
729 
730 		SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect() - setslotstatus "
731 		    "succeeded");
732 
733 		/*
734 		 * Need to check HEALTHY# signal.
735 		 */
736 		rval = schpc_getslotstatus(expander, board, slot, &getslot);
737 
738 		if (rval) {
739 			/*
740 			 * System Controller/Mailbox failure.
741 			 */
742 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
743 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
744 			    "Unable to Communicate with System Controller",
745 			    expander, board, SCHPC_SLOT_NUM(slot),
746 			    schpc_p->schpc_slot[slot].ap_id);
747 
748 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
749 
750 			goto failed;
751 		}
752 
753 		if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
754 
755 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
756 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
757 			    "Unable to Read Slot Status", expander, board,
758 			    SCHPC_SLOT_NUM(slot),
759 			    schpc_p->schpc_slot[slot].ap_id);
760 
761 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
762 
763 			goto failed;
764 		}
765 
766 		if ((getslot.slot_powergood != PCIMSG_ON) ||
767 		    (getslot.slot_powerfault == PCIMSG_ON)) {
768 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
769 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
770 			    "Power failure detected", expander, board,
771 			    SCHPC_SLOT_NUM(slot),
772 			    schpc_p->schpc_slot[slot].ap_id);
773 
774 			/*
775 			 * Initialize Set Slot Command.
776 			 */
777 			schpc_init_setslot_message(&setslot);
778 
779 			/*
780 			 * Turn slot power off.
781 			 */
782 			setslot.slot_power_off = PCIMSG_ON;
783 
784 			(void) schpc_setslotstatus(expander, board,
785 			    slot, &setslot);
786 
787 			schpc_setslotled(expander, board, slot,
788 			    (SERVICE_LED_ON | FAULT_LED_ON));
789 
790 			goto failed;
791 		}
792 
793 		if (!getslot.slot_HEALTHY) {
794 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
795 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
796 			    "Adapter did not assert HEALTHY#", expander, board,
797 			    SCHPC_SLOT_NUM(slot),
798 			    schpc_p->schpc_slot[slot].ap_id);
799 
800 			/*
801 			 * Initialize Set Slot Command.
802 			 */
803 			schpc_init_setslot_message(&setslot);
804 
805 			/*
806 			 * Turn slot power off.
807 			 */
808 			setslot.slot_power_off = PCIMSG_ON;
809 
810 			(void) schpc_setslotstatus(expander, board, slot,
811 			    &setslot);
812 
813 			schpc_setslotled(expander, board, slot,
814 			    (SERVICE_LED_ON | FAULT_LED_ON));
815 
816 			goto failed;
817 		}
818 
819 		/*
820 		 * Initialize Set Slot Command.
821 		 */
822 		schpc_init_setslot_message(&setslot);
823 
824 		/*
825 		 * Start monitoring ENUM# and HEALTHY#
826 		 */
827 		setslot.slot_enable_HEALTHY = PCIMSG_ON;
828 		setslot.slot_enable_ENUM = PCIMSG_ON;
829 
830 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
831 
832 		if (rval != 0) {
833 			/*
834 			 * System Controller/Mailbox failure.
835 			 */
836 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
837 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
838 			    "Unable to Communicate with System Controller",
839 			    expander, board, SCHPC_SLOT_NUM(slot),
840 			    schpc_p->schpc_slot[slot].ap_id);
841 
842 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
843 
844 			goto failed;
845 		}
846 		if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
847 
848 			int		freq;
849 			find_dev_t	find_dev;
850 
851 			/*
852 			 * The Request was successfully completed.
853 			 */
854 
855 			SCHPC_DEBUG0(D_IOC_CONNECT,
856 			    "schpc_connect() - setslotstatus succeeded");
857 
858 			schpc_p->schpc_slot[slot].state |=
859 			    SCHPC_SLOTSTATE_CONNECTED;
860 
861 			schpc_setslotled(expander, board, slot,
862 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_OFF));
863 
864 			find_dev.cname = schpc_p->schpc_slot[slot].nexus_path;
865 			find_dev.caddr = (char *)kmem_alloc(MAXPATHLEN,
866 			    KM_SLEEP);
867 			find_dev.dip = NULL;
868 
869 			/* root node doesn't have to be held */
870 			ddi_walk_devs(ddi_root_node(), schpc_find_dip,
871 			    &find_dev);
872 			if (find_dev.dip != NULL) {
873 				/*
874 				 * Update the clock-frequency property to
875 				 * reflect the new slot-frequency.
876 				 */
877 				freq = schpc_slot_freq(&getslot);
878 				SCHPC_DEBUG2(D_FREQCHG,
879 				    "schpc_connect: updating dip=%p freq=%dHZ",
880 				    find_dev.dip, freq);
881 				if (ndi_prop_update_int(DDI_DEV_T_NONE,
882 				    find_dev.dip, "clock-frequency", freq)
883 				    != DDI_SUCCESS) {
884 					cmn_err(CE_WARN,
885 					    "schpc: - failed to update "
886 					    "clock-frequency property for %s",
887 					    find_dev.cname);
888 				}
889 				ndi_rele_devi(find_dev.dip);
890 			} else {
891 				cmn_err(CE_WARN,
892 				    "schpc: couldn't find dip for %s ",
893 				    find_dev.cname);
894 			}
895 			kmem_free(find_dev.caddr, MAXPATHLEN);
896 
897 			mutex_enter(&schpc_p->schpc_mutex);
898 			schpc_p->schpc_slot[slot].state &=
899 			    ~SCHPC_SLOTSTATE_EXECUTING;
900 
901 			/*
902 			 * If leaf registers were saved off, then they
903 			 * need to be restored.
904 			 */
905 			schpc_restore_leaf(slot);
906 
907 			/*
908 			 * Since the device saw a PCI Reset, we need to
909 			 * wait 2^25 clock cycles before the first
910 			 * Configuration access. The worst case is 33MHz,
911 			 * which is a 1 second wait.
912 			 */
913 			drv_usecwait(1000000);
914 
915 			cv_signal(&schpc_p->schpc_cv);
916 			mutex_exit(&schpc_p->schpc_mutex);
917 
918 			return (0);
919 		} else {
920 			/*
921 			 * The System Controller Rejected the
922 			 * connection request.
923 			 */
924 			cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
925 			    "on Expander %d Board %d PCI Slot %d - Ap_Id=%s :"
926 			    "System Controller failed connection request",
927 			    expander, board, SCHPC_SLOT_NUM(slot),
928 			    schpc_p->schpc_slot[slot].ap_id);
929 
930 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
931 
932 			goto failed;
933 		}
934 	}
935 
936 	/*
937 	 * The System Controller Rejected the connection request.
938 	 */
939 	cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
940 	    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
941 	    "failed connection request", expander, board, SCHPC_SLOT_NUM(slot),
942 	    schpc_p->schpc_slot[slot].ap_id);
943 
944 	schpc_setslotled(expander, board, slot, FAULT_LED_ON);
945 
946 failed:
947 	mutex_enter(&schpc_p->schpc_mutex);
948 	schpc_p->schpc_slot[slot].state &=
949 	    ~SCHPC_SLOTSTATE_EXECUTING;
950 	cv_signal(&schpc_p->schpc_cv);
951 	mutex_exit(&schpc_p->schpc_mutex);
952 
953 	return (HPC_ERR_FAILED);
954 }
955 
956 /*
957  * schpc_disconnect()
958  *
959  * Called by Hot Plug Services to disconnect a slot to the bus.
960  */
961 
962 /*ARGSUSED*/
963 static int
964 schpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data,
965 	uint_t flags)
966 {
967 	int		rval;
968 	int		expander, board, slot;
969 	pci_setslot_t	setslot;
970 
971 	SCHPC_DEBUG2(D_IOC_CONNECT,
972 	    "schpc_disconnect( ops_arg=%p slot_hdl=%p)", ops_arg, slot_hdl);
973 
974 	mutex_enter(&schpc_p->schpc_mutex);
975 
976 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
977 
978 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
979 		SCHPC_DEBUG0(D_IOC_CONNECT,
980 		    "schpc_disconnect - HPC Not Inited");
981 		mutex_exit(&schpc_p->schpc_mutex);
982 		return (HPC_ERR_FAILED);
983 	}
984 
985 	/*
986 	 * Check to see if we are already disconnected.
987 	 */
988 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) {
989 		mutex_exit(&schpc_p->schpc_mutex);
990 		return (0);
991 	}
992 
993 	/*
994 	 * Block if another thread is executing a HPC command.
995 	 */
996 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
997 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
998 	}
999 
1000 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1001 
1002 	mutex_exit(&schpc_p->schpc_mutex);
1003 
1004 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1005 	board = schpc_p->schpc_slot[slot].board; /* get board */
1006 
1007 	/*
1008 	 * If a leaf reset is going to be asserted due to a mode/freq.
1009 	 * change, then the leaf registers of the XMITS bridge will need
1010 	 * to be saved off prior to the connect.
1011 	 */
1012 	if (schpc_is_leaf_reset_required(slot)) {
1013 		if (schpc_save_leaf(slot) != 0) {
1014 
1015 			cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
1016 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
1017 			    expander, board, slot & 3,
1018 			    schpc_p->schpc_slot[slot].ap_id);
1019 
1020 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1021 
1022 			goto failed;
1023 		}
1024 	}
1025 
1026 	/*
1027 	 * Initialize Set Slot Command.
1028 	 */
1029 	schpc_init_setslot_message(&setslot);
1030 
1031 	setslot.slot_power_off = PCIMSG_ON;	   /* Turn Power Off */
1032 
1033 	setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */
1034 
1035 	setslot.slot_disable_ENUM = PCIMSG_ON;	   /* Mask the ENUM# signal */
1036 	setslot.slot_disable_HEALTHY = PCIMSG_ON;  /* Mask the HEALTHY# sig */
1037 
1038 	rval = schpc_setslotstatus(expander, board, slot, &setslot);
1039 
1040 	SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
1041 	    "setslotstatus returned 0x%x", rval);
1042 
1043 	if (rval != 0) {
1044 		/*
1045 		 * System Controller/Mailbox failure.
1046 		 */
1047 		cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
1048 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
1049 		    "Communicate with System Controller", expander, board,
1050 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
1051 
1052 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1053 
1054 		goto failed;
1055 	}
1056 
1057 	SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
1058 	    "slot_replystatus returned 0x%x", setslot.slot_replystatus);
1059 
1060 	if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
1061 
1062 		/*
1063 		 * The Request was successfully completed.
1064 		 */
1065 		schpc_p->schpc_slot[slot].state &=
1066 		    ~SCHPC_SLOTSTATE_CONNECTED;
1067 
1068 		schpc_setslotled(expander, board, slot,
1069 		    (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF));
1070 
1071 		SCHPC_DEBUG0(D_IOC_CONNECT,
1072 		    "schpc_disconnect() - setslotstatus succeeded");
1073 
1074 		mutex_enter(&schpc_p->schpc_mutex);
1075 		schpc_p->schpc_slot[slot].state &=
1076 		    ~SCHPC_SLOTSTATE_EXECUTING;
1077 		cv_signal(&schpc_p->schpc_cv);
1078 		mutex_exit(&schpc_p->schpc_mutex);
1079 
1080 		return (0);
1081 	}
1082 	/*
1083 	 * System Controller/Mailbox failure.
1084 	 */
1085 	cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
1086 	    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
1087 	    "failed disconnection request", expander, board,
1088 	    SCHPC_SLOT_NUM(slot),
1089 	    schpc_p->schpc_slot[slot].ap_id);
1090 
1091 	schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1092 
1093 failed:
1094 	schpc_restore_leaf(slot);
1095 	mutex_enter(&schpc_p->schpc_mutex);
1096 	schpc_p->schpc_slot[slot].state &=
1097 	    ~SCHPC_SLOTSTATE_EXECUTING;
1098 	cv_signal(&schpc_p->schpc_cv);
1099 	mutex_exit(&schpc_p->schpc_mutex);
1100 
1101 	return (HPC_ERR_FAILED);
1102 }
1103 
1104 /*
1105  * schpc_cpci_control
1106  *
1107  * Called by Hot Plug Services to perform a attachment point specific
1108  * on a Hot Pluggable Compact PCI Slot.
1109  */
1110 /*ARGSUSED*/
1111 static int
1112 schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
1113     caddr_t arg)
1114 {
1115 	int		rval;
1116 	int		expander, board, slot;
1117 	pci_setslot_t	setslot;
1118 	pci_getslot_t   slotstatus;
1119 	hpc_led_info_t	*hpc_led_info;
1120 
1121 	SCHPC_DEBUG3(D_IOC_CONTROL,
1122 	    "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)",
1123 	    ops_arg, slot_hdl, request);
1124 
1125 	mutex_enter(&schpc_p->schpc_mutex);
1126 
1127 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
1128 
1129 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
1130 		SCHPC_DEBUG0(D_IOC_CONNECT,
1131 		    "schpc_disconnect - HPC Not Inited");
1132 		mutex_exit(&schpc_p->schpc_mutex);
1133 		return (HPC_ERR_FAILED);
1134 	}
1135 
1136 	/*
1137 	 * Block if another thread is executing a HPC command.
1138 	 */
1139 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
1140 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
1141 	}
1142 
1143 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1144 
1145 	mutex_exit(&schpc_p->schpc_mutex);
1146 
1147 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1148 	board = schpc_p->schpc_slot[slot].board; /* get board */
1149 
1150 	/*
1151 	 * Initialize Set Slot Command.
1152 	 */
1153 	schpc_init_setslot_message(&setslot);
1154 
1155 	/*
1156 	 * Initialize LED to last know state.
1157 	 */
1158 	switch (schpc_p->schpc_slot[slot].led.led_power) {
1159 	case LED_ON:
1160 		setslot.slot_led_power = PCIMSG_LED_ON;
1161 		break;
1162 	case LED_OFF:
1163 		setslot.slot_led_power = PCIMSG_LED_OFF;
1164 		break;
1165 	case LED_FLASH:
1166 		setslot.slot_led_power = PCIMSG_LED_FLASH;
1167 		break;
1168 	}
1169 
1170 	switch (schpc_p->schpc_slot[slot].led.led_service) {
1171 	case LED_ON:
1172 		setslot.slot_led_service = PCIMSG_LED_ON;
1173 		break;
1174 	case LED_OFF:
1175 		setslot.slot_led_service = PCIMSG_LED_OFF;
1176 		break;
1177 	case LED_FLASH:
1178 		setslot.slot_led_service = PCIMSG_LED_FLASH;
1179 		break;
1180 	}
1181 
1182 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
1183 	case LED_ON:
1184 		setslot.slot_led_fault = PCIMSG_LED_ON;
1185 		break;
1186 	case LED_OFF:
1187 		setslot.slot_led_fault = PCIMSG_LED_OFF;
1188 		break;
1189 	case LED_FLASH:
1190 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
1191 		break;
1192 	}
1193 
1194 	switch (request) {
1195 
1196 	case HPC_CTRL_GET_LED_STATE:
1197 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1198 		    "HPC_CTRL_GET_LED_STATE");
1199 		hpc_led_info = (hpc_led_info_t *)arg;
1200 
1201 		switch (hpc_led_info->led) {
1202 		case HPC_FAULT_LED:
1203 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1204 			case LED_OFF:
1205 				hpc_led_info->state = HPC_LED_OFF;
1206 				break;
1207 			case LED_ON:
1208 				hpc_led_info->state = HPC_LED_ON;
1209 				break;
1210 			case LED_FLASH:
1211 				hpc_led_info->state = HPC_LED_BLINK;
1212 				break;
1213 			}
1214 			break;
1215 
1216 		case HPC_POWER_LED:
1217 			switch (schpc_p->schpc_slot[slot].led.led_power) {
1218 			case LED_OFF:
1219 				hpc_led_info->state = HPC_LED_OFF;
1220 				break;
1221 			case LED_ON:
1222 				hpc_led_info->state = HPC_LED_ON;
1223 				break;
1224 			case LED_FLASH:
1225 				hpc_led_info->state = HPC_LED_BLINK;
1226 				break;
1227 			}
1228 			break;
1229 		case HPC_ATTN_LED:
1230 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1231 			case LED_OFF:
1232 				hpc_led_info->state = HPC_LED_OFF;
1233 				break;
1234 			case LED_ON:
1235 				hpc_led_info->state = HPC_LED_OFF;
1236 				break;
1237 			case LED_FLASH:
1238 				hpc_led_info->state = HPC_LED_ON;
1239 				break;
1240 			}
1241 			break;
1242 		case HPC_ACTIVE_LED:
1243 			switch (schpc_p->schpc_slot[slot].led.led_service) {
1244 			case LED_OFF:
1245 				hpc_led_info->state = HPC_LED_OFF;
1246 				break;
1247 			case LED_ON:
1248 				hpc_led_info->state = HPC_LED_ON;
1249 				break;
1250 			case LED_FLASH:
1251 				hpc_led_info->state = HPC_LED_BLINK;
1252 				break;
1253 			}
1254 			break;
1255 		default:
1256 			SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1257 			    "Invalid LED %x", hpc_led_info->led);
1258 
1259 			mutex_enter(&schpc_p->schpc_mutex);
1260 			schpc_p->schpc_slot[slot].state &=
1261 			    ~SCHPC_SLOTSTATE_EXECUTING;
1262 			cv_signal(&schpc_p->schpc_cv);
1263 			mutex_exit(&schpc_p->schpc_mutex);
1264 
1265 			return (HPC_ERR_FAILED);
1266 		}
1267 
1268 		mutex_enter(&schpc_p->schpc_mutex);
1269 		schpc_p->schpc_slot[slot].state &=
1270 		    ~SCHPC_SLOTSTATE_EXECUTING;
1271 		cv_signal(&schpc_p->schpc_cv);
1272 		mutex_exit(&schpc_p->schpc_mutex);
1273 
1274 		return (0);
1275 
1276 	case HPC_CTRL_SET_LED_STATE:
1277 		hpc_led_info = (hpc_led_info_t *)arg;
1278 
1279 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1280 		    "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", hpc_led_info);
1281 
1282 		switch (hpc_led_info->led) {
1283 		case HPC_FAULT_LED:
1284 			switch (hpc_led_info->state) {
1285 			case HPC_LED_OFF:
1286 				schpc_p->schpc_slot[slot].led.led_fault =
1287 				    LED_OFF;
1288 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1289 				break;
1290 			case HPC_LED_ON:
1291 				schpc_p->schpc_slot[slot].led.led_fault =
1292 				    LED_ON;
1293 				setslot.slot_led_fault = PCIMSG_LED_ON;
1294 				break;
1295 			case HPC_LED_BLINK:
1296 				schpc_p->schpc_slot[slot].led.led_fault =
1297 				    LED_FLASH;
1298 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1299 				break;
1300 			}
1301 			break;
1302 		case HPC_POWER_LED:
1303 			switch (hpc_led_info->state) {
1304 			case HPC_LED_OFF:
1305 				schpc_p->schpc_slot[slot].led.led_power =
1306 				    LED_OFF;
1307 				setslot.slot_led_power = PCIMSG_LED_OFF;
1308 				break;
1309 			case HPC_LED_ON:
1310 				schpc_p->schpc_slot[slot].led.led_power =
1311 				    LED_ON;
1312 				setslot.slot_led_power = PCIMSG_LED_ON;
1313 				break;
1314 			case HPC_LED_BLINK:
1315 				schpc_p->schpc_slot[slot].led.led_power =
1316 				    LED_FLASH;
1317 				setslot.slot_led_power = PCIMSG_LED_FLASH;
1318 				break;
1319 			}
1320 			break;
1321 		case HPC_ATTN_LED:
1322 			switch (hpc_led_info->state) {
1323 			case HPC_LED_OFF:
1324 				schpc_p->schpc_slot[slot].led.led_fault =
1325 				    LED_OFF;
1326 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1327 				break;
1328 			case HPC_LED_ON:
1329 				schpc_p->schpc_slot[slot].led.led_fault =
1330 				    LED_FLASH;
1331 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1332 				break;
1333 			case HPC_LED_BLINK:
1334 				schpc_p->schpc_slot[slot].led.led_fault =
1335 				    LED_FLASH;
1336 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1337 				break;
1338 			}
1339 			break;
1340 		case HPC_ACTIVE_LED:
1341 			switch (hpc_led_info->state) {
1342 			case HPC_LED_OFF:
1343 				schpc_p->schpc_slot[slot].led.led_service =
1344 				    LED_OFF;
1345 				setslot.slot_led_service = PCIMSG_LED_OFF;
1346 				break;
1347 			case HPC_LED_ON:
1348 				schpc_p->schpc_slot[slot].led.led_service =
1349 				    LED_ON;
1350 				setslot.slot_led_service = PCIMSG_LED_ON;
1351 				break;
1352 			case HPC_LED_BLINK:
1353 				schpc_p->schpc_slot[slot].led.led_service =
1354 				    LED_FLASH;
1355 				setslot.slot_led_service = PCIMSG_LED_FLASH;
1356 				break;
1357 			}
1358 			break;
1359 		default:
1360 			mutex_enter(&schpc_p->schpc_mutex);
1361 			schpc_p->schpc_slot[slot].state &=
1362 			    ~SCHPC_SLOTSTATE_EXECUTING;
1363 			cv_signal(&schpc_p->schpc_cv);
1364 			mutex_exit(&schpc_p->schpc_mutex);
1365 
1366 			return (0);
1367 		}
1368 
1369 		(void) schpc_setslotstatus(expander, board, slot, &setslot);
1370 
1371 		mutex_enter(&schpc_p->schpc_mutex);
1372 		schpc_p->schpc_slot[slot].state &=
1373 		    ~SCHPC_SLOTSTATE_EXECUTING;
1374 		cv_signal(&schpc_p->schpc_cv);
1375 		mutex_exit(&schpc_p->schpc_mutex);
1376 
1377 		return (0);
1378 
1379 	case HPC_CTRL_GET_SLOT_STATE: {
1380 		hpc_slot_state_t	*hpc_slot_state;
1381 
1382 		hpc_slot_state = (hpc_slot_state_t *)arg;
1383 
1384 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1385 		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1386 		    hpc_slot_state);
1387 
1388 		rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
1389 
1390 		if (!rval) {
1391 
1392 			if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
1393 				return (HPC_ERR_FAILED);
1394 			}
1395 
1396 			if (slotstatus.slot_empty == PCIMSG_ON) {
1397 				*hpc_slot_state = HPC_SLOT_EMPTY;
1398 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
1399 			} else if (slotstatus.slot_power_on == PCIMSG_ON) {
1400 				*hpc_slot_state = HPC_SLOT_CONNECTED;
1401 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
1402 				schpc_p->schpc_slot[slot].state |=
1403 				    SCHPC_SLOTSTATE_CONNECTED;
1404 			} else {
1405 				*hpc_slot_state = HPC_SLOT_DISCONNECTED;
1406 				SCHPC_DEBUG0(D_IOC_CONTROL,
1407 				    "Slot Disconnected");
1408 				schpc_p->schpc_slot[slot].state &=
1409 				    ~SCHPC_SLOTSTATE_CONNECTED;
1410 			}
1411 		} else {
1412 			SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
1413 
1414 			mutex_enter(&schpc_p->schpc_mutex);
1415 			schpc_p->schpc_slot[slot].state &=
1416 			    ~SCHPC_SLOTSTATE_EXECUTING;
1417 			cv_signal(&schpc_p->schpc_cv);
1418 			mutex_exit(&schpc_p->schpc_mutex);
1419 
1420 			return (HPC_ERR_FAILED);
1421 		}
1422 
1423 		mutex_enter(&schpc_p->schpc_mutex);
1424 		schpc_p->schpc_slot[slot].state &=
1425 		    ~SCHPC_SLOTSTATE_EXECUTING;
1426 		cv_signal(&schpc_p->schpc_cv);
1427 		mutex_exit(&schpc_p->schpc_mutex);
1428 
1429 		return (0);
1430 	}
1431 	case HPC_CTRL_GET_BOARD_TYPE: {
1432 		hpc_board_type_t	*hpc_board_type;
1433 
1434 		hpc_board_type = (hpc_board_type_t *)arg;
1435 
1436 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1437 		    "HPC_CTRL_GET_BOARD_TYPE");
1438 
1439 		/*
1440 		 * The HPC driver does not know what board type
1441 		 * is plugged in.
1442 		 */
1443 		*hpc_board_type = HPC_BOARD_CPCI_HS;
1444 
1445 		mutex_enter(&schpc_p->schpc_mutex);
1446 		schpc_p->schpc_slot[slot].state &=
1447 		    ~SCHPC_SLOTSTATE_EXECUTING;
1448 		cv_signal(&schpc_p->schpc_cv);
1449 		mutex_exit(&schpc_p->schpc_mutex);
1450 
1451 		return (0);
1452 
1453 	}
1454 	case HPC_CTRL_DEV_CONFIGURED:
1455 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1456 		    "HPC_CTRL_DEV_CONFIGURED");
1457 
1458 		mutex_enter(&schpc_p->schpc_mutex);
1459 		schpc_p->schpc_slot[slot].state &=
1460 		    ~SCHPC_SLOTSTATE_EXECUTING;
1461 		cv_signal(&schpc_p->schpc_cv);
1462 		mutex_exit(&schpc_p->schpc_mutex);
1463 
1464 		return (0);
1465 
1466 	case HPC_CTRL_DEV_UNCONFIGURED:
1467 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1468 		    "HPC_CTRL_DEV_UNCONFIGURED");
1469 
1470 		if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) {
1471 			/*
1472 			 * When the occupant is unconfigured, power
1473 			 * down the slot.
1474 			 */
1475 			rval = schpc_disconnect((caddr_t)schpc_p,
1476 			    schpc_p->schpc_slot[slot].slot_handle,
1477 			    0, 0);
1478 
1479 			schpc_p->schpc_slot[slot].state &=
1480 			    ~SCHPC_SLOTSTATE_ENUM;
1481 		}
1482 
1483 		mutex_enter(&schpc_p->schpc_mutex);
1484 		schpc_p->schpc_slot[slot].state &=
1485 		    ~SCHPC_SLOTSTATE_EXECUTING;
1486 		cv_signal(&schpc_p->schpc_cv);
1487 		mutex_exit(&schpc_p->schpc_mutex);
1488 
1489 		return (0);
1490 
1491 	case HPC_CTRL_ENABLE_AUTOCFG:
1492 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1493 		    "HPC_CTRL_ENABLE_AUTOCFG");
1494 
1495 		schpc_p->schpc_slot[slot].state |=
1496 		    SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1497 
1498 		mutex_enter(&schpc_p->schpc_mutex);
1499 		schpc_p->schpc_slot[slot].state &=
1500 		    ~SCHPC_SLOTSTATE_EXECUTING;
1501 		cv_signal(&schpc_p->schpc_cv);
1502 		mutex_exit(&schpc_p->schpc_mutex);
1503 
1504 		return (0);
1505 
1506 	case HPC_CTRL_DISABLE_AUTOCFG:
1507 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1508 		    "HPC_CTRL_DISABLE_AUTOCFG");
1509 		schpc_p->schpc_slot[slot].state &=
1510 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1511 
1512 		mutex_enter(&schpc_p->schpc_mutex);
1513 		schpc_p->schpc_slot[slot].state &=
1514 		    ~SCHPC_SLOTSTATE_EXECUTING;
1515 		cv_signal(&schpc_p->schpc_cv);
1516 		mutex_exit(&schpc_p->schpc_mutex);
1517 
1518 		return (0);
1519 
1520 	case HPC_CTRL_DISABLE_ENUM:
1521 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1522 		    "HPC_CTRL_DISABLE_ENUM");
1523 
1524 		setslot.slot_disable_ENUM = PCIMSG_ON;
1525 
1526 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
1527 
1528 		if (rval)
1529 			rval = HPC_ERR_FAILED;
1530 
1531 		mutex_enter(&schpc_p->schpc_mutex);
1532 		schpc_p->schpc_slot[slot].state &=
1533 		    ~SCHPC_SLOTSTATE_EXECUTING;
1534 		cv_signal(&schpc_p->schpc_cv);
1535 		mutex_exit(&schpc_p->schpc_mutex);
1536 
1537 		return (rval);
1538 
1539 	case HPC_CTRL_ENABLE_ENUM:
1540 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1541 		    "HPC_CTRL_ENABLE_ENUM");
1542 
1543 		setslot.slot_enable_ENUM = PCIMSG_ON;
1544 
1545 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
1546 
1547 		if (rval)
1548 			rval = HPC_ERR_FAILED;
1549 
1550 		mutex_enter(&schpc_p->schpc_mutex);
1551 		schpc_p->schpc_slot[slot].state &=
1552 		    ~SCHPC_SLOTSTATE_EXECUTING;
1553 		cv_signal(&schpc_p->schpc_cv);
1554 		mutex_exit(&schpc_p->schpc_mutex);
1555 
1556 		return (rval);
1557 
1558 	default:
1559 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1560 		    "****NOT SUPPORTED CONTROL CMD");
1561 
1562 		mutex_enter(&schpc_p->schpc_mutex);
1563 		schpc_p->schpc_slot[slot].state &=
1564 		    ~SCHPC_SLOTSTATE_EXECUTING;
1565 		cv_signal(&schpc_p->schpc_cv);
1566 		mutex_exit(&schpc_p->schpc_mutex);
1567 
1568 		return (HPC_ERR_NOTSUPPORTED);
1569 	}
1570 }
1571 
1572 /*
1573  * schpc_pci_control
1574  *
1575  * Called by Hot Plug Services to perform a attachment point specific
1576  * on a Hot Pluggable Standard PCI Slot.
1577  */
1578 /*ARGSUSED*/
1579 static int
1580 schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
1581     caddr_t arg)
1582 {
1583 	int		rval;
1584 	int		expander, board, slot;
1585 	pci_setslot_t	setslot;
1586 	pci_getslot_t   slotstatus;
1587 	hpc_led_info_t	*hpc_led_info;
1588 
1589 	SCHPC_DEBUG3(D_IOC_CONTROL,
1590 	    "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)",
1591 	    ops_arg, slot_hdl, request);
1592 
1593 	mutex_enter(&schpc_p->schpc_mutex);
1594 
1595 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
1596 
1597 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
1598 		SCHPC_DEBUG0(D_IOC_CONNECT,
1599 		    "schpc_disconnect - HPC Not Inited");
1600 		mutex_exit(&schpc_p->schpc_mutex);
1601 		return (HPC_ERR_FAILED);
1602 	}
1603 
1604 	/*
1605 	 * Block if another thread is executing a HPC command.
1606 	 */
1607 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
1608 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
1609 	}
1610 
1611 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1612 
1613 	mutex_exit(&schpc_p->schpc_mutex);
1614 
1615 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1616 	board = schpc_p->schpc_slot[slot].board; /* get board */
1617 
1618 	/*
1619 	 * Initialize Set Slot Command.
1620 	 */
1621 	schpc_init_setslot_message(&setslot);
1622 
1623 	/*
1624 	 * Initialize LED to last know state.
1625 	 */
1626 	switch (schpc_p->schpc_slot[slot].led.led_power) {
1627 	case LED_ON:
1628 		setslot.slot_led_power = PCIMSG_LED_ON;
1629 		break;
1630 	case LED_OFF:
1631 		setslot.slot_led_power = PCIMSG_LED_OFF;
1632 		break;
1633 	case LED_FLASH:
1634 		setslot.slot_led_power = PCIMSG_LED_FLASH;
1635 		break;
1636 	}
1637 
1638 	switch (schpc_p->schpc_slot[slot].led.led_service) {
1639 	case LED_ON:
1640 		setslot.slot_led_service = PCIMSG_LED_ON;
1641 		break;
1642 	case LED_OFF:
1643 		setslot.slot_led_service = PCIMSG_LED_OFF;
1644 		break;
1645 	case LED_FLASH:
1646 		setslot.slot_led_service = PCIMSG_LED_FLASH;
1647 		break;
1648 	}
1649 
1650 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
1651 	case LED_ON:
1652 		setslot.slot_led_fault = PCIMSG_LED_ON;
1653 		break;
1654 	case LED_OFF:
1655 		setslot.slot_led_fault = PCIMSG_LED_OFF;
1656 		break;
1657 	case LED_FLASH:
1658 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
1659 		break;
1660 	}
1661 
1662 	switch (request) {
1663 
1664 
1665 	case HPC_CTRL_GET_SLOT_STATE: {
1666 		hpc_slot_state_t	*hpc_slot_state;
1667 
1668 		hpc_slot_state = (hpc_slot_state_t *)arg;
1669 
1670 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1671 		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1672 		    hpc_slot_state);
1673 
1674 		rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
1675 
1676 		if (!rval) {
1677 
1678 			if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
1679 
1680 				mutex_enter(&schpc_p->schpc_mutex);
1681 				schpc_p->schpc_slot[slot].state &=
1682 				    ~SCHPC_SLOTSTATE_EXECUTING;
1683 				cv_signal(&schpc_p->schpc_cv);
1684 				mutex_exit(&schpc_p->schpc_mutex);
1685 
1686 				return (HPC_ERR_FAILED);
1687 			}
1688 
1689 			if (slotstatus.slot_empty == PCIMSG_ON) {
1690 				*hpc_slot_state = HPC_SLOT_EMPTY;
1691 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
1692 			} else if (slotstatus.slot_power_on == PCIMSG_ON) {
1693 				*hpc_slot_state = HPC_SLOT_CONNECTED;
1694 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
1695 				schpc_p->schpc_slot[slot].state |=
1696 				    SCHPC_SLOTSTATE_CONNECTED;
1697 			} else {
1698 				*hpc_slot_state = HPC_SLOT_DISCONNECTED;
1699 				SCHPC_DEBUG0(D_IOC_CONTROL,
1700 				    "Slot Disconnected");
1701 				schpc_p->schpc_slot[slot].state &=
1702 				    ~SCHPC_SLOTSTATE_CONNECTED;
1703 			}
1704 		} else {
1705 			SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
1706 
1707 			mutex_enter(&schpc_p->schpc_mutex);
1708 			schpc_p->schpc_slot[slot].state &=
1709 			    ~SCHPC_SLOTSTATE_EXECUTING;
1710 			cv_signal(&schpc_p->schpc_cv);
1711 			mutex_exit(&schpc_p->schpc_mutex);
1712 
1713 			return (HPC_ERR_FAILED);
1714 		}
1715 
1716 		mutex_enter(&schpc_p->schpc_mutex);
1717 		schpc_p->schpc_slot[slot].state &=
1718 		    ~SCHPC_SLOTSTATE_EXECUTING;
1719 		cv_signal(&schpc_p->schpc_cv);
1720 		mutex_exit(&schpc_p->schpc_mutex);
1721 
1722 		return (0);
1723 	}
1724 	case HPC_CTRL_GET_BOARD_TYPE: {
1725 		hpc_board_type_t	*hpc_board_type;
1726 
1727 		hpc_board_type = (hpc_board_type_t *)arg;
1728 
1729 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1730 		    "HPC_CTRL_GET_BOARD_TYPE");
1731 
1732 
1733 		/*
1734 		 * The HPC driver does not know what board type
1735 		 * is plugged in.
1736 		 */
1737 		*hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
1738 
1739 		mutex_enter(&schpc_p->schpc_mutex);
1740 		schpc_p->schpc_slot[slot].state &=
1741 		    ~SCHPC_SLOTSTATE_EXECUTING;
1742 		cv_signal(&schpc_p->schpc_cv);
1743 		mutex_exit(&schpc_p->schpc_mutex);
1744 
1745 		return (0);
1746 
1747 	}
1748 	case HPC_CTRL_DEV_UNCONFIG_START:
1749 	case HPC_CTRL_DEV_CONFIG_START:
1750 	case HPC_CTRL_DEV_CONFIGURED:
1751 	case HPC_CTRL_DEV_UNCONFIGURED:
1752 		mutex_enter(&schpc_p->schpc_mutex);
1753 		schpc_p->schpc_slot[slot].state &=
1754 		    ~SCHPC_SLOTSTATE_EXECUTING;
1755 		cv_signal(&schpc_p->schpc_cv);
1756 		mutex_exit(&schpc_p->schpc_mutex);
1757 
1758 		return (0);
1759 
1760 	case HPC_CTRL_GET_LED_STATE:
1761 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1762 		    "HPC_CTRL_GET_LED_STATE");
1763 		hpc_led_info = (hpc_led_info_t *)arg;
1764 
1765 		switch (hpc_led_info->led) {
1766 		case HPC_FAULT_LED:
1767 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1768 			case LED_OFF:
1769 				hpc_led_info->state = HPC_LED_OFF;
1770 				break;
1771 			case LED_ON:
1772 				hpc_led_info->state = HPC_LED_ON;
1773 				break;
1774 			case LED_FLASH:
1775 				hpc_led_info->state = HPC_LED_BLINK;
1776 				break;
1777 			}
1778 			break;
1779 
1780 		case HPC_POWER_LED:
1781 			switch (schpc_p->schpc_slot[slot].led.led_power) {
1782 			case LED_OFF:
1783 				hpc_led_info->state = HPC_LED_OFF;
1784 				break;
1785 			case LED_ON:
1786 				hpc_led_info->state = HPC_LED_ON;
1787 				break;
1788 			case LED_FLASH:
1789 				hpc_led_info->state = HPC_LED_BLINK;
1790 				break;
1791 			}
1792 			break;
1793 		case HPC_ATTN_LED:
1794 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1795 			case LED_OFF:
1796 				hpc_led_info->state = HPC_LED_OFF;
1797 				break;
1798 			case LED_ON:
1799 				hpc_led_info->state = HPC_LED_OFF;
1800 				break;
1801 			case LED_FLASH:
1802 				hpc_led_info->state = HPC_LED_ON;
1803 				break;
1804 			}
1805 			break;
1806 		case HPC_ACTIVE_LED:
1807 			switch (schpc_p->schpc_slot[slot].led.led_service) {
1808 			case LED_OFF:
1809 				hpc_led_info->state = HPC_LED_OFF;
1810 				break;
1811 			case LED_ON:
1812 				hpc_led_info->state = HPC_LED_ON;
1813 				break;
1814 			case LED_FLASH:
1815 				hpc_led_info->state = HPC_LED_BLINK;
1816 				break;
1817 			}
1818 			break;
1819 		default:
1820 			SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1821 			    "Invalid LED %x", hpc_led_info->led);
1822 
1823 			mutex_enter(&schpc_p->schpc_mutex);
1824 			schpc_p->schpc_slot[slot].state &=
1825 			    ~SCHPC_SLOTSTATE_EXECUTING;
1826 			cv_signal(&schpc_p->schpc_cv);
1827 			mutex_exit(&schpc_p->schpc_mutex);
1828 
1829 			return (HPC_ERR_FAILED);
1830 		}
1831 
1832 		mutex_enter(&schpc_p->schpc_mutex);
1833 		schpc_p->schpc_slot[slot].state &=
1834 		    ~SCHPC_SLOTSTATE_EXECUTING;
1835 		cv_signal(&schpc_p->schpc_cv);
1836 		mutex_exit(&schpc_p->schpc_mutex);
1837 
1838 		return (0);
1839 
1840 	case HPC_CTRL_SET_LED_STATE:
1841 		hpc_led_info = (hpc_led_info_t *)arg;
1842 
1843 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1844 		    "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", hpc_led_info);
1845 
1846 		switch (hpc_led_info->led) {
1847 		case HPC_FAULT_LED:
1848 			switch (hpc_led_info->state) {
1849 			case HPC_LED_OFF:
1850 				schpc_p->schpc_slot[slot].led.led_fault =
1851 				    LED_OFF;
1852 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1853 				break;
1854 			case HPC_LED_ON:
1855 				schpc_p->schpc_slot[slot].led.led_fault =
1856 				    LED_ON;
1857 				setslot.slot_led_fault = PCIMSG_LED_ON;
1858 				break;
1859 			case HPC_LED_BLINK:
1860 				schpc_p->schpc_slot[slot].led.led_fault =
1861 				    LED_FLASH;
1862 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1863 				break;
1864 			}
1865 			break;
1866 		case HPC_POWER_LED:
1867 			switch (hpc_led_info->state) {
1868 			case HPC_LED_OFF:
1869 				schpc_p->schpc_slot[slot].led.led_power =
1870 				    LED_OFF;
1871 				setslot.slot_led_power = PCIMSG_LED_OFF;
1872 				break;
1873 			case HPC_LED_ON:
1874 				schpc_p->schpc_slot[slot].led.led_power =
1875 				    LED_ON;
1876 				setslot.slot_led_power = PCIMSG_LED_ON;
1877 				break;
1878 			case HPC_LED_BLINK:
1879 				schpc_p->schpc_slot[slot].led.led_power =
1880 				    LED_FLASH;
1881 				setslot.slot_led_power = PCIMSG_LED_FLASH;
1882 				break;
1883 			}
1884 			break;
1885 		case HPC_ATTN_LED:
1886 			switch (hpc_led_info->state) {
1887 			case HPC_LED_OFF:
1888 				schpc_p->schpc_slot[slot].led.led_fault =
1889 				    LED_OFF;
1890 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1891 				break;
1892 			case HPC_LED_ON:
1893 				schpc_p->schpc_slot[slot].led.led_fault =
1894 				    LED_FLASH;
1895 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1896 				break;
1897 			case HPC_LED_BLINK:
1898 				schpc_p->schpc_slot[slot].led.led_fault =
1899 				    LED_FLASH;
1900 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1901 				break;
1902 			}
1903 			break;
1904 		case HPC_ACTIVE_LED:
1905 			switch (hpc_led_info->state) {
1906 			case HPC_LED_OFF:
1907 				schpc_p->schpc_slot[slot].led.led_service =
1908 				    LED_OFF;
1909 				setslot.slot_led_service = PCIMSG_LED_OFF;
1910 				break;
1911 			case HPC_LED_ON:
1912 				schpc_p->schpc_slot[slot].led.led_service =
1913 				    LED_ON;
1914 				setslot.slot_led_service = PCIMSG_LED_ON;
1915 				break;
1916 			case HPC_LED_BLINK:
1917 				schpc_p->schpc_slot[slot].led.led_service =
1918 				    LED_FLASH;
1919 				setslot.slot_led_service = PCIMSG_LED_FLASH;
1920 				break;
1921 			}
1922 			break;
1923 		default:
1924 			mutex_enter(&schpc_p->schpc_mutex);
1925 			schpc_p->schpc_slot[slot].state &=
1926 			    ~SCHPC_SLOTSTATE_EXECUTING;
1927 			cv_signal(&schpc_p->schpc_cv);
1928 			mutex_exit(&schpc_p->schpc_mutex);
1929 
1930 			return (0);
1931 		}
1932 
1933 		(void) schpc_setslotstatus(expander, board, slot, &setslot);
1934 
1935 		mutex_enter(&schpc_p->schpc_mutex);
1936 		schpc_p->schpc_slot[slot].state &=
1937 		    ~SCHPC_SLOTSTATE_EXECUTING;
1938 		cv_signal(&schpc_p->schpc_cv);
1939 		mutex_exit(&schpc_p->schpc_mutex);
1940 
1941 		return (0);
1942 
1943 	case HPC_CTRL_ENABLE_AUTOCFG:
1944 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1945 		    "HPC_CTRL_ENABLE_AUTOCFG");
1946 
1947 		schpc_p->schpc_slot[slot].state |=
1948 		    SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1949 
1950 		mutex_enter(&schpc_p->schpc_mutex);
1951 		schpc_p->schpc_slot[slot].state &=
1952 		    ~SCHPC_SLOTSTATE_EXECUTING;
1953 		cv_signal(&schpc_p->schpc_cv);
1954 		mutex_exit(&schpc_p->schpc_mutex);
1955 
1956 		return (0);
1957 
1958 	case HPC_CTRL_DISABLE_AUTOCFG:
1959 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1960 		    "HPC_CTRL_DISABLE_AUTOCFG");
1961 		schpc_p->schpc_slot[slot].state &=
1962 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1963 
1964 		mutex_enter(&schpc_p->schpc_mutex);
1965 		schpc_p->schpc_slot[slot].state &=
1966 		    ~SCHPC_SLOTSTATE_EXECUTING;
1967 		cv_signal(&schpc_p->schpc_cv);
1968 		mutex_exit(&schpc_p->schpc_mutex);
1969 
1970 		return (0);
1971 
1972 	case HPC_CTRL_DISABLE_ENUM:
1973 	case HPC_CTRL_ENABLE_ENUM:
1974 	default:
1975 		mutex_enter(&schpc_p->schpc_mutex);
1976 		schpc_p->schpc_slot[slot].state &=
1977 		    ~SCHPC_SLOTSTATE_EXECUTING;
1978 		cv_signal(&schpc_p->schpc_cv);
1979 		mutex_exit(&schpc_p->schpc_mutex);
1980 
1981 		return (HPC_ERR_NOTSUPPORTED);
1982 	}
1983 }
1984 
1985 /*
1986  * schpc_test
1987  *
1988  * Tests the slot.
1989  */
1990 /*ARGSUSED*/
1991 static void
1992 schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags)
1993 {
1994 	pci_getslot_t	slotstatus;
1995 	pci_setslot_t	setslot;
1996 	int		expander, board;
1997 	int		rval;
1998 	int		retry = 1;
1999 
2000 	SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)",
2001 	    ops_arg, SCHPC_SLOT_NUM(slot));
2002 
2003 	SCHPC_DEBUG3(D_IOC_TEST,
2004 	    "    schpc_test() Expander=%d Board=%d Slot=%d",
2005 	    schpc_p->schpc_slot[slot].expander,
2006 	    schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot));
2007 
2008 	expander = schpc_p->schpc_slot[slot].expander;
2009 	board = schpc_p->schpc_slot[slot].board;
2010 
2011 restart_test:
2012 	/*
2013 	 * Initial the slot with its occupant and receptacle in good condition.
2014 	 */
2015 	schpc_p->schpc_slot[slot].state |=  SCHPC_SLOTSTATE_REC_GOOD;
2016 	schpc_p->schpc_slot[slot].state |=  SCHPC_SLOTSTATE_OCC_GOOD;
2017 
2018 
2019 	rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
2020 
2021 	if (rval) {
2022 		/*
2023 		 * System Controller/Mailbox failure.
2024 		 */
2025 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2026 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
2027 		    "Communicate with System Controller", expander, board,
2028 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
2029 
2030 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2031 		return;
2032 	}
2033 
2034 	if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
2035 
2036 		cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
2037 		    "is not hot pluggable\n", expander, board,
2038 		    SCHPC_SLOT_NUM(slot));
2039 
2040 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2041 		return;
2042 	}
2043 
2044 	switch (slotstatus.slot_condition) {
2045 	case PCIMSG_SLOTCOND_OCC_FAIL:
2046 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2047 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2048 		    "System Controller/Occupant Failed",
2049 		    expander, board, SCHPC_SLOT_NUM(slot),
2050 		    schpc_p->schpc_slot[slot].ap_id);
2051 
2052 		schpc_setslotled(expander, board, slot,
2053 		    (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON));
2054 
2055 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_OCC_GOOD;
2056 		return;
2057 	case PCIMSG_SLOTCOND_REC_FAIL:
2058 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2059 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2060 		    "System Controller/Receptacle Failed",
2061 		    expander, board, SCHPC_SLOT_NUM(slot),
2062 		    schpc_p->schpc_slot[slot].ap_id);
2063 
2064 		schpc_setslotled(expander, board, slot,
2065 		    (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON));
2066 
2067 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2068 		return;
2069 	case PCIMSG_SLOTCOND_NOHOTPLUG:
2070 		cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
2071 		    "is not hot pluggable\n", expander, board,
2072 		    SCHPC_SLOT_NUM(slot));
2073 
2074 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2075 		return;
2076 	}
2077 
2078 	if (slotstatus.slot_power_on) {
2079 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
2080 
2081 		if (!slotstatus.slot_HEALTHY) {
2082 			/*
2083 			 * cPCI Adapter is not asserting HEALTHY#.
2084 			 */
2085 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2086 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2087 			    "PCI adapter not HEALTHY", expander, board,
2088 			    SCHPC_SLOT_NUM(slot),
2089 			    schpc_p->schpc_slot[slot].ap_id);
2090 
2091 			schpc_setslotled(expander, board, slot,
2092 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2093 
2094 			schpc_p->schpc_slot[slot].state &=
2095 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2096 
2097 			return;
2098 		}
2099 
2100 		if (!slotstatus.slot_powergood) {
2101 			/*
2102 			 * PCI Power Input is not good.
2103 			 */
2104 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2105 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2106 			    "System Controller PCI Power Input Not Good",
2107 			    expander, board, SCHPC_SLOT_NUM(slot),
2108 			    schpc_p->schpc_slot[slot].ap_id);
2109 
2110 			schpc_setslotled(expander, board, slot,
2111 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2112 
2113 			schpc_p->schpc_slot[slot].state &=
2114 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2115 
2116 			return;
2117 		}
2118 
2119 		if (slotstatus.slot_powerfault) {
2120 			/*
2121 			 * PCI Power Fault.
2122 			 */
2123 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2124 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2125 			    "System Controller PCI Power Fault",
2126 			    expander, board, SCHPC_SLOT_NUM(slot),
2127 			    schpc_p->schpc_slot[slot].ap_id);
2128 
2129 			schpc_setslotled(expander, board, slot,
2130 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2131 
2132 			schpc_p->schpc_slot[slot].state &=
2133 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2134 
2135 			return;
2136 		}
2137 	}
2138 
2139 	SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0");
2140 
2141 	/*
2142 	 * Is the slot empty?
2143 	 */
2144 	if (slotstatus.slot_empty) {
2145 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty");
2146 
2147 		schpc_p->schpc_slot[slot].state &=
2148 		    ~SCHPC_SLOTSTATE_PRESENT;
2149 
2150 		if (slotstatus.slot_power_on) {
2151 
2152 			SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot "
2153 			    "is powered ON");
2154 
2155 			/*
2156 			 * Tests will be retried once after powering off
2157 			 * an empty slot.
2158 			 */
2159 			if (retry) {
2160 
2161 				/*
2162 				 * Turn off the slot and restart test.
2163 				 */
2164 				SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() "
2165 				    "Turning Empty Slot OFF");
2166 
2167 				schpc_init_setslot_message(&setslot);
2168 				setslot.slot_power_off = PCIMSG_ON;
2169 				(void) schpc_setslotstatus(
2170 				    expander, board, slot, &setslot);
2171 
2172 				retry = 0;
2173 
2174 				goto restart_test;
2175 			}
2176 		}
2177 	} else {
2178 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present");
2179 
2180 		if (!slotstatus.slot_power_on) {
2181 			if (retry) {
2182 				/*
2183 				 * If there is a cassette present and the
2184 				 * power is off, try turning the power on and
2185 				 * restart the test. This allows access to
2186 				 * the FRUID when an empty cassette is
2187 				 * installed.
2188 				 */
2189 				SCHPC_DEBUG0(D_IOC_TEST,
2190 				    "schpc_test() Power On Adapter");
2191 				schpc_init_setslot_message(&setslot);
2192 				setslot.slot_power_on = PCIMSG_ON;
2193 				(void) schpc_setslotstatus(
2194 				    expander, board, slot, &setslot);
2195 				retry = 0;
2196 				goto restart_test;
2197 			}
2198 		}
2199 
2200 		schpc_p->schpc_slot[slot].state |=
2201 		    SCHPC_SLOTSTATE_PRESENT;
2202 	}
2203 
2204 	/*
2205 	 * Is the slot powered up?
2206 	 */
2207 	schpc_init_setslot_message(&setslot);
2208 
2209 	if (slotstatus.slot_power_on) {
2210 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On");
2211 
2212 		schpc_p->schpc_slot[slot].state |=
2213 		    SCHPC_SLOTSTATE_CONNECTED;
2214 
2215 		setslot.slot_led_power = PCIMSG_LED_ON;
2216 		setslot.slot_led_service = PCIMSG_LED_OFF;
2217 		setslot.slot_enable_ENUM = PCIMSG_ON;
2218 		setslot.slot_enable_HEALTHY = PCIMSG_ON;
2219 	} else {
2220 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off");
2221 
2222 		schpc_p->schpc_slot[slot].state &=
2223 		    ~SCHPC_SLOTSTATE_CONNECTED;
2224 
2225 		setslot.slot_led_power = PCIMSG_LED_OFF;
2226 		setslot.slot_led_service = PCIMSG_LED_ON;
2227 		setslot.slot_disable_ENUM = PCIMSG_ON;
2228 		setslot.slot_disable_HEALTHY = PCIMSG_ON;
2229 	}
2230 
2231 	setslot.slot_led_fault = PCIMSG_LED_OFF;
2232 
2233 	(void) schpc_setslotstatus(expander, board, slot, &setslot);
2234 
2235 	/*
2236 	 * Save LED State.
2237 	 */
2238 	switch (setslot.slot_led_power) {
2239 	case PCIMSG_LED_ON:
2240 		schpc_p->schpc_slot[slot].led.led_power = LED_ON;
2241 		break;
2242 	case PCIMSG_LED_OFF:
2243 		schpc_p->schpc_slot[slot].led.led_power = LED_OFF;
2244 		break;
2245 	case PCIMSG_LED_FLASH:
2246 		schpc_p->schpc_slot[slot].led.led_power = LED_FLASH;
2247 		break;
2248 	}
2249 	switch (setslot.slot_led_service) {
2250 	case PCIMSG_LED_ON:
2251 		schpc_p->schpc_slot[slot].led.led_service = LED_ON;
2252 		break;
2253 	case PCIMSG_LED_OFF:
2254 		schpc_p->schpc_slot[slot].led.led_service = LED_OFF;
2255 		break;
2256 	case PCIMSG_LED_FLASH:
2257 		schpc_p->schpc_slot[slot].led.led_service = LED_FLASH;
2258 		break;
2259 	}
2260 	switch (setslot.slot_led_fault) {
2261 	case PCIMSG_LED_ON:
2262 		schpc_p->schpc_slot[slot].led.led_fault = LED_ON;
2263 		break;
2264 	case PCIMSG_LED_OFF:
2265 		schpc_p->schpc_slot[slot].led.led_fault = LED_OFF;
2266 		break;
2267 	case PCIMSG_LED_FLASH:
2268 		schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH;
2269 		break;
2270 	}
2271 }
2272 
2273 
2274 /*
2275  * schpc_event_handler
2276  *
2277  * Placed on the schpc_event_taskq by schpc_event_filter when an
2278  * unsolicited MBOXSC_MSG_EVENT is received from the SC.  It handles
2279  * things like power insertion/removal, ENUM#, etc.
2280  */
2281 static void
2282 schpc_event_handler(void *arg)
2283 {
2284 	pci_getslot_t	slotstatus;
2285 	uint8_t		expander, board, slot;
2286 	int		rval;
2287 	pcimsg_t *event = (pcimsg_t *)arg;
2288 
2289 	/*
2290 	 * OK, we got an event message. Since the event message only tells
2291 	 * us something has changed and not changed to what, we need to get
2292 	 * the current slot status to find how WHAT was change to WHAT.
2293 	 */
2294 
2295 	slot = event->pcimsg_slot;
2296 	expander = event->pcimsg_node; /* get expander */
2297 	board = event->pcimsg_board; /* get board */
2298 
2299 	SCHPC_DEBUG3(D_EVENT,
2300 	    "schpc_event_handler() - exp=%d board=%d slot=%d",
2301 	    expander, board, slot);
2302 
2303 	/* create a slot table index */
2304 	slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot);
2305 
2306 	SCHPC_DEBUG1(D_EVENT,
2307 	    "schpc_event_handler() - expanded slot %d", slot);
2308 
2309 	if (schpc_p == NULL) {
2310 		cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc");
2311 		kmem_free(event, sizeof (pcimsg_t));
2312 		return;
2313 	}
2314 
2315 	mutex_enter(&schpc_p->schpc_mutex);
2316 
2317 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
2318 		SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited");
2319 		mutex_exit(&schpc_p->schpc_mutex);
2320 		kmem_free(event, sizeof (pcimsg_t));
2321 		return;
2322 	}
2323 	/*
2324 	 * Block if another thread is executing a HPC command.
2325 	 */
2326 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
2327 		SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy");
2328 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
2329 	}
2330 
2331 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
2332 
2333 	mutex_exit(&schpc_p->schpc_mutex);
2334 
2335 	rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
2336 
2337 	if (rval) {
2338 		cmn_err(CE_WARN, "schpc/Event Handler - Can not get status "
2339 		    "for expander=%d board=%d slot=%d\n",
2340 		    expander, board, SCHPC_SLOT_NUM(slot));
2341 
2342 		mutex_enter(&schpc_p->schpc_mutex);
2343 		schpc_p->schpc_slot[slot].state &=
2344 		    ~SCHPC_SLOTSTATE_EXECUTING;
2345 		cv_signal(&schpc_p->schpc_cv);
2346 		mutex_exit(&schpc_p->schpc_mutex);
2347 		kmem_free(event, sizeof (pcimsg_t));
2348 		return;
2349 	}
2350 
2351 	if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
2352 		cmn_err(CE_WARN, "schpc/Event Handler - Can not get good "
2353 		    "status for expander=%d board=%d slot=%d\n",
2354 		    expander, board, SCHPC_SLOT_NUM(slot));
2355 
2356 		mutex_enter(&schpc_p->schpc_mutex);
2357 		schpc_p->schpc_slot[slot].state &=
2358 		    ~SCHPC_SLOTSTATE_EXECUTING;
2359 		cv_signal(&schpc_p->schpc_cv);
2360 		mutex_exit(&schpc_p->schpc_mutex);
2361 
2362 		kmem_free(event, sizeof (pcimsg_t));
2363 		return;
2364 	}
2365 
2366 	SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d",
2367 	    expander, board, SCHPC_SLOT_NUM(slot));
2368 
2369 	if (schpc_p->schpc_slot[slot].slot_ops == NULL) {
2370 		SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event "
2371 		    "for unregistered slot for expander=%d board=%d slot=%d",
2372 		    expander, board, SCHPC_SLOT_NUM(slot));
2373 
2374 		mutex_enter(&schpc_p->schpc_mutex);
2375 		schpc_p->schpc_slot[slot].state &=
2376 		    ~SCHPC_SLOTSTATE_EXECUTING;
2377 		cv_signal(&schpc_p->schpc_cv);
2378 		mutex_exit(&schpc_p->schpc_mutex);
2379 
2380 		kmem_free(event, sizeof (pcimsg_t));
2381 		return;
2382 	}
2383 
2384 	/* Slot Power Event */
2385 
2386 	if (event->pcimsg_type.pcimsg_slotevent.slot_power) {
2387 		SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event");
2388 		/*
2389 		 * The SC may have changed to slot power status.
2390 		 */
2391 		if (slotstatus.slot_power_on) {
2392 			schpc_p->schpc_slot[slot].state |=
2393 			    SCHPC_SLOTSTATE_CONNECTED;
2394 
2395 			hpc_slot_event_notify(
2396 			    schpc_p->schpc_slot[slot].slot_handle,
2397 			    HPC_EVENT_SLOT_POWER_ON, 0);
2398 		} else {
2399 			schpc_p->schpc_slot[slot].state &=
2400 			    ~SCHPC_SLOTSTATE_CONNECTED;
2401 
2402 			hpc_slot_event_notify(
2403 			    schpc_p->schpc_slot[slot].slot_handle,
2404 			    HPC_EVENT_SLOT_POWER_OFF, 0);
2405 		}
2406 	}
2407 
2408 	/* Adapter Insertion/Removal Event */
2409 
2410 	if (event->pcimsg_type.pcimsg_slotevent.slot_presence) {
2411 		if (slotstatus.slot_empty == PCIMSG_ON) {
2412 
2413 			/* Adapter Removed */
2414 
2415 			SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed");
2416 
2417 			if (schpc_p->schpc_slot[slot].state &
2418 			    SCHPC_SLOTSTATE_CONNECTED) {
2419 				/*
2420 				 * If the adapter has been removed while
2421 				 * there the slot is connected, it could be
2422 				 * due to a ENUM handling.
2423 				 */
2424 				cmn_err(CE_WARN, "Card removed from "
2425 				    "powered on slot at "
2426 				    "expander=%d board=%d slot=%d\n",
2427 				    expander, board, SCHPC_SLOT_NUM(slot));
2428 
2429 				schpc_p->schpc_slot[slot].state &=
2430 				    ~SCHPC_SLOTSTATE_EXECUTING;
2431 				rval = schpc_disconnect((caddr_t)schpc_p,
2432 				    schpc_p->schpc_slot[slot].slot_handle,
2433 				    0, 0);
2434 				mutex_enter(&schpc_p->schpc_mutex);
2435 				while (schpc_p->schpc_slot[slot].state &
2436 				    SCHPC_SLOTSTATE_EXECUTING) {
2437 					SCHPC_DEBUG0(D_EVENT,
2438 					    "schpc_event_handler - "
2439 					    "Slot is busy");
2440 					cv_wait(&schpc_p->schpc_cv,
2441 					    &schpc_p->schpc_mutex);
2442 				}
2443 
2444 				schpc_p->schpc_slot[slot].state |=
2445 				    SCHPC_SLOTSTATE_EXECUTING;
2446 
2447 				mutex_exit(&schpc_p->schpc_mutex);
2448 			}
2449 			schpc_p->schpc_slot[slot].state |=
2450 			    SCHPC_SLOTSTATE_OCC_GOOD;
2451 
2452 			schpc_p->schpc_slot[slot].state &=
2453 			    ~SCHPC_SLOTSTATE_PRESENT;
2454 
2455 			hpc_slot_event_notify(
2456 			    schpc_p->schpc_slot[slot].slot_handle,
2457 			    HPC_EVENT_SLOT_REMOVAL, 0);
2458 		} else {
2459 
2460 			/* Adapter Inserted */
2461 
2462 			SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted");
2463 
2464 			if (schpc_p->schpc_slot[slot].state &
2465 			    SCHPC_SLOTSTATE_PRESENT) {
2466 				/*
2467 				 * If the adapter is already present
2468 				 * throw the this event away.
2469 				 */
2470 
2471 				SCHPC_DEBUG0(D_EVENT,
2472 				    "Adapter is already present");
2473 
2474 				mutex_enter(&schpc_p->schpc_mutex);
2475 				schpc_p->schpc_slot[slot].state &=
2476 				    ~SCHPC_SLOTSTATE_EXECUTING;
2477 				cv_signal(&schpc_p->schpc_cv);
2478 				mutex_exit(&schpc_p->schpc_mutex);
2479 
2480 				kmem_free(event, sizeof (pcimsg_t));
2481 				return;
2482 			}
2483 
2484 			schpc_p->schpc_slot[slot].state |=
2485 			    SCHPC_SLOTSTATE_PRESENT;
2486 
2487 			schpc_p->schpc_slot[slot].state &=
2488 			    ~SCHPC_SLOTSTATE_CONNECTED;
2489 
2490 			hpc_slot_event_notify(
2491 			    schpc_p->schpc_slot[slot].slot_handle,
2492 			    HPC_EVENT_SLOT_INSERTION, 0);
2493 
2494 			if (schpc_p->schpc_slot[slot].state &
2495 			    SCHPC_SLOTSTATE_AUTOCFG_ENABLE) {
2496 				SCHPC_DEBUG0(D_EVENT, "Auto Configuration "
2497 				    "(Connect/Configure) Started");
2498 
2499 				schpc_p->schpc_slot[slot].state &=
2500 				    ~SCHPC_SLOTSTATE_EXECUTING;
2501 
2502 				rval = schpc_connect((caddr_t)schpc_p,
2503 				    schpc_p->schpc_slot[slot].slot_handle,
2504 				    0, 0);
2505 
2506 				if (rval) {
2507 					cmn_err(CE_WARN, "schpc/Event Handler -"
2508 					    " Can not connect");
2509 
2510 					mutex_enter(&schpc_p->schpc_mutex);
2511 					schpc_p->schpc_slot[slot].state &=
2512 					    ~SCHPC_SLOTSTATE_EXECUTING;
2513 					cv_signal(&schpc_p->schpc_cv);
2514 					mutex_exit(&schpc_p->schpc_mutex);
2515 
2516 					kmem_free(event, sizeof (pcimsg_t));
2517 					return;
2518 				}
2519 				mutex_enter(&schpc_p->schpc_mutex);
2520 				while (schpc_p->schpc_slot[slot].state &
2521 				    SCHPC_SLOTSTATE_EXECUTING) {
2522 					SCHPC_DEBUG0(D_EVENT,
2523 					    "schpc_event_handler - "
2524 					    "Slot is busy");
2525 					cv_wait(&schpc_p->schpc_cv,
2526 					    &schpc_p->schpc_mutex);
2527 				}
2528 
2529 				schpc_p->schpc_slot[slot].state |=
2530 				    SCHPC_SLOTSTATE_EXECUTING;
2531 
2532 				mutex_exit(&schpc_p->schpc_mutex);
2533 
2534 				hpc_slot_event_notify(
2535 				    schpc_p->schpc_slot[slot].slot_handle,
2536 				    HPC_EVENT_SLOT_CONFIGURE, 0);
2537 			} else {
2538 				schpc_setslotled(expander, board, slot,
2539 				    SERVICE_LED_ON);
2540 			}
2541 		}
2542 	}
2543 
2544 	/* ENUM# signal change event */
2545 
2546 	if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) {
2547 		/*
2548 		 * ENUM should only be received to the adapter remove
2549 		 * procedure.
2550 		 */
2551 
2552 		SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted");
2553 
2554 		schpc_setslotled(expander, board, slot, FAULT_LED_FLASH);
2555 
2556 		schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM;
2557 
2558 		hpc_slot_event_notify(
2559 		    schpc_p->schpc_slot[slot].slot_handle,
2560 		    HPC_EVENT_SLOT_ENUM, 0);
2561 	}
2562 
2563 	/* HEALTHY# signal change event */
2564 
2565 	if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) {
2566 
2567 		if (!slotstatus.slot_HEALTHY) {
2568 
2569 			SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED");
2570 
2571 			schpc_p->schpc_slot[slot].state &=
2572 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2573 
2574 			hpc_slot_event_notify(
2575 			    schpc_p->schpc_slot[slot].slot_handle,
2576 			    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2577 
2578 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2579 		} else {
2580 			SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK");
2581 
2582 			schpc_p->schpc_slot[slot].state |=
2583 			    SCHPC_SLOTSTATE_OCC_GOOD;
2584 
2585 			hpc_slot_event_notify(
2586 			    schpc_p->schpc_slot[slot].slot_handle,
2587 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
2588 
2589 			schpc_setslotled(expander, board, slot,
2590 			    FAULT_LED_OFF);
2591 		}
2592 	}
2593 
2594 	/* Good Power change event */
2595 
2596 	if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) {
2597 		if (slotstatus.slot_powergood == PCIMSG_ON) {
2598 
2599 			SCHPC_DEBUG0(D_EVENT,
2600 			    "Event Type: Slot Power Good Detected");
2601 
2602 			schpc_p->schpc_slot[slot].state |=
2603 			    SCHPC_SLOTSTATE_OCC_GOOD;
2604 
2605 			hpc_slot_event_notify(
2606 			    schpc_p->schpc_slot[slot].slot_handle,
2607 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
2608 
2609 			schpc_setslotled(expander, board, slot,
2610 			    FAULT_LED_OFF);
2611 		} else {
2612 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good "
2613 			    "Detected");
2614 
2615 			if (schpc_p->schpc_slot[slot].state &
2616 			    SCHPC_SLOTSTATE_CONNECTED) {
2617 
2618 				SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: "
2619 				    "power failed");
2620 
2621 				schpc_p->schpc_slot[slot].state &=
2622 				    ~SCHPC_SLOTSTATE_OCC_GOOD;
2623 
2624 				hpc_slot_event_notify(
2625 				    schpc_p->schpc_slot[slot].slot_handle,
2626 				    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2627 
2628 				schpc_setslotled(expander, board, slot,
2629 				    FAULT_LED_ON);
2630 			}
2631 		}
2632 	}
2633 
2634 	/* Power Fault change event */
2635 
2636 	if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) {
2637 		if (slotstatus.slot_powerfault == PCIMSG_ON) {
2638 
2639 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2640 			    "Detected");
2641 
2642 			schpc_p->schpc_slot[slot].state &=
2643 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2644 
2645 			hpc_slot_event_notify(
2646 			    schpc_p->schpc_slot[slot].slot_handle,
2647 			    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2648 
2649 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2650 		} else {
2651 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2652 			    "Cleared");
2653 
2654 			schpc_p->schpc_slot[slot].state |=
2655 			    SCHPC_SLOTSTATE_OCC_GOOD;
2656 
2657 			hpc_slot_event_notify(
2658 			    schpc_p->schpc_slot[slot].slot_handle,
2659 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
2660 
2661 			schpc_setslotled(expander, board, slot,
2662 			    FAULT_LED_OFF);
2663 		}
2664 	}
2665 	mutex_enter(&schpc_p->schpc_mutex);
2666 	schpc_p->schpc_slot[slot].state &=
2667 	    ~SCHPC_SLOTSTATE_EXECUTING;
2668 	cv_signal(&schpc_p->schpc_cv);
2669 	mutex_exit(&schpc_p->schpc_mutex);
2670 
2671 	kmem_free(event, sizeof (pcimsg_t));
2672 }
2673 
2674 
2675 /*
2676  * schpc_event_filter
2677  *
2678  * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the
2679  * schpc_event_taskq for processing by the schpc_event_handler _if_
2680  * hotpluggable pci slots have been registered; otherwise, the
2681  * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox
2682  * open for future messages.
2683  */
2684 static void
2685 schpc_event_filter(pcimsg_t *pmsg)
2686 {
2687 	if (slots_registered == B_TRUE) {
2688 
2689 		pcimsg_t *pevent;
2690 
2691 		/*
2692 		 * If hotpluggable pci slots have been registered then enqueue
2693 		 * the event onto the schpc_event_taskq for processing.
2694 		 */
2695 
2696 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2697 		    "slots_registered = B_TRUE");
2698 
2699 		pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP);
2700 		bcopy(pmsg, pevent, sizeof (pcimsg_t));
2701 
2702 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2703 		    "event alloc'd");
2704 
2705 		if (taskq_dispatch(schpc_event_taskq, schpc_event_handler,
2706 		    (void *)pevent, TQ_SLEEP) == NULL) {
2707 			cmn_err(CE_WARN, "schpc: schpc_event_filter - "
2708 			    "taskq_dispatch failed to enqueue event");
2709 			kmem_free(pevent, sizeof (pcimsg_t));
2710 			return;
2711 		}
2712 
2713 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2714 		    "event was taskq_dispatch'ed to schpc_event_handler");
2715 	} else {
2716 		/*
2717 		 * Oops, schpc received an event _before_ the slots have been
2718 		 * registered. In that case there is no choice but to toss
2719 		 * the event.
2720 		 */
2721 		cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding "
2722 		    "premature event");
2723 	}
2724 }
2725 
2726 
2727 /*
2728  * schpc_msg_thread
2729  * A stand-alone thread that monitors the incoming mailbox for
2730  * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from
2731  * the mailbox for processing.
2732  *
2733  * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the
2734  * schpc_replylist, and the waiting thread is notified that its REPLY
2735  * message has arrived; otherwise, if no REPLY match is found, then it is
2736  * discarded.
2737  *
2738  * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed
2739  * by the schpc_event_handler.
2740  *
2741  * The schpc_msg_thread is started in _init().
2742  */
2743 void
2744 schpc_msg_thread(void)
2745 {
2746 	int			err;
2747 	uint32_t		type;
2748 	uint32_t		cmd;
2749 	uint64_t		transid;
2750 	uint32_t		length;
2751 	pcimsg_t		msg;
2752 
2753 	SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running");
2754 
2755 	/* CONSTCOND */
2756 	while (1) {
2757 
2758 		/* setup wildcard arguments */
2759 		type = 0;
2760 		cmd = 0;
2761 		transid = 0;
2762 		length = sizeof (pcimsg_t);
2763 		bzero(&msg, sizeof (pcimsg_t));
2764 
2765 		err = mboxsc_getmsg(KEY_SCPC, &type, &cmd,
2766 		    &transid, &length, (void *)&msg,
2767 		    schpc_timeout_getmsg);
2768 
2769 		if (err) {
2770 			switch (err) {
2771 
2772 			/*FALLTHROUGH*/
2773 			case ETIMEDOUT:
2774 			case EAGAIN:
2775 				continue;
2776 
2777 			default:
2778 				/*
2779 				 * unfortunately, we can't do very much here
2780 				 * because we're wildcarding mboxsc_getmsg
2781 				 * so if it encounters an error, we can't
2782 				 * identify which transid it belongs to.
2783 				 */
2784 				cmn_err(CE_WARN,
2785 				"schpc - mboxsc_getmsg failed, err=0x%x", err);
2786 				delay(drv_usectohz(100000));
2787 				continue;
2788 			}
2789 		}
2790 
2791 		if (msg.pcimsg_revision != PCIMSG_REVISION) {
2792 			/*
2793 			 * This version of the schpc driver only understands
2794 			 * version 1.0 of the PCI Hot Plug Message format.
2795 			 */
2796 			cmn_err(CE_WARN, " schpc: schpc_msg_thread - "
2797 			    "discarding event w/ unknown message version %x",
2798 			    msg.pcimsg_revision);
2799 			continue;
2800 		}
2801 
2802 		switch (type) {
2803 
2804 		case MBOXSC_MSG_EVENT:
2805 			schpc_event_filter(&msg);
2806 			break;
2807 
2808 		case MBOXSC_MSG_REPLY:
2809 			schpc_reply_handler(&msg, type, cmd, transid, length);
2810 			break;
2811 
2812 		default:
2813 			cmn_err(CE_WARN,
2814 			    "schpc - mboxsc_getmsg unknown msg"
2815 			    " type=0x%x", type);
2816 			break;
2817 		}
2818 	}
2819 	/* this thread never exits */
2820 }
2821 
2822 
2823 void
2824 schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
2825 			uint64_t transid, uint32_t length)
2826 {
2827 	schpc_replylist_t	*entry;
2828 
2829 	mutex_enter(&schpc_replylist_mutex);
2830 	entry = schpc_replylist_first;
2831 	while (entry != NULL) {
2832 		if (entry->transid == transid) {
2833 			break;
2834 		} else
2835 			entry = entry->next;
2836 	}
2837 	if (entry) {
2838 		SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2839 		    "schpc_reply_handler() - 0x%lx transid reply "
2840 		    "received", transid);
2841 
2842 		mutex_enter(&entry->reply_lock);
2843 		if (entry->reply_cexit == B_FALSE) {
2844 			SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2845 			    "schpc_reply_handler() - 0x%lx transid"
2846 			    " cv_signal waiting thread", transid);
2847 
2848 			/*
2849 			 * emulate mboxsc_getmsg by copying the reply
2850 			 */
2851 			entry->type = type;
2852 			entry->cmd = cmd;
2853 			entry->transid = transid;
2854 			entry->length = length;
2855 			bcopy((caddr_t)pmsg, &entry->reply, length);
2856 
2857 			/* reply was received */
2858 			entry->reply_recvd = B_TRUE;
2859 
2860 			/*
2861 			 * wake up thread waiting for reply with transid
2862 			 */
2863 			cv_signal(&entry->reply_cv);
2864 		}
2865 		mutex_exit(&entry->reply_lock);
2866 	} else {
2867 		cmn_err(CE_WARN, "schpc - no match for transid 0x%lx",
2868 		    transid);
2869 	}
2870 	mutex_exit(&schpc_replylist_mutex);
2871 }
2872 
2873 
2874 /*
2875  * schpc_putrequest
2876  *
2877  * A wrapper around the synchronous call mboxsc_putmsg().
2878  */
2879 int
2880 schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
2881 		uint32_t length, void *datap, clock_t timeout,
2882 		schpc_replylist_t **entryp)
2883 {
2884 	int rval;
2885 
2886 	/* add the request to replylist to keep track of outstanding requests */
2887 	*entryp = schpc_replylist_link(cmd, *transidp, length);
2888 
2889 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2890 	    "0x%lx transid mboxsc_putmsg called", *transidp);
2891 
2892 	/* wait synchronously for request to be sent */
2893 	rval = mboxsc_putmsg(key, type, cmd, transidp, length,
2894 	    (void *)datap, timeout);
2895 
2896 	SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2897 	    "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval);
2898 
2899 	/* if problem is encountered then remove the request from replylist */
2900 	if (rval)
2901 		schpc_replylist_unlink(*entryp);
2902 
2903 	return (rval);
2904 }
2905 
2906 
2907 /*
2908  * schpc_getreply
2909  *
2910  * Wait for the schpc_msg_thread to respond that a matching reply has
2911  * arrived; otherwise, timeout and remove the entry from the schpc_replylist.
2912  */
2913 /*ARGSUSED*/
2914 int
2915 schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
2916 		uint64_t *transidp, uint32_t *lengthp, void *datap,
2917 		clock_t timeout, schpc_replylist_t *listp)
2918 {
2919 	int rc = 0;
2920 
2921 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2922 	    "schpc_getreply() - 0x%lx transid waiting for reply",
2923 	    *transidp);
2924 
2925 	/*
2926 	 * wait here until schpc_msg_thread because it's always
2927 	 * looking for reply messages
2928 	 */
2929 	mutex_enter(&listp->reply_lock);
2930 
2931 	while (listp->reply_recvd == B_FALSE) {
2932 		/*
2933 		 * wait for reply or timeout
2934 		 */
2935 		rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock,
2936 		    ddi_get_lbolt() + drv_usectohz(timeout * 1000));
2937 		switch (rc) {
2938 		case -1: /* most likely a timeout, but check anyway */
2939 
2940 			/* message was received after all */
2941 			if (listp->reply_recvd == B_TRUE)
2942 				break;
2943 
2944 			/* no, it's really a timeout */
2945 			listp->reply_cexit = B_TRUE;
2946 			mutex_exit(&listp->reply_lock);
2947 			cmn_err(CE_WARN,
2948 			"schpc - 0x%lx transid reply timed out", *transidp);
2949 			schpc_replylist_unlink(listp);
2950 			return (ETIMEDOUT);
2951 
2952 		default:
2953 			break;
2954 		}
2955 	}
2956 
2957 	*typep = listp->type;
2958 	*cmdp = listp->cmd;
2959 	*transidp = listp->transid;
2960 	*lengthp = listp->length;
2961 	bcopy((caddr_t)&listp->reply, datap, *lengthp);
2962 	mutex_exit(&listp->reply_lock);
2963 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2964 	    "schpc_getreply() - 0x%lx transid received", *transidp);
2965 	schpc_replylist_unlink(listp);
2966 	return (0);
2967 }
2968 
2969 
2970 /*
2971  * schpc_replylist_unlink
2972  *
2973  * Deallocate a schpc_replylist_t element.
2974  */
2975 void
2976 schpc_replylist_unlink(schpc_replylist_t *entry)
2977 {
2978 #if DEBUG
2979 	schpc_replylist_t *dbg_entry;
2980 #endif	/* DEBUG */
2981 
2982 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2983 	    "schpc_replylist_unlink() - 0x%lx transid deleted from replylist",
2984 	    entry->transid);
2985 
2986 	mutex_enter(&schpc_replylist_mutex);
2987 	if (entry->prev) {
2988 		entry->prev->next = entry->next;
2989 		if (entry->next)
2990 			entry->next->prev = entry->prev;
2991 	} else {
2992 		schpc_replylist_first = entry->next;
2993 		if (entry->next)
2994 			entry->next->prev = NULL;
2995 	}
2996 	if (entry == schpc_replylist_last) {
2997 		schpc_replylist_last = entry->prev;
2998 	}
2999 	kmem_free(entry, sizeof (schpc_replylist_t));
3000 	schpc_replylist_count--;
3001 
3002 #if DEBUG
3003 	if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3004 		dbg_entry = schpc_replylist_first;
3005 		cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist "
3006 		    "count = %d\n", schpc_replylist_count);
3007 		while (dbg_entry != NULL) {
3008 			cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - "
3009 			    "0x%lx transid\n", dbg_entry->transid);
3010 			dbg_entry = dbg_entry->next;
3011 		}
3012 	}
3013 #endif	/* DEBUG  */
3014 
3015 	mutex_exit(&schpc_replylist_mutex);
3016 }
3017 
3018 
3019 /*
3020  * schpc_replylist_link
3021  *
3022  * Allocate and initialize a schpc_replylist_t element.
3023  */
3024 schpc_replylist_t *
3025 schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length)
3026 {
3027 	schpc_replylist_t *entry;
3028 #if DEBUG
3029 	schpc_replylist_t *dbg_entry;
3030 #endif	/* DEBUG */
3031 
3032 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
3033 	    "schpc_replylist_link() - 0x%lx transid inserting into replylist",
3034 	    transid);
3035 
3036 	entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP);
3037 	mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL);
3038 	cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL);
3039 	entry->type = MBOXSC_MSG_REPLY;
3040 	entry->cmd  = cmd;
3041 	entry->transid  = transid;
3042 	entry->length  = length;
3043 	entry->reply_recvd = B_FALSE;
3044 	entry->reply_cexit = B_FALSE;
3045 
3046 	mutex_enter(&schpc_replylist_mutex);
3047 	if (schpc_replylist_last) {
3048 		entry->prev = schpc_replylist_last;
3049 		schpc_replylist_last->next = entry;
3050 		schpc_replylist_last = entry;
3051 	} else {
3052 		schpc_replylist_last = schpc_replylist_first = entry;
3053 	}
3054 
3055 	schpc_replylist_count++;
3056 
3057 #if DEBUG
3058 	if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3059 		dbg_entry = schpc_replylist_first;
3060 		cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist "
3061 		    "count = %d\n", schpc_replylist_count);
3062 		while (dbg_entry != NULL) {
3063 			cmn_err(CE_CONT, "schpc: schpc_replylist_link() - "
3064 			    "0x%lx transid\n", dbg_entry->transid);
3065 			dbg_entry = dbg_entry->next;
3066 		}
3067 	}
3068 #endif	/* DEBUG  */
3069 
3070 	mutex_exit(&schpc_replylist_mutex);
3071 
3072 	return (entry);
3073 }
3074 
3075 
3076 /*
3077  * schpc_getslotstatus
3078  *
3079  * Issues a Get Slot Status command to the System Controller
3080  * for a specific slot.
3081  */
3082 static int
3083 schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3084     pci_getslot_t *slotstatus)
3085 {
3086 	pcimsg_t	request;
3087 	pcimsg_t	reply;
3088 	int		rval;
3089 	uint32_t	type, cmd, length;
3090 	uint64_t	transid;
3091 	schpc_replylist_t *entry;
3092 
3093 	SCHPC_DEBUG4(D_GETSLOTSTATUS,
3094 	    "schpc_getslotstatus(expander=%d board=%d "
3095 	    "slot=%d slotstatus=0x%p", expander, board,
3096 	    SCHPC_SLOT_NUM(slot), slotstatus);
3097 
3098 	if (schpc_p == NULL) {
3099 		return (1);
3100 	}
3101 
3102 	bzero(&request, sizeof (pcimsg_t));
3103 
3104 	request.pcimsg_node = expander;
3105 	request.pcimsg_board = board;
3106 	request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3107 	request.pcimsg_revision = PCIMSG_REVISION;
3108 	request.pcimsg_command = PCIMSG_GETSLOTSTATUS;
3109 
3110 	type = MBOXSC_MSG_REQUEST;
3111 	cmd = PCIMSG_GETSLOTSTATUS;
3112 	transid =  schpc_gettransid(schpc_p, slot);
3113 	length = sizeof (pcimsg_t);
3114 
3115 	SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3116 	    "0x%lx transid schpc_putrequest called", transid);
3117 
3118 	rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3119 	    (void *)&request, schpc_timeout_putmsg, &entry);
3120 
3121 	SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3122 	    "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3123 
3124 	if (rval) {
3125 		return (rval);
3126 	}
3127 
3128 	bzero(&reply, sizeof (pcimsg_t));
3129 	type = MBOXSC_MSG_REPLY;
3130 
3131 	SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3132 	    "0x%lx transid schpc_getreply called", transid);
3133 
3134 	rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3135 	    (void *)&reply, schpc_timeout_getmsg, entry);
3136 
3137 	SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3138 	    "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3139 
3140 	if (rval == 0) {
3141 		*slotstatus = reply.pcimsg_type.pcimsg_getslot;
3142 
3143 		SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()");
3144 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_power_on %x",
3145 		    reply.pcimsg_type.pcimsg_getslot.slot_power_on);
3146 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_powergood %x",
3147 		    reply.pcimsg_type.pcimsg_getslot.slot_powergood);
3148 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_powerfault %x",
3149 		    reply.pcimsg_type.pcimsg_getslot.slot_powerfault);
3150 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_empty %x",
3151 		    reply.pcimsg_type.pcimsg_getslot.slot_empty);
3152 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_freq_cap %x",
3153 		    reply.pcimsg_type.pcimsg_getslot.slot_freq_cap);
3154 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_freq_setting %x",
3155 		    reply.pcimsg_type.pcimsg_getslot.slot_freq_setting);
3156 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_condition %x",
3157 		    reply.pcimsg_type.pcimsg_getslot.slot_condition);
3158 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_HEALTHY %x",
3159 		    reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY);
3160 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_ENUM %x",
3161 		    reply.pcimsg_type.pcimsg_getslot.slot_ENUM);
3162 	}
3163 
3164 	return (rval);
3165 }
3166 
3167 
3168 /*
3169  * schpc_setslotstatus
3170  *
3171  * Issues a Set Slot Status command to the System Controller
3172  * for a specific slot.
3173  */
3174 static int
3175 schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3176     pci_setslot_t *slotstatus)
3177 {
3178 	pcimsg_t	request;
3179 	pcimsg_t	reply;
3180 	int		rval;
3181 	uint32_t	type, cmd, length;
3182 	uint64_t	transid;
3183 	schpc_replylist_t *entry;
3184 
3185 	SCHPC_DEBUG4(D_SETSLOTSTATUS,
3186 	    "schpc_setslotstatus(expander=%d board=%d "
3187 	    "slot=%d slotstatus=0x%p", expander, board,
3188 	    SCHPC_SLOT_NUM(slot), slotstatus);
3189 
3190 	bzero(&request, sizeof (pcimsg_t));
3191 
3192 	if (schpc_p == NULL) {
3193 		return (1);
3194 	}
3195 
3196 	request.pcimsg_node = expander;
3197 	request.pcimsg_board = board;
3198 	request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3199 	request.pcimsg_revision = PCIMSG_REVISION;
3200 	request.pcimsg_command = PCIMSG_SETSLOTSTATUS;
3201 
3202 	request.pcimsg_type.pcimsg_setslot = *slotstatus;
3203 
3204 	SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change");
3205 	SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d",
3206 	    slotstatus->slot_led_power,
3207 	    slotstatus->slot_led_service,
3208 	    slotstatus->slot_led_fault);
3209 
3210 	type = MBOXSC_MSG_REQUEST;
3211 	cmd = PCIMSG_SETSLOTSTATUS;
3212 	transid =  schpc_gettransid(schpc_p, slot);
3213 	length = sizeof (pcimsg_t);
3214 
3215 	SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3216 	    "0x%lx transid schpc_putrequest called", transid);
3217 
3218 	rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3219 	    (void *)&request, schpc_timeout_putmsg, &entry);
3220 
3221 	SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3222 	    "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3223 
3224 	if (rval) {
3225 		return (rval);
3226 	}
3227 
3228 	bzero(&reply, sizeof (pcimsg_t));
3229 	type = MBOXSC_MSG_REPLY;
3230 
3231 	SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3232 	    "0x%lx transid schpc_getreply called", transid);
3233 
3234 	rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3235 	    (void *)&reply, schpc_timeout_getmsg, entry);
3236 
3237 	SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3238 	    "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3239 
3240 	if (rval == 0) {
3241 		slotstatus->slot_replystatus =
3242 		    reply.pcimsg_type.pcimsg_setslot.slot_replystatus;
3243 	}
3244 
3245 	return (rval);
3246 }
3247 
3248 /*
3249  * schpc_setslotled
3250  *
3251  * Changes the attention indicators for a given slot.
3252  */
3253 static void
3254 schpc_setslotled(int expander, int board, int slot, uint32_t led_state)
3255 {
3256 
3257 	pci_setslot_t	setslot;
3258 
3259 	if (schpc_p == NULL) {
3260 		return;
3261 	}
3262 
3263 	schpc_init_setslot_message(&setslot);
3264 
3265 	if (led_state & POWER_LED_ON) {
3266 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
3267 	}
3268 	if (led_state & POWER_LED_OFF) {
3269 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF;
3270 	}
3271 	if (led_state & POWER_LED_FLASH) {
3272 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH;
3273 	}
3274 	if (led_state & SERVICE_LED_ON) {
3275 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON;
3276 	}
3277 	if (led_state & SERVICE_LED_OFF) {
3278 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF;
3279 	}
3280 	if (led_state & SERVICE_LED_FLASH) {
3281 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH;
3282 	}
3283 	if (led_state & FAULT_LED_ON) {
3284 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON;
3285 	}
3286 	if (led_state & FAULT_LED_OFF) {
3287 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF;
3288 	}
3289 	if (led_state & FAULT_LED_FLASH) {
3290 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH;
3291 	}
3292 
3293 	switch (schpc_p->schpc_slot[slot].led.led_power) {
3294 	case PCIMSG_LED_ON:
3295 		setslot.slot_led_power = PCIMSG_LED_ON;
3296 		break;
3297 	case PCIMSG_LED_OFF:
3298 		setslot.slot_led_power = PCIMSG_LED_OFF;
3299 		break;
3300 	case PCIMSG_LED_FLASH:
3301 		setslot.slot_led_power = PCIMSG_LED_FLASH;
3302 		break;
3303 	}
3304 	switch (schpc_p->schpc_slot[slot].led.led_service) {
3305 	case PCIMSG_LED_ON:
3306 		setslot.slot_led_service = PCIMSG_LED_ON;
3307 		break;
3308 	case PCIMSG_LED_OFF:
3309 		setslot.slot_led_service = PCIMSG_LED_OFF;
3310 		break;
3311 	case PCIMSG_LED_FLASH:
3312 		setslot.slot_led_service = PCIMSG_LED_FLASH;
3313 		break;
3314 	}
3315 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
3316 	case PCIMSG_LED_ON:
3317 		setslot.slot_led_fault = PCIMSG_LED_ON;
3318 		break;
3319 	case PCIMSG_LED_OFF:
3320 		setslot.slot_led_fault = PCIMSG_LED_OFF;
3321 		break;
3322 	case PCIMSG_LED_FLASH:
3323 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
3324 		break;
3325 	}
3326 
3327 	(void) schpc_setslotstatus(expander, board, slot, &setslot);
3328 }
3329 
3330 /*
3331  * schpc_init_setslot_message
3332  *
3333  * Initialize Set Slot Message before using it.
3334  */
3335 static void
3336 schpc_init_setslot_message(pci_setslot_t *setslot)
3337 {
3338 	/*
3339 	 * Initialize Set Slot Command.
3340 	 */
3341 	setslot->slot_power_on = PCIMSG_OFF;
3342 	setslot->slot_power_off = PCIMSG_OFF;
3343 	setslot->slot_led_power = PCIMSG_LED_OFF;
3344 	setslot->slot_led_service = PCIMSG_LED_OFF;
3345 	setslot->slot_led_fault = PCIMSG_LED_OFF;
3346 	setslot->slot_disable_ENUM = PCIMSG_OFF;
3347 	setslot->slot_enable_ENUM = PCIMSG_OFF;
3348 	setslot->slot_disable_HEALTHY = PCIMSG_OFF;
3349 	setslot->slot_enable_HEALTHY = PCIMSG_OFF;
3350 }
3351 
3352 /*
3353  * schpc_gettransid
3354  *
3355  * Builds a unique transaction ID.
3356  */
3357 static uint64_t
3358 schpc_gettransid(schpc_t *schpc_p, int slot)
3359 {
3360 	uint64_t	trans_id;
3361 
3362 	mutex_enter(&schpc_p->schpc_mutex);
3363 
3364 	if (++schpc_p->schpc_transid == 0)
3365 		schpc_p->schpc_transid = 1;
3366 
3367 	trans_id = (schpc_p->schpc_slot[slot].expander<<24) |
3368 	    (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid;
3369 
3370 	mutex_exit(&schpc_p->schpc_mutex);
3371 
3372 	SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning",
3373 	    trans_id);
3374 
3375 	return (trans_id);
3376 }
3377 
3378 /*
3379  * schpc_slot_get_index
3380  *
3381  * get slot table index from the slot handle
3382  */
3383 static int
3384 schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot)
3385 {
3386 	int	i;
3387 	int	rval = -1;
3388 
3389 	ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex));
3390 
3391 	for (i = 0; i < schpc_p->schpc_number_of_slots; i++) {
3392 		if (schpc_p->schpc_slot[i].slot_handle == slot)
3393 			return (i);
3394 	}
3395 
3396 	return (rval);
3397 }
3398 
3399 /*
3400  * schpc_register_all_slots
3401  *
3402  * Search device tree for pci nodes and register attachment points
3403  * for all hot pluggable slots.
3404  */
3405 /*ARGSUSED*/
3406 static void
3407 schpc_register_all_slots(schpc_t *schpc_p)
3408 {
3409 	int		slot = 0;
3410 	char		caddr[64];
3411 	dev_info_t	*pci_dip = NULL;
3412 	find_dev_t	find_dev;
3413 	int		leaf, schizo, expander, portid, offset;
3414 
3415 	SCHPC_DEBUG1(D_ATTACH,
3416 	    "schpc_register_all_slots(schpc_p=%p)", schpc_p);
3417 
3418 	/*
3419 	 * Allow the event_handler to start processing unsolicited
3420 	 * events now that slots are about to be registered.
3421 	 */
3422 	slots_registered = B_TRUE;
3423 
3424 	for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) {
3425 
3426 		leaf = SCHPC_SLOT_LEAF(slot);
3427 		schizo = SCHPC_SLOT_SCHIZO(slot);
3428 		expander = SCHPC_SLOT_EXPANDER(slot);
3429 
3430 		if (schizo == 0)
3431 			portid = 0x1c;
3432 		else
3433 			portid = 0x1d;
3434 
3435 		if (leaf == 0)
3436 			offset = 0x600000;
3437 		else
3438 			offset = 0x700000;
3439 
3440 		portid = (expander << 5) | portid;
3441 
3442 		(void) sprintf(caddr, "%x,%x", portid, offset);
3443 
3444 		SCHPC_DEBUG3(D_ATTACH,
3445 		    "schpc_register_all_slots: searching for pci@%s"
3446 		    " schizo=%d, leaf=%d", caddr, schizo, leaf);
3447 
3448 		find_dev.cname = "pci";
3449 		find_dev.caddr = caddr;
3450 		find_dev.schizo = schizo;
3451 		find_dev.leaf = leaf;
3452 		find_dev.dip = NULL;
3453 
3454 		/* root node doesn't have to be held */
3455 		ddi_walk_devs(ddi_root_node(), schpc_match_dip,
3456 		    &find_dev);
3457 
3458 		pci_dip = find_dev.dip;
3459 
3460 		if (pci_dip == NULL) {
3461 
3462 			SCHPC_DEBUG1(D_ATTACH,
3463 			    "schpc_register_all_slots: pci@%s NOT FOUND",
3464 			    caddr);
3465 
3466 			continue;
3467 		}
3468 
3469 		SCHPC_DEBUG2(D_ATTACH,
3470 		    "schpc_register_all_slots: pci@%s FOUND dip=0x%p",
3471 		    caddr, pci_dip);
3472 
3473 		(void) schpc_add_pci(pci_dip);
3474 
3475 		/*
3476 		 * Release hold acquired in schpc_match_dip()
3477 		 */
3478 		ndi_rele_devi(pci_dip);
3479 	}
3480 
3481 	SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit");
3482 
3483 	thread_exit();
3484 }
3485 
3486 /*
3487  * schpc_add_pci
3488  *
3489  * Routine to add attachments points associated with a pci node.
3490  * Can be call externally by DR when configuring a PCI I/O Board.
3491  */
3492 int
3493 schpc_add_pci(dev_info_t *bdip)
3494 {
3495 	int		portid;
3496 	int		expander, board, schizo, leaf, slot, status;
3497 	char		ap_id[MAXNAMELEN];
3498 	char		caddr[64];
3499 	char		*naddr;
3500 	hpc_slot_info_t	slot_info;
3501 	hpc_slot_ops_t	*slot_ops;
3502 	dev_info_t 	*sdip = bdip;
3503 
3504 	SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", sdip);
3505 
3506 	if (schpc_p == NULL) {
3507 		/*
3508 		 * The schpc driver has not been attached yet.
3509 		 */
3510 		return (DDI_SUCCESS);
3511 	}
3512 
3513 	if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) {
3514 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n", sdip);
3515 		return (DDI_FAILURE);
3516 	}
3517 
3518 	expander = schpc_getexpander(sdip);
3519 	board = schpc_getboard(sdip);
3520 
3521 	switch (portid & 0x1f) {
3522 
3523 	case 0x1c:
3524 		schizo = 0;
3525 		break;
3526 	case 0x1d:
3527 		schizo = 1;
3528 		break;
3529 	default:
3530 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3531 		    "Invalid pci portid 0x%x\n", sdip, portid);
3532 		return (DDI_FAILURE);
3533 	}
3534 
3535 	naddr = ddi_get_name_addr(sdip);
3536 	if (naddr == NULL) {
3537 		SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr"
3538 		    "(0x%p) returns null", sdip);
3539 		return (DDI_FAILURE);
3540 	}
3541 
3542 	(void) sprintf(caddr, "%x,600000", portid);
3543 
3544 	if (strcmp(caddr, naddr) == 0) {
3545 		leaf = 0;
3546 	} else {
3547 		(void) sprintf(caddr, "%x,700000", portid);
3548 		if (strcmp(caddr, naddr) == 0) {
3549 			char *name;
3550 
3551 			leaf = 1;
3552 			name = ddi_binding_name(sdip);
3553 			if ((strcmp(name, "pci108e,8002") == 0) &&
3554 			    (schizo == 0)) {
3555 				int circ;
3556 				dev_info_t *cdip;
3557 				/*
3558 				 * XMITS 0 Leaf B will have its hot
3559 				 * pluggable slot off a PCI-PCI bridge,
3560 				 * which is the only child.
3561 				 */
3562 				ndi_devi_enter(sdip, &circ);
3563 				cdip = ddi_get_child(sdip);
3564 				if (cdip == NULL) {
3565 					cmn_err(CE_WARN,
3566 					    "schpc_add_pci(dip=0x%p) - "
3567 					    "Invalid pci name addr %s\n",
3568 					    sdip, naddr);
3569 					ndi_devi_exit(sdip, circ);
3570 					return (DDI_FAILURE);
3571 				}
3572 				ndi_devi_exit(sdip, circ);
3573 				sdip = cdip;
3574 			}
3575 		} else {
3576 			cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3577 			    "Invalid pci name addr %s\n", sdip, naddr);
3578 			return (DDI_FAILURE);
3579 		}
3580 	}
3581 
3582 	/* create a slot table index */
3583 	slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf);
3584 
3585 	if (schpc_p->schpc_slot[slot].devi) {
3586 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3587 		    "pci node already registered\n", sdip);
3588 		return (DDI_FAILURE);
3589 	}
3590 
3591 	/*
3592 	 * There is no need to hold the dip while saving it in
3593 	 * the devi field below. The dip is never dereferenced.
3594 	 * (If that changes, this code should be modified).
3595 	 * We want to avoid holding the dip here because it
3596 	 * prevents DR.
3597 	 *
3598 	 * NOTE: Even though the slot on XMITS0 Leaf-B
3599 	 * is connected to a pci_pci bridge, we will be saving
3600 	 * the busdip in this datastructure. This will make
3601 	 * it easier to identify the dip being removed in
3602 	 * schpc_remove_pci().
3603 	 */
3604 	schpc_p->schpc_slot[slot].devi = bdip;
3605 
3606 	schpc_p->schpc_slot[slot].expander = expander;
3607 	schpc_p->schpc_slot[slot].board = board;
3608 	schpc_p->schpc_slot[slot].schizo = schizo;
3609 	schpc_p->schpc_slot[slot].leaf = leaf;
3610 
3611 	/*
3612 	 * Starcat PCI slots are always PCI device 1.
3613 	 */
3614 	schpc_p->schpc_slot[slot].pci_id = 1;
3615 
3616 	schpc_buildapid(sdip, slot, (char *)&ap_id);
3617 
3618 	(void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id);
3619 
3620 	/* safe to call ddi_pathname(): bdip is held */
3621 	(void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path);
3622 
3623 	status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot));
3624 	switch (status) {
3625 		case RSV_UNKNOWN:
3626 		case RSV_PRESENT:
3627 		case RSV_MISS:
3628 		case RSV_PASS:
3629 		case RSV_EMPTY_CASSETTE:
3630 
3631 			/*
3632 			 * Test the condition of the slot.
3633 			 */
3634 			schpc_test((caddr_t)schpc_p, slot, 0, 0);
3635 			break;
3636 		case RSV_BLACK:
3637 			schpc_p->schpc_slot[slot].state = 0;
3638 			cmn_err(CE_WARN, "schpc: PCI card blacklisted: "
3639 			    "expander=%d board=%d slot=%d\n", expander,
3640 			    board, SCHPC_SLOT_NUM(slot));
3641 			break;
3642 		default:
3643 			schpc_p->schpc_slot[slot].state = 0;
3644 			cmn_err(CE_WARN, "schpc: PCI card failed by POST: "
3645 			    "expander=%d board=%d slot=%d failure=0x%x\n",
3646 			    expander, board, SCHPC_SLOT_NUM(slot), status);
3647 			break;
3648 	}
3649 
3650 	if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) {
3651 
3652 		/* allocate slot ops */
3653 
3654 		slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
3655 		schpc_p->schpc_slot[slot].slot_ops = slot_ops;
3656 
3657 		/*
3658 		 * Default to Autoconfiguration disabled.
3659 		 */
3660 		schpc_p->schpc_slot[slot].state &=
3661 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
3662 
3663 		/*
3664 		 * Fill in the slot information structure that
3665 		 * describes the slot.
3666 		 */
3667 		slot_info.version = HPC_SLOT_OPS_VERSION;
3668 
3669 		if (schpc_p->schpc_hotplugmodel ==
3670 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG)
3671 			slot_info.slot_type = HPC_SLOT_TYPE_PCI;
3672 		else
3673 			slot_info.slot_type = HPC_SLOT_TYPE_CPCI;
3674 
3675 		slot_info.slot.pci.device_number =
3676 		    schpc_p->schpc_slot[slot].pci_id;
3677 
3678 		slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
3679 
3680 		if (schpc_use_legacy_apid)
3681 			slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE;
3682 		else
3683 			slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
3684 			    HPC_SLOT_CREATE_DEVLINK;
3685 
3686 		strcpy(slot_info.slot.pci.slot_logical_name,
3687 		    schpc_p->schpc_slot[slot].ap_id);
3688 
3689 		/*
3690 		 * Fill in the slot ops structure that tells
3691 		 * the Hot Plug Services what function we
3692 		 * support.
3693 		 */
3694 		slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
3695 		if (schpc_p->schpc_hotplugmodel ==
3696 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
3697 			slot_ops->hpc_op_connect = schpc_connect;
3698 			slot_ops->hpc_op_disconnect = schpc_disconnect;
3699 			slot_ops->hpc_op_insert = NULL;
3700 			slot_ops->hpc_op_remove = NULL;
3701 			slot_ops->hpc_op_control = schpc_pci_control;
3702 		} else {
3703 			slot_ops->hpc_op_connect = NULL;
3704 			slot_ops->hpc_op_disconnect = NULL;
3705 			slot_ops->hpc_op_insert = NULL;
3706 			slot_ops->hpc_op_remove = NULL;
3707 			slot_ops->hpc_op_control = schpc_cpci_control;
3708 		}
3709 
3710 		SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC "
3711 		    "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s",
3712 		    schpc_p->schpc_slot[slot].nexus_path,
3713 		    schpc_p, SCHPC_SLOT_NUM(slot),
3714 		    slot_info.slot.pci.device_number,
3715 		    slot_info.slot.pci.slot_logical_name);
3716 
3717 		if (hpc_slot_register(schpc_p->schpc_devi,
3718 		    schpc_p->schpc_slot[slot].nexus_path, &slot_info,
3719 		    &schpc_p->schpc_slot[slot].slot_handle,
3720 		    slot_ops, (caddr_t)schpc_p, 0) != 0) {
3721 
3722 			/*
3723 			 * If the slot can not be registered,
3724 			 * then the slot_ops need to be freed.
3725 			 */
3726 			cmn_err(CE_WARN, "schpc%d Unable to Register "
3727 			    "Slot %s", schpc_p->schpc_instance,
3728 			    slot_info.slot.pci.slot_logical_name);
3729 
3730 			hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops);
3731 
3732 			schpc_p->schpc_slot[slot].slot_ops = NULL;
3733 
3734 			return (DDI_FAILURE);
3735 		}
3736 
3737 		/*
3738 		 * We are ready to take commands from the HPC Services.
3739 		 */
3740 		schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED;
3741 	}
3742 
3743 	return (DDI_SUCCESS);
3744 }
3745 
3746 /*
3747  * schpc_remove_pci
3748  *
3749  * Routine to remove attachments points associated with a pci node.
3750  * Can be call externally by DR when unconfiguring a PCI I/O Board.
3751  */
3752 int
3753 schpc_remove_pci(dev_info_t *dip)
3754 {
3755 	int slot;
3756 
3757 	SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", dip);
3758 
3759 	if (schpc_p == NULL) {
3760 		/*
3761 		 * The schpc driver has not been attached yet.
3762 		 */
3763 		return (DDI_SUCCESS);
3764 	}
3765 
3766 	for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) {
3767 		if (schpc_p->schpc_slot[slot].devi == dip) {
3768 
3769 			if (schpc_p->schpc_slot[slot].slot_ops) {
3770 				if (hpc_slot_unregister(
3771 				    &schpc_p->schpc_slot[slot].slot_handle)) {
3772 					cmn_err(CE_WARN,
3773 					    "schpc_remove_pci(dip=0x%p) - "
3774 					    "unable to unregister pci slots\n",
3775 					    dip);
3776 					return (DDI_FAILURE);
3777 				} else {
3778 					hpc_free_slot_ops(
3779 					    schpc_p->schpc_slot[slot].slot_ops);
3780 
3781 					schpc_p->schpc_slot[slot].slot_ops =
3782 					    NULL;
3783 
3784 					schpc_p->schpc_slot[slot].devi = NULL;
3785 
3786 					return (DDI_SUCCESS);
3787 				}
3788 			} else {
3789 				schpc_p->schpc_slot[slot].devi = NULL;
3790 
3791 				return (DDI_SUCCESS);
3792 			}
3793 		}
3794 	}
3795 
3796 	cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) "
3797 	    "dip not found\n", dip);
3798 
3799 	return (DDI_SUCCESS);
3800 }
3801 
3802 /*
3803  * schpc_match_dip
3804  *
3805  * Used by ddi_walk_devs to find PCI Nexus nodes associated with
3806  * Hot Plug Controllers.
3807  */
3808 static int
3809 schpc_match_dip(dev_info_t *dip, void *arg)
3810 {
3811 	char		*naddr;
3812 	find_dev_t	*find_dev = (find_dev_t *)arg;
3813 
3814 	if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 &&
3815 	    ((((naddr = ddi_get_name_addr(dip)) != NULL) &&
3816 	    (strcmp(find_dev->caddr, naddr) == 0)) ||
3817 	    ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) {
3818 		/*
3819 		 * While ddi_walk_devs() holds dips when invoking this
3820 		 * callback, this dip is being saved and will be accessible
3821 		 * to the caller outside ddi_walk_devs(). Therefore it must be
3822 		 * held.
3823 		 */
3824 		ndi_hold_devi(dip);
3825 		find_dev->dip = dip;
3826 
3827 		SCHPC_DEBUG2(D_ATTACH,
3828 		    "schpc_match_dip: pci@%s FOUND dip=0x%p",
3829 		    find_dev->caddr, find_dev->dip);
3830 
3831 		return (DDI_WALK_TERMINATE);
3832 	}
3833 
3834 	ASSERT(find_dev->dip == NULL);
3835 	return (DDI_WALK_CONTINUE);
3836 }
3837 
3838 /*
3839  * schpc_buildapid
3840  *
3841  * Takes a component address and translates it into a ap_id prefix.
3842  */
3843 static void
3844 schpc_buildapid(dev_info_t *dip, int slot, char *ap_id)
3845 {
3846 	int r, pci_id_cnt, pci_id_bit;
3847 	int slots_before, found;
3848 	unsigned char *slot_names_data, *s;
3849 	int slot_names_size;
3850 	int slot_num;
3851 	unsigned int bit_mask;
3852 
3853 	slot_num = SCHPC_SLOT_NUM(slot);
3854 
3855 	if (schpc_use_legacy_apid) {
3856 		SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot);
3857 
3858 		sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3859 		    schpc_getboard(dip), slot_num);
3860 
3861 		SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3862 
3863 		return;
3864 	}
3865 
3866 	r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3867 	    "slot-names", (caddr_t)&slot_names_data,
3868 	    &slot_names_size);
3869 
3870 	if (r == DDI_PROP_SUCCESS) {
3871 
3872 		/*
3873 		 * We can try to use the slot-names property to
3874 		 * build our ap-id.
3875 		 */
3876 		bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) |
3877 		    (slot_names_data[1] << 16) | (slot_names_data[0] << 24);
3878 
3879 		pci_id_bit = 1;
3880 		pci_id_cnt = slots_before = found = 0;
3881 
3882 		SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x",
3883 		    slot, bit_mask);
3884 
3885 		/*
3886 		 * Walk the bit mask until we find the bit that corresponds
3887 		 * to our slots device number.  We count how many bits
3888 		 * we find before we find our slot's bit.
3889 		 */
3890 		while (!found && (pci_id_cnt < 32)) {
3891 
3892 			while (schpc_p->schpc_slot[slot].pci_id
3893 			    != pci_id_cnt) {
3894 
3895 				/*
3896 				 * Find the next bit set.
3897 				 */
3898 				while (!(bit_mask & pci_id_bit) &&
3899 				    (pci_id_cnt < 32)) {
3900 					pci_id_bit = pci_id_bit << 1;
3901 					pci_id_cnt++;
3902 				}
3903 
3904 				if (schpc_p->schpc_slot[slot].pci_id !=
3905 				    pci_id_cnt)
3906 					slots_before++;
3907 				else
3908 					found = 1;
3909 			}
3910 		}
3911 
3912 		if (pci_id_cnt < 32) {
3913 
3914 			/*
3915 			 * Set ptr to first string.
3916 			 */
3917 			s = slot_names_data + 4;
3918 
3919 			/*
3920 			 * Increment past all the strings for the slots
3921 			 * before ours.
3922 			 */
3923 			while (slots_before) {
3924 				while (*s != NULL)
3925 					s++;
3926 				s++;
3927 				slots_before--;
3928 			}
3929 
3930 			/*
3931 			 * We should be at our string.
3932 			 */
3933 
3934 			sprintf(ap_id, "IO%d_%s", schpc_getexpander(dip), s);
3935 
3936 			SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s",
3937 			    slot, ap_id);
3938 
3939 			kmem_free(slot_names_data, slot_names_size);
3940 			return;
3941 		}
3942 
3943 		SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found",
3944 		    slot);
3945 
3946 		kmem_free(slot_names_data, slot_names_size);
3947 	} else
3948 		SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found",
3949 		    slot);
3950 
3951 	/*
3952 	 * Build the ap-id using the legacy naming scheme.
3953 	 */
3954 	sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3955 	    schpc_getboard(dip), slot_num);
3956 
3957 	SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3958 }
3959 
3960 /*
3961  * schpc_getexpander
3962  *
3963  * Returns the Expander Number (0-17) for the dip passed in. The Expander
3964  * Number is extracted from the portid property of the pci node. Portid
3965  * consists of <Expbrd#><1110x>, where x is the schizo number.
3966  */
3967 static int
3968 schpc_getexpander(dev_info_t *dip)
3969 {
3970 	int	id;
3971 
3972 	id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1);
3973 
3974 	if (id != -1)
3975 		return (id >> 5);
3976 	else {
3977 		id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1);
3978 		return (id);
3979 	}
3980 }
3981 
3982 /*
3983  * schpc_getboard
3984  *
3985  * Returns the board number (0 or 1) for the dip passed in.
3986  */
3987 static int
3988 schpc_getboard(dev_info_t *dip)
3989 {
3990 	_NOTE(ARGUNUSED(dip))
3991 
3992 	/*
3993 	 * Hot Pluggable PCI/cPCI slots are only available on
3994 	 * Board 1 (half-bandwidth slot).
3995 	 */
3996 	return (1);
3997 }
3998 
3999 /*ARGSUSED*/
4000 static int
4001 schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot)
4002 {
4003 	gdcd_t *gdcd;
4004 	int prd_slot, status, bus;
4005 
4006 	SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4007 	    "exp=%d board=%d slot=%d", expander, board, slot);
4008 
4009 	if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t),
4010 	    KM_SLEEP)) == NULL) {
4011 		return (RSV_UNDEFINED);
4012 	}
4013 
4014 	/*
4015 	 * Get the Starcat Specific Global DCD Structure from the golden
4016 	 * IOSRAM.
4017 	 */
4018 	if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
4019 		cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
4020 		    "From IOSRAM\n");
4021 		kmem_free(gdcd, sizeof (gdcd_t));
4022 		return (RSV_UNDEFINED);
4023 	}
4024 
4025 	if (gdcd->h.dcd_magic != GDCD_MAGIC) {
4026 
4027 		cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n",
4028 		    gdcd->h.dcd_magic);
4029 
4030 		kmem_free(gdcd, sizeof (gdcd_t));
4031 		return (RSV_UNDEFINED);
4032 	}
4033 
4034 	if (gdcd->h.dcd_version != DCD_VERSION) {
4035 		cmn_err(CE_WARN, "schpc: GDCD Bad Version: "
4036 		    "GDCD Version 0x%x Expecting 0x%x\n",
4037 		    gdcd->h.dcd_version, DCD_VERSION);
4038 
4039 		kmem_free(gdcd, sizeof (gdcd_t));
4040 		return (RSV_UNDEFINED);
4041 	}
4042 
4043 	if (slot < 2)
4044 		prd_slot = 4;
4045 	else
4046 		prd_slot = 5;
4047 
4048 	bus = slot & 0x1;
4049 
4050 	status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0];
4051 
4052 	kmem_free(gdcd, sizeof (gdcd_t));
4053 
4054 	SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4055 	    "prd_slot=%d bus=%d status=%d", prd_slot, bus, status);
4056 
4057 	return (status);
4058 }
4059 
4060 #define	LEAF_SAVE_END			0xff
4061 
4062 typedef struct {
4063 	int	reg;
4064 	int	offset;
4065 	int	access_size;
4066 	int	number;
4067 } save_reg_list_t;
4068 
4069 /*
4070  * Save List Array.  Describes the leaf registers that need to
4071  * be restored after a leaf reset.
4072  *
4073  * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space
4074  * Entry 2 - Offset Start
4075  * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit
4076  * Entry 4 - # of registers to be saved starting at offset,
4077  */
4078 save_reg_list_t	save_reg_list[] = {	0, 0x110, 8, 1,
4079 					0, 0x200, 8, 2,
4080 					0, 0x1000, 8, 0x18,
4081 					0, 0x1a00, 8, 1,
4082 					0, 0x2000, 8, 1,
4083 					0, 0x2020, 8, 1,
4084 					0, 0x2040, 8, 1,
4085 					0, 0x2308, 8, 2,
4086 					0, 0x2800, 8, 1,
4087 					2, 0x04, 2, 1,		/* Command */
4088 					2, 0x0d, 1, 1,		/* Latency */
4089 					2, 0x40, 1, 1,		/* Bus # */
4090 					2, 0x41, 1, 1,		/* Sub. Bus # */
4091 					LEAF_SAVE_END, 0, 0, 0};
4092 
4093 static int
4094 schpc_save_leaf(int slot)
4095 {
4096 	int		save_entry, list_entry, reg;
4097 	caddr_t		leaf_regs;
4098 	ddi_device_acc_attr_t attr;
4099 
4100 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4101 
4102 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4103 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4104 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4105 
4106 	/*
4107 	 * Map in the 3 addresses spaces defined for XMITS.
4108 	 */
4109 	for (reg = 0; reg < 3; reg++) {
4110 		if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg,
4111 		    &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot].
4112 		    saved_handle[reg]) != DDI_SUCCESS) {
4113 			cmn_err(CE_WARN, "Mapin failed\n");
4114 			schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4115 			return (1);
4116 		}
4117 
4118 		schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs;
4119 	}
4120 
4121 
4122 	/*
4123 	 * Determine how many entries are in the list so we can
4124 	 * allocate the save space.
4125 	 */
4126 	list_entry = 0;
4127 	save_entry = 0;
4128 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4129 		save_entry += save_reg_list[list_entry].number;
4130 		list_entry++;
4131 	}
4132 
4133 	schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t));
4134 
4135 	if (schpc_p->schpc_slot[slot].saved_size == 0)
4136 		return (0);
4137 
4138 	schpc_p->schpc_slot[slot].saved_regs =
4139 	    (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size,
4140 	    KM_SLEEP);
4141 
4142 	/*
4143 	 * Walk through the register list and save contents.
4144 	 */
4145 	list_entry = 0;
4146 	save_entry = 0;
4147 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4148 		schpc_save_entry(slot, list_entry, save_entry);
4149 		save_entry += save_reg_list[list_entry].number;
4150 		list_entry ++;
4151 	}
4152 
4153 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4154 
4155 	return (0);
4156 }
4157 
4158 static void
4159 schpc_restore_leaf(int slot)
4160 {
4161 	int	save_entry, list_entry, reg;
4162 
4163 	if (schpc_p->schpc_slot[slot].saved_regs == NULL)
4164 		return;
4165 
4166 	/*
4167 	 * Walk through the register list and restore contents.
4168 	 */
4169 	list_entry = 0;
4170 	save_entry = 0;
4171 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4172 
4173 		schpc_restore_entry(slot, list_entry, save_entry);
4174 
4175 		save_entry += save_reg_list[list_entry].number;
4176 		list_entry ++;
4177 	}
4178 
4179 	/*
4180 	 * Free the mapped in registers.
4181 	 */
4182 	for (reg = 0; reg < 3; reg++) {
4183 		if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) {
4184 
4185 			ddi_regs_map_free(
4186 			    &schpc_p->schpc_slot[slot].saved_handle[reg]);
4187 
4188 			schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4189 		}
4190 	}
4191 
4192 	kmem_free(schpc_p->schpc_slot[slot].saved_regs,
4193 	    schpc_p->schpc_slot[slot].saved_size);
4194 
4195 	schpc_p->schpc_slot[slot].saved_size = 0;
4196 	schpc_p->schpc_slot[slot].saved_regs = NULL;
4197 
4198 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot);
4199 }
4200 
4201 static void
4202 schpc_save_entry(int slot, int list_entry, int save_entry)
4203 {
4204 	int reg, reads = 0;
4205 
4206 	reg = save_reg_list[list_entry].reg;
4207 
4208 	while (reads < save_reg_list[list_entry].number) {
4209 		switch (save_reg_list[list_entry].access_size) {
4210 		case 8:
4211 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4212 			    ddi_get64(
4213 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4214 			    (uint64_t *)(schpc_p->schpc_slot[slot].
4215 			    saved_regs_va[reg]
4216 			    + save_reg_list[list_entry].offset +
4217 			    (reads * sizeof (uint64_t))));
4218 #ifdef DEBUG
4219 			if (schpc_dump_save_regs)
4220 				cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg,
4221 				    save_reg_list[list_entry].offset +
4222 				    (reads * sizeof (uint64_t)),
4223 				    schpc_p->schpc_slot[slot].
4224 				    saved_regs[save_entry]);
4225 #endif
4226 
4227 			break;
4228 		case 4:
4229 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4230 			    ddi_get32(
4231 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4232 			    (uint32_t *)(schpc_p->schpc_slot[slot].
4233 			    saved_regs_va[reg]
4234 			    + save_reg_list[list_entry].offset +
4235 			    (reads * sizeof (uint32_t))));
4236 
4237 #ifdef DEBUG
4238 			if (schpc_dump_save_regs)
4239 				cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg,
4240 				    save_reg_list[list_entry].offset +
4241 				    (reads * sizeof (uint32_t)),
4242 				    schpc_p->schpc_slot[slot].
4243 				    saved_regs[save_entry]);
4244 #endif
4245 
4246 			break;
4247 		case 2:
4248 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4249 			    ddi_get16(
4250 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4251 			    (uint16_t *)(schpc_p->schpc_slot[slot].
4252 			    saved_regs_va[reg]
4253 			    + save_reg_list[list_entry].offset +
4254 			    (reads * sizeof (uint16_t))));
4255 
4256 #ifdef DEBUG
4257 			if (schpc_dump_save_regs)
4258 				cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg,
4259 				    save_reg_list[list_entry].offset +
4260 				    (reads * sizeof (uint16_t)),
4261 				    schpc_p->schpc_slot[slot].
4262 				    saved_regs[save_entry]);
4263 #endif
4264 
4265 			break;
4266 		case 1:
4267 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4268 			    ddi_get8(
4269 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4270 			    (uint8_t *)(schpc_p->schpc_slot[slot].
4271 			    saved_regs_va[reg]
4272 			    + save_reg_list[list_entry].offset +
4273 			    (reads * sizeof (uint8_t))));
4274 
4275 #ifdef DEBUG
4276 			if (schpc_dump_save_regs)
4277 				cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg,
4278 				    save_reg_list[list_entry].offset +
4279 				    (reads * sizeof (uint8_t)),
4280 				    schpc_p->schpc_slot[slot].
4281 				    saved_regs[save_entry]);
4282 #endif
4283 
4284 			break;
4285 		default:
4286 			cmn_err(CE_WARN,
4287 			    "schpc: Illegal List Entry\n");
4288 		}
4289 		reads++;
4290 		save_entry++;
4291 	}
4292 }
4293 
4294 static void
4295 schpc_restore_entry(int slot, int list_entry, int save_entry)
4296 {
4297 	int reg, writes = 0;
4298 
4299 	reg = save_reg_list[list_entry].reg;
4300 
4301 	while (writes < save_reg_list[list_entry].number) {
4302 		switch (save_reg_list[list_entry].access_size) {
4303 		case 8:
4304 #ifdef DEBUG
4305 			if (schpc_dump_save_regs)
4306 				cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg,
4307 				    save_reg_list[list_entry].offset +
4308 				    (writes * sizeof (uint64_t)),
4309 				    schpc_p->schpc_slot[slot].
4310 				    saved_regs[save_entry]);
4311 #endif
4312 
4313 			ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg],
4314 			    (uint64_t *)(schpc_p->schpc_slot[slot].
4315 			    saved_regs_va[reg]
4316 			    + save_reg_list[list_entry].offset +
4317 			    (writes * sizeof (uint64_t))),
4318 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4319 
4320 			break;
4321 		case 4:
4322 #ifdef DEBUG
4323 			if (schpc_dump_save_regs)
4324 				cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg,
4325 				    save_reg_list[list_entry].offset +
4326 				    (writes * sizeof (uint32_t)),
4327 				    schpc_p->schpc_slot[slot].
4328 				    saved_regs[save_entry]);
4329 #endif
4330 
4331 			ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg],
4332 			    (uint32_t *)(schpc_p->schpc_slot[slot].
4333 			    saved_regs_va[reg]
4334 			    + save_reg_list[list_entry].offset +
4335 			    (writes * sizeof (uint32_t))),
4336 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4337 
4338 			break;
4339 		case 2:
4340 #ifdef DEBUG
4341 			if (schpc_dump_save_regs)
4342 				cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg,
4343 				    save_reg_list[list_entry].offset +
4344 				    (writes * sizeof (uint16_t)),
4345 				    schpc_p->schpc_slot[slot].
4346 				    saved_regs[save_entry]);
4347 #endif
4348 
4349 			ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg],
4350 			    (uint16_t *)(schpc_p->schpc_slot[slot].
4351 			    saved_regs_va[reg]
4352 			    + save_reg_list[list_entry].offset +
4353 			    (writes * sizeof (uint16_t))),
4354 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4355 
4356 			break;
4357 		case 1:
4358 #ifdef DEBUG
4359 			if (schpc_dump_save_regs)
4360 				cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg,
4361 				    save_reg_list[list_entry].offset +
4362 				    (writes * sizeof (uint8_t)),
4363 				    schpc_p->schpc_slot[slot].
4364 				    saved_regs[save_entry]);
4365 #endif
4366 
4367 			ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg],
4368 			    (uint8_t *)(schpc_p->schpc_slot[slot].
4369 			    saved_regs_va[reg]
4370 			    + save_reg_list[list_entry].offset +
4371 			    (writes * sizeof (uint8_t))),
4372 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4373 
4374 			break;
4375 		default:
4376 			cmn_err(CE_WARN,
4377 			    "schpc: Illegal List Entry\n");
4378 		}
4379 		writes++;
4380 		save_entry++;
4381 	}
4382 }
4383 
4384 /*
4385  * Returns TRUE if a leaf reset is required to change frequencies/mode.
4386  */
4387 static int
4388 schpc_is_leaf_reset_required(int slot)
4389 {
4390 	char *name;
4391 	int32_t mod_rev;
4392 
4393 	/*
4394 	 * Only XMITS 3.0 and greater connected slots will require a
4395 	 * reset to switch frequency and/or mode.
4396 	 */
4397 	name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4398 
4399 	if (strcmp(name, "pci108e,8002") == 0) {
4400 		mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4401 		    schpc_p->schpc_slot[slot].devi,
4402 		    DDI_PROP_DONTPASS, "module-revision#", 0);
4403 
4404 		SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4405 
4406 		/*
4407 		 * Check for XMITS 3.0 or greater.
4408 		 */
4409 		if (mod_rev >= XMITS_30) {
4410 
4411 			/*
4412 			 * The leaf attached to C5V0 (slot 1) should
4413 			 * not be reset.
4414 			 */
4415 			if ((slot & 3) == 1) {
4416 
4417 				SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4418 				    "Not Required - C5V0", slot);
4419 
4420 				return (0);
4421 			}
4422 
4423 			SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4424 			    "Required", slot);
4425 
4426 			return (1);
4427 		}
4428 	}
4429 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot);
4430 
4431 	return (0);
4432 }
4433 
4434 /*
4435  * Returns TRUE if the bus can change frequencies.
4436  */
4437 static int
4438 schpc_is_freq_switchable(int slot)
4439 {
4440 	char *name;
4441 	int32_t mod_rev;
4442 
4443 	name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4444 
4445 	if (strcmp(name, "pci108e,8002") == 0) {
4446 		mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4447 		    schpc_p->schpc_slot[slot].devi,
4448 		    DDI_PROP_DONTPASS, "module-revision#", 0);
4449 
4450 		SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4451 
4452 		/*
4453 		 * We will only report back that XMITS 2.0 (mod_rev = 2)
4454 		 * or greater will have the ability to switch frequencies.
4455 		 */
4456 		if (mod_rev >= XMITS_20) {
4457 			SCHPC_DEBUG1(D_FREQCHG, "Slot %d - "
4458 			    "Frequency is switchable", slot);
4459 			return (1);
4460 		}
4461 	}
4462 
4463 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot);
4464 	return (0);
4465 }
4466 
4467 /*
4468  * schpc_slot_freq
4469  *
4470  * Convert the slot frequency setting to integer value.
4471  */
4472 static int
4473 schpc_slot_freq(pci_getslot_t *getslotp)
4474 {
4475 	switch (getslotp->slot_freq_setting) {
4476 	case PCIMSG_FREQ_33MHZ:
4477 		return (SCHPC_33MHZ);
4478 	case PCIMSG_FREQ_66MHZ:
4479 		return (SCHPC_66MHZ);
4480 	case PCIMSG_FREQ_90MHZ:
4481 		return (SCHPC_90MHZ);
4482 	case PCIMSG_FREQ_133MHZ:
4483 		return (SCHPC_133MHZ);
4484 	default:
4485 		return (0);
4486 	}
4487 }
4488 
4489 /*
4490  * schpc_find_dip
4491  *
4492  * Used by ddi_walk_devs to find the dip which belongs
4493  * to a certain slot.
4494  *
4495  * When this function returns, the dip is held.  It is the
4496  * responsibility of the caller to release the dip.
4497  */
4498 static int
4499 schpc_find_dip(dev_info_t *dip, void *arg)
4500 {
4501 	find_dev_t	*find_dev = (find_dev_t *)arg;
4502 	char		*pathname = find_dev->caddr;
4503 
4504 	(void) ddi_pathname(dip, pathname);
4505 	if (strcmp(find_dev->cname, pathname) == 0) {
4506 		ndi_hold_devi(dip);
4507 		find_dev->dip = dip;
4508 		return (DDI_WALK_TERMINATE);
4509 	}
4510 	return (DDI_WALK_CONTINUE);
4511 }
4512