xref: /titanic_50/usr/src/uts/sun4u/starcat/io/schpc.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
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 2009 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 	    (void *)ops_arg, (void *)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 				    (void *)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)", (void *)ops_arg,
973 	    slot_hdl);
974 
975 	mutex_enter(&schpc_p->schpc_mutex);
976 
977 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
978 
979 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
980 		SCHPC_DEBUG0(D_IOC_CONNECT,
981 		    "schpc_disconnect - HPC Not Inited");
982 		mutex_exit(&schpc_p->schpc_mutex);
983 		return (HPC_ERR_FAILED);
984 	}
985 
986 	/*
987 	 * Check to see if we are already disconnected.
988 	 */
989 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) {
990 		mutex_exit(&schpc_p->schpc_mutex);
991 		return (0);
992 	}
993 
994 	/*
995 	 * Block if another thread is executing a HPC command.
996 	 */
997 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
998 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
999 	}
1000 
1001 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1002 
1003 	mutex_exit(&schpc_p->schpc_mutex);
1004 
1005 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1006 	board = schpc_p->schpc_slot[slot].board; /* get board */
1007 
1008 	/*
1009 	 * If a leaf reset is going to be asserted due to a mode/freq.
1010 	 * change, then the leaf registers of the XMITS bridge will need
1011 	 * to be saved off prior to the connect.
1012 	 */
1013 	if (schpc_is_leaf_reset_required(slot)) {
1014 		if (schpc_save_leaf(slot) != 0) {
1015 
1016 			cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
1017 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
1018 			    expander, board, slot & 3,
1019 			    schpc_p->schpc_slot[slot].ap_id);
1020 
1021 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1022 
1023 			goto failed;
1024 		}
1025 	}
1026 
1027 	/*
1028 	 * Initialize Set Slot Command.
1029 	 */
1030 	schpc_init_setslot_message(&setslot);
1031 
1032 	setslot.slot_power_off = PCIMSG_ON;	   /* Turn Power Off */
1033 
1034 	setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */
1035 
1036 	setslot.slot_disable_ENUM = PCIMSG_ON;	   /* Mask the ENUM# signal */
1037 	setslot.slot_disable_HEALTHY = PCIMSG_ON;  /* Mask the HEALTHY# sig */
1038 
1039 	rval = schpc_setslotstatus(expander, board, slot, &setslot);
1040 
1041 	SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
1042 	    "setslotstatus returned 0x%x", rval);
1043 
1044 	if (rval != 0) {
1045 		/*
1046 		 * System Controller/Mailbox failure.
1047 		 */
1048 		cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
1049 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
1050 		    "Communicate with System Controller", expander, board,
1051 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
1052 
1053 		schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1054 
1055 		goto failed;
1056 	}
1057 
1058 	SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
1059 	    "slot_replystatus returned 0x%x", setslot.slot_replystatus);
1060 
1061 	if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
1062 
1063 		/*
1064 		 * The Request was successfully completed.
1065 		 */
1066 		schpc_p->schpc_slot[slot].state &=
1067 		    ~SCHPC_SLOTSTATE_CONNECTED;
1068 
1069 		schpc_setslotled(expander, board, slot,
1070 		    (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF));
1071 
1072 		SCHPC_DEBUG0(D_IOC_CONNECT,
1073 		    "schpc_disconnect() - setslotstatus succeeded");
1074 
1075 		mutex_enter(&schpc_p->schpc_mutex);
1076 		schpc_p->schpc_slot[slot].state &=
1077 		    ~SCHPC_SLOTSTATE_EXECUTING;
1078 		cv_signal(&schpc_p->schpc_cv);
1079 		mutex_exit(&schpc_p->schpc_mutex);
1080 
1081 		return (0);
1082 	}
1083 	/*
1084 	 * System Controller/Mailbox failure.
1085 	 */
1086 	cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
1087 	    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
1088 	    "failed disconnection request", expander, board,
1089 	    SCHPC_SLOT_NUM(slot),
1090 	    schpc_p->schpc_slot[slot].ap_id);
1091 
1092 	schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1093 
1094 failed:
1095 	schpc_restore_leaf(slot);
1096 	mutex_enter(&schpc_p->schpc_mutex);
1097 	schpc_p->schpc_slot[slot].state &=
1098 	    ~SCHPC_SLOTSTATE_EXECUTING;
1099 	cv_signal(&schpc_p->schpc_cv);
1100 	mutex_exit(&schpc_p->schpc_mutex);
1101 
1102 	return (HPC_ERR_FAILED);
1103 }
1104 
1105 /*
1106  * schpc_cpci_control
1107  *
1108  * Called by Hot Plug Services to perform a attachment point specific
1109  * on a Hot Pluggable Compact PCI Slot.
1110  */
1111 /*ARGSUSED*/
1112 static int
1113 schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
1114     caddr_t arg)
1115 {
1116 	int		rval;
1117 	int		expander, board, slot;
1118 	pci_setslot_t	setslot;
1119 	pci_getslot_t   slotstatus;
1120 	hpc_led_info_t	*hpc_led_info;
1121 
1122 	SCHPC_DEBUG3(D_IOC_CONTROL,
1123 	    "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)",
1124 	    (void *)ops_arg, (void *)slot_hdl, request);
1125 
1126 	mutex_enter(&schpc_p->schpc_mutex);
1127 
1128 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
1129 
1130 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
1131 		SCHPC_DEBUG0(D_IOC_CONNECT,
1132 		    "schpc_disconnect - HPC Not Inited");
1133 		mutex_exit(&schpc_p->schpc_mutex);
1134 		return (HPC_ERR_FAILED);
1135 	}
1136 
1137 	/*
1138 	 * Block if another thread is executing a HPC command.
1139 	 */
1140 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
1141 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
1142 	}
1143 
1144 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1145 
1146 	mutex_exit(&schpc_p->schpc_mutex);
1147 
1148 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1149 	board = schpc_p->schpc_slot[slot].board; /* get board */
1150 
1151 	/*
1152 	 * Initialize Set Slot Command.
1153 	 */
1154 	schpc_init_setslot_message(&setslot);
1155 
1156 	/*
1157 	 * Initialize LED to last know state.
1158 	 */
1159 	switch (schpc_p->schpc_slot[slot].led.led_power) {
1160 	case LED_ON:
1161 		setslot.slot_led_power = PCIMSG_LED_ON;
1162 		break;
1163 	case LED_OFF:
1164 		setslot.slot_led_power = PCIMSG_LED_OFF;
1165 		break;
1166 	case LED_FLASH:
1167 		setslot.slot_led_power = PCIMSG_LED_FLASH;
1168 		break;
1169 	}
1170 
1171 	switch (schpc_p->schpc_slot[slot].led.led_service) {
1172 	case LED_ON:
1173 		setslot.slot_led_service = PCIMSG_LED_ON;
1174 		break;
1175 	case LED_OFF:
1176 		setslot.slot_led_service = PCIMSG_LED_OFF;
1177 		break;
1178 	case LED_FLASH:
1179 		setslot.slot_led_service = PCIMSG_LED_FLASH;
1180 		break;
1181 	}
1182 
1183 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
1184 	case LED_ON:
1185 		setslot.slot_led_fault = PCIMSG_LED_ON;
1186 		break;
1187 	case LED_OFF:
1188 		setslot.slot_led_fault = PCIMSG_LED_OFF;
1189 		break;
1190 	case LED_FLASH:
1191 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
1192 		break;
1193 	}
1194 
1195 	switch (request) {
1196 
1197 	case HPC_CTRL_GET_LED_STATE:
1198 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1199 		    "HPC_CTRL_GET_LED_STATE");
1200 		hpc_led_info = (hpc_led_info_t *)arg;
1201 
1202 		switch (hpc_led_info->led) {
1203 		case HPC_FAULT_LED:
1204 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1205 			case LED_OFF:
1206 				hpc_led_info->state = HPC_LED_OFF;
1207 				break;
1208 			case LED_ON:
1209 				hpc_led_info->state = HPC_LED_ON;
1210 				break;
1211 			case LED_FLASH:
1212 				hpc_led_info->state = HPC_LED_BLINK;
1213 				break;
1214 			}
1215 			break;
1216 
1217 		case HPC_POWER_LED:
1218 			switch (schpc_p->schpc_slot[slot].led.led_power) {
1219 			case LED_OFF:
1220 				hpc_led_info->state = HPC_LED_OFF;
1221 				break;
1222 			case LED_ON:
1223 				hpc_led_info->state = HPC_LED_ON;
1224 				break;
1225 			case LED_FLASH:
1226 				hpc_led_info->state = HPC_LED_BLINK;
1227 				break;
1228 			}
1229 			break;
1230 		case HPC_ATTN_LED:
1231 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1232 			case LED_OFF:
1233 				hpc_led_info->state = HPC_LED_OFF;
1234 				break;
1235 			case LED_ON:
1236 				hpc_led_info->state = HPC_LED_OFF;
1237 				break;
1238 			case LED_FLASH:
1239 				hpc_led_info->state = HPC_LED_ON;
1240 				break;
1241 			}
1242 			break;
1243 		case HPC_ACTIVE_LED:
1244 			switch (schpc_p->schpc_slot[slot].led.led_service) {
1245 			case LED_OFF:
1246 				hpc_led_info->state = HPC_LED_OFF;
1247 				break;
1248 			case LED_ON:
1249 				hpc_led_info->state = HPC_LED_ON;
1250 				break;
1251 			case LED_FLASH:
1252 				hpc_led_info->state = HPC_LED_BLINK;
1253 				break;
1254 			}
1255 			break;
1256 		default:
1257 			SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1258 			    "Invalid LED %x", hpc_led_info->led);
1259 
1260 			mutex_enter(&schpc_p->schpc_mutex);
1261 			schpc_p->schpc_slot[slot].state &=
1262 			    ~SCHPC_SLOTSTATE_EXECUTING;
1263 			cv_signal(&schpc_p->schpc_cv);
1264 			mutex_exit(&schpc_p->schpc_mutex);
1265 
1266 			return (HPC_ERR_FAILED);
1267 		}
1268 
1269 		mutex_enter(&schpc_p->schpc_mutex);
1270 		schpc_p->schpc_slot[slot].state &=
1271 		    ~SCHPC_SLOTSTATE_EXECUTING;
1272 		cv_signal(&schpc_p->schpc_cv);
1273 		mutex_exit(&schpc_p->schpc_mutex);
1274 
1275 		return (0);
1276 
1277 	case HPC_CTRL_SET_LED_STATE:
1278 		hpc_led_info = (hpc_led_info_t *)arg;
1279 
1280 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1281 		    "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1282 		    (void *)hpc_led_info);
1283 
1284 		switch (hpc_led_info->led) {
1285 		case HPC_FAULT_LED:
1286 			switch (hpc_led_info->state) {
1287 			case HPC_LED_OFF:
1288 				schpc_p->schpc_slot[slot].led.led_fault =
1289 				    LED_OFF;
1290 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1291 				break;
1292 			case HPC_LED_ON:
1293 				schpc_p->schpc_slot[slot].led.led_fault =
1294 				    LED_ON;
1295 				setslot.slot_led_fault = PCIMSG_LED_ON;
1296 				break;
1297 			case HPC_LED_BLINK:
1298 				schpc_p->schpc_slot[slot].led.led_fault =
1299 				    LED_FLASH;
1300 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1301 				break;
1302 			}
1303 			break;
1304 		case HPC_POWER_LED:
1305 			switch (hpc_led_info->state) {
1306 			case HPC_LED_OFF:
1307 				schpc_p->schpc_slot[slot].led.led_power =
1308 				    LED_OFF;
1309 				setslot.slot_led_power = PCIMSG_LED_OFF;
1310 				break;
1311 			case HPC_LED_ON:
1312 				schpc_p->schpc_slot[slot].led.led_power =
1313 				    LED_ON;
1314 				setslot.slot_led_power = PCIMSG_LED_ON;
1315 				break;
1316 			case HPC_LED_BLINK:
1317 				schpc_p->schpc_slot[slot].led.led_power =
1318 				    LED_FLASH;
1319 				setslot.slot_led_power = PCIMSG_LED_FLASH;
1320 				break;
1321 			}
1322 			break;
1323 		case HPC_ATTN_LED:
1324 			switch (hpc_led_info->state) {
1325 			case HPC_LED_OFF:
1326 				schpc_p->schpc_slot[slot].led.led_fault =
1327 				    LED_OFF;
1328 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1329 				break;
1330 			case HPC_LED_ON:
1331 				schpc_p->schpc_slot[slot].led.led_fault =
1332 				    LED_FLASH;
1333 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1334 				break;
1335 			case HPC_LED_BLINK:
1336 				schpc_p->schpc_slot[slot].led.led_fault =
1337 				    LED_FLASH;
1338 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1339 				break;
1340 			}
1341 			break;
1342 		case HPC_ACTIVE_LED:
1343 			switch (hpc_led_info->state) {
1344 			case HPC_LED_OFF:
1345 				schpc_p->schpc_slot[slot].led.led_service =
1346 				    LED_OFF;
1347 				setslot.slot_led_service = PCIMSG_LED_OFF;
1348 				break;
1349 			case HPC_LED_ON:
1350 				schpc_p->schpc_slot[slot].led.led_service =
1351 				    LED_ON;
1352 				setslot.slot_led_service = PCIMSG_LED_ON;
1353 				break;
1354 			case HPC_LED_BLINK:
1355 				schpc_p->schpc_slot[slot].led.led_service =
1356 				    LED_FLASH;
1357 				setslot.slot_led_service = PCIMSG_LED_FLASH;
1358 				break;
1359 			}
1360 			break;
1361 		default:
1362 			mutex_enter(&schpc_p->schpc_mutex);
1363 			schpc_p->schpc_slot[slot].state &=
1364 			    ~SCHPC_SLOTSTATE_EXECUTING;
1365 			cv_signal(&schpc_p->schpc_cv);
1366 			mutex_exit(&schpc_p->schpc_mutex);
1367 
1368 			return (0);
1369 		}
1370 
1371 		(void) schpc_setslotstatus(expander, board, slot, &setslot);
1372 
1373 		mutex_enter(&schpc_p->schpc_mutex);
1374 		schpc_p->schpc_slot[slot].state &=
1375 		    ~SCHPC_SLOTSTATE_EXECUTING;
1376 		cv_signal(&schpc_p->schpc_cv);
1377 		mutex_exit(&schpc_p->schpc_mutex);
1378 
1379 		return (0);
1380 
1381 	case HPC_CTRL_GET_SLOT_STATE: {
1382 		hpc_slot_state_t	*hpc_slot_state;
1383 
1384 		hpc_slot_state = (hpc_slot_state_t *)arg;
1385 
1386 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1387 		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1388 		    (void *)hpc_slot_state);
1389 
1390 		rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
1391 
1392 		if (!rval) {
1393 
1394 			if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
1395 				return (HPC_ERR_FAILED);
1396 			}
1397 
1398 			if (slotstatus.slot_empty == PCIMSG_ON) {
1399 				*hpc_slot_state = HPC_SLOT_EMPTY;
1400 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
1401 			} else if (slotstatus.slot_power_on == PCIMSG_ON) {
1402 				*hpc_slot_state = HPC_SLOT_CONNECTED;
1403 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
1404 				schpc_p->schpc_slot[slot].state |=
1405 				    SCHPC_SLOTSTATE_CONNECTED;
1406 			} else {
1407 				*hpc_slot_state = HPC_SLOT_DISCONNECTED;
1408 				SCHPC_DEBUG0(D_IOC_CONTROL,
1409 				    "Slot Disconnected");
1410 				schpc_p->schpc_slot[slot].state &=
1411 				    ~SCHPC_SLOTSTATE_CONNECTED;
1412 			}
1413 		} else {
1414 			SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
1415 
1416 			mutex_enter(&schpc_p->schpc_mutex);
1417 			schpc_p->schpc_slot[slot].state &=
1418 			    ~SCHPC_SLOTSTATE_EXECUTING;
1419 			cv_signal(&schpc_p->schpc_cv);
1420 			mutex_exit(&schpc_p->schpc_mutex);
1421 
1422 			return (HPC_ERR_FAILED);
1423 		}
1424 
1425 		mutex_enter(&schpc_p->schpc_mutex);
1426 		schpc_p->schpc_slot[slot].state &=
1427 		    ~SCHPC_SLOTSTATE_EXECUTING;
1428 		cv_signal(&schpc_p->schpc_cv);
1429 		mutex_exit(&schpc_p->schpc_mutex);
1430 
1431 		return (0);
1432 	}
1433 	case HPC_CTRL_GET_BOARD_TYPE: {
1434 		hpc_board_type_t	*hpc_board_type;
1435 
1436 		hpc_board_type = (hpc_board_type_t *)arg;
1437 
1438 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1439 		    "HPC_CTRL_GET_BOARD_TYPE");
1440 
1441 		/*
1442 		 * The HPC driver does not know what board type
1443 		 * is plugged in.
1444 		 */
1445 		*hpc_board_type = HPC_BOARD_CPCI_HS;
1446 
1447 		mutex_enter(&schpc_p->schpc_mutex);
1448 		schpc_p->schpc_slot[slot].state &=
1449 		    ~SCHPC_SLOTSTATE_EXECUTING;
1450 		cv_signal(&schpc_p->schpc_cv);
1451 		mutex_exit(&schpc_p->schpc_mutex);
1452 
1453 		return (0);
1454 
1455 	}
1456 	case HPC_CTRL_DEV_CONFIGURED:
1457 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1458 		    "HPC_CTRL_DEV_CONFIGURED");
1459 
1460 		mutex_enter(&schpc_p->schpc_mutex);
1461 		schpc_p->schpc_slot[slot].state &=
1462 		    ~SCHPC_SLOTSTATE_EXECUTING;
1463 		cv_signal(&schpc_p->schpc_cv);
1464 		mutex_exit(&schpc_p->schpc_mutex);
1465 
1466 		return (0);
1467 
1468 	case HPC_CTRL_DEV_UNCONFIGURED:
1469 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1470 		    "HPC_CTRL_DEV_UNCONFIGURED");
1471 
1472 		if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) {
1473 			/*
1474 			 * When the occupant is unconfigured, power
1475 			 * down the slot.
1476 			 */
1477 			rval = schpc_disconnect((caddr_t)schpc_p,
1478 			    schpc_p->schpc_slot[slot].slot_handle,
1479 			    0, 0);
1480 
1481 			schpc_p->schpc_slot[slot].state &=
1482 			    ~SCHPC_SLOTSTATE_ENUM;
1483 		}
1484 
1485 		mutex_enter(&schpc_p->schpc_mutex);
1486 		schpc_p->schpc_slot[slot].state &=
1487 		    ~SCHPC_SLOTSTATE_EXECUTING;
1488 		cv_signal(&schpc_p->schpc_cv);
1489 		mutex_exit(&schpc_p->schpc_mutex);
1490 
1491 		return (0);
1492 
1493 	case HPC_CTRL_ENABLE_AUTOCFG:
1494 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1495 		    "HPC_CTRL_ENABLE_AUTOCFG");
1496 
1497 		schpc_p->schpc_slot[slot].state |=
1498 		    SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1499 
1500 		mutex_enter(&schpc_p->schpc_mutex);
1501 		schpc_p->schpc_slot[slot].state &=
1502 		    ~SCHPC_SLOTSTATE_EXECUTING;
1503 		cv_signal(&schpc_p->schpc_cv);
1504 		mutex_exit(&schpc_p->schpc_mutex);
1505 
1506 		return (0);
1507 
1508 	case HPC_CTRL_DISABLE_AUTOCFG:
1509 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1510 		    "HPC_CTRL_DISABLE_AUTOCFG");
1511 		schpc_p->schpc_slot[slot].state &=
1512 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1513 
1514 		mutex_enter(&schpc_p->schpc_mutex);
1515 		schpc_p->schpc_slot[slot].state &=
1516 		    ~SCHPC_SLOTSTATE_EXECUTING;
1517 		cv_signal(&schpc_p->schpc_cv);
1518 		mutex_exit(&schpc_p->schpc_mutex);
1519 
1520 		return (0);
1521 
1522 	case HPC_CTRL_DISABLE_ENUM:
1523 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1524 		    "HPC_CTRL_DISABLE_ENUM");
1525 
1526 		setslot.slot_disable_ENUM = PCIMSG_ON;
1527 
1528 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
1529 
1530 		if (rval)
1531 			rval = HPC_ERR_FAILED;
1532 
1533 		mutex_enter(&schpc_p->schpc_mutex);
1534 		schpc_p->schpc_slot[slot].state &=
1535 		    ~SCHPC_SLOTSTATE_EXECUTING;
1536 		cv_signal(&schpc_p->schpc_cv);
1537 		mutex_exit(&schpc_p->schpc_mutex);
1538 
1539 		return (rval);
1540 
1541 	case HPC_CTRL_ENABLE_ENUM:
1542 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1543 		    "HPC_CTRL_ENABLE_ENUM");
1544 
1545 		setslot.slot_enable_ENUM = PCIMSG_ON;
1546 
1547 		rval = schpc_setslotstatus(expander, board, slot, &setslot);
1548 
1549 		if (rval)
1550 			rval = HPC_ERR_FAILED;
1551 
1552 		mutex_enter(&schpc_p->schpc_mutex);
1553 		schpc_p->schpc_slot[slot].state &=
1554 		    ~SCHPC_SLOTSTATE_EXECUTING;
1555 		cv_signal(&schpc_p->schpc_cv);
1556 		mutex_exit(&schpc_p->schpc_mutex);
1557 
1558 		return (rval);
1559 
1560 	default:
1561 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1562 		    "****NOT SUPPORTED CONTROL CMD");
1563 
1564 		mutex_enter(&schpc_p->schpc_mutex);
1565 		schpc_p->schpc_slot[slot].state &=
1566 		    ~SCHPC_SLOTSTATE_EXECUTING;
1567 		cv_signal(&schpc_p->schpc_cv);
1568 		mutex_exit(&schpc_p->schpc_mutex);
1569 
1570 		return (HPC_ERR_NOTSUPPORTED);
1571 	}
1572 }
1573 
1574 /*
1575  * schpc_pci_control
1576  *
1577  * Called by Hot Plug Services to perform a attachment point specific
1578  * on a Hot Pluggable Standard PCI Slot.
1579  */
1580 /*ARGSUSED*/
1581 static int
1582 schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
1583     caddr_t arg)
1584 {
1585 	int		rval;
1586 	int		expander, board, slot;
1587 	pci_setslot_t	setslot;
1588 	pci_getslot_t   slotstatus;
1589 	hpc_led_info_t	*hpc_led_info;
1590 
1591 	SCHPC_DEBUG3(D_IOC_CONTROL,
1592 	    "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)",
1593 	    (void *)ops_arg, (void *)slot_hdl, request);
1594 
1595 	mutex_enter(&schpc_p->schpc_mutex);
1596 
1597 	slot = schpc_slot_get_index(schpc_p, slot_hdl);
1598 
1599 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
1600 		SCHPC_DEBUG0(D_IOC_CONNECT,
1601 		    "schpc_disconnect - HPC Not Inited");
1602 		mutex_exit(&schpc_p->schpc_mutex);
1603 		return (HPC_ERR_FAILED);
1604 	}
1605 
1606 	/*
1607 	 * Block if another thread is executing a HPC command.
1608 	 */
1609 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
1610 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
1611 	}
1612 
1613 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1614 
1615 	mutex_exit(&schpc_p->schpc_mutex);
1616 
1617 	expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1618 	board = schpc_p->schpc_slot[slot].board; /* get board */
1619 
1620 	/*
1621 	 * Initialize Set Slot Command.
1622 	 */
1623 	schpc_init_setslot_message(&setslot);
1624 
1625 	/*
1626 	 * Initialize LED to last know state.
1627 	 */
1628 	switch (schpc_p->schpc_slot[slot].led.led_power) {
1629 	case LED_ON:
1630 		setslot.slot_led_power = PCIMSG_LED_ON;
1631 		break;
1632 	case LED_OFF:
1633 		setslot.slot_led_power = PCIMSG_LED_OFF;
1634 		break;
1635 	case LED_FLASH:
1636 		setslot.slot_led_power = PCIMSG_LED_FLASH;
1637 		break;
1638 	}
1639 
1640 	switch (schpc_p->schpc_slot[slot].led.led_service) {
1641 	case LED_ON:
1642 		setslot.slot_led_service = PCIMSG_LED_ON;
1643 		break;
1644 	case LED_OFF:
1645 		setslot.slot_led_service = PCIMSG_LED_OFF;
1646 		break;
1647 	case LED_FLASH:
1648 		setslot.slot_led_service = PCIMSG_LED_FLASH;
1649 		break;
1650 	}
1651 
1652 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
1653 	case LED_ON:
1654 		setslot.slot_led_fault = PCIMSG_LED_ON;
1655 		break;
1656 	case LED_OFF:
1657 		setslot.slot_led_fault = PCIMSG_LED_OFF;
1658 		break;
1659 	case LED_FLASH:
1660 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
1661 		break;
1662 	}
1663 
1664 	switch (request) {
1665 
1666 
1667 	case HPC_CTRL_GET_SLOT_STATE: {
1668 		hpc_slot_state_t	*hpc_slot_state;
1669 
1670 		hpc_slot_state = (hpc_slot_state_t *)arg;
1671 
1672 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1673 		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1674 		    (void *)hpc_slot_state);
1675 
1676 		rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
1677 
1678 		if (!rval) {
1679 
1680 			if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
1681 
1682 				mutex_enter(&schpc_p->schpc_mutex);
1683 				schpc_p->schpc_slot[slot].state &=
1684 				    ~SCHPC_SLOTSTATE_EXECUTING;
1685 				cv_signal(&schpc_p->schpc_cv);
1686 				mutex_exit(&schpc_p->schpc_mutex);
1687 
1688 				return (HPC_ERR_FAILED);
1689 			}
1690 
1691 			if (slotstatus.slot_empty == PCIMSG_ON) {
1692 				*hpc_slot_state = HPC_SLOT_EMPTY;
1693 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
1694 			} else if (slotstatus.slot_power_on == PCIMSG_ON) {
1695 				*hpc_slot_state = HPC_SLOT_CONNECTED;
1696 				SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
1697 				schpc_p->schpc_slot[slot].state |=
1698 				    SCHPC_SLOTSTATE_CONNECTED;
1699 			} else {
1700 				*hpc_slot_state = HPC_SLOT_DISCONNECTED;
1701 				SCHPC_DEBUG0(D_IOC_CONTROL,
1702 				    "Slot Disconnected");
1703 				schpc_p->schpc_slot[slot].state &=
1704 				    ~SCHPC_SLOTSTATE_CONNECTED;
1705 			}
1706 		} else {
1707 			SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
1708 
1709 			mutex_enter(&schpc_p->schpc_mutex);
1710 			schpc_p->schpc_slot[slot].state &=
1711 			    ~SCHPC_SLOTSTATE_EXECUTING;
1712 			cv_signal(&schpc_p->schpc_cv);
1713 			mutex_exit(&schpc_p->schpc_mutex);
1714 
1715 			return (HPC_ERR_FAILED);
1716 		}
1717 
1718 		mutex_enter(&schpc_p->schpc_mutex);
1719 		schpc_p->schpc_slot[slot].state &=
1720 		    ~SCHPC_SLOTSTATE_EXECUTING;
1721 		cv_signal(&schpc_p->schpc_cv);
1722 		mutex_exit(&schpc_p->schpc_mutex);
1723 
1724 		return (0);
1725 	}
1726 	case HPC_CTRL_GET_BOARD_TYPE: {
1727 		hpc_board_type_t	*hpc_board_type;
1728 
1729 		hpc_board_type = (hpc_board_type_t *)arg;
1730 
1731 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1732 		    "HPC_CTRL_GET_BOARD_TYPE");
1733 
1734 
1735 		/*
1736 		 * The HPC driver does not know what board type
1737 		 * is plugged in.
1738 		 */
1739 		*hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
1740 
1741 		mutex_enter(&schpc_p->schpc_mutex);
1742 		schpc_p->schpc_slot[slot].state &=
1743 		    ~SCHPC_SLOTSTATE_EXECUTING;
1744 		cv_signal(&schpc_p->schpc_cv);
1745 		mutex_exit(&schpc_p->schpc_mutex);
1746 
1747 		return (0);
1748 
1749 	}
1750 	case HPC_CTRL_DEV_UNCONFIG_START:
1751 	case HPC_CTRL_DEV_CONFIG_START:
1752 	case HPC_CTRL_DEV_CONFIGURED:
1753 	case HPC_CTRL_DEV_UNCONFIGURED:
1754 		mutex_enter(&schpc_p->schpc_mutex);
1755 		schpc_p->schpc_slot[slot].state &=
1756 		    ~SCHPC_SLOTSTATE_EXECUTING;
1757 		cv_signal(&schpc_p->schpc_cv);
1758 		mutex_exit(&schpc_p->schpc_mutex);
1759 
1760 		return (0);
1761 
1762 	case HPC_CTRL_GET_LED_STATE:
1763 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1764 		    "HPC_CTRL_GET_LED_STATE");
1765 		hpc_led_info = (hpc_led_info_t *)arg;
1766 
1767 		switch (hpc_led_info->led) {
1768 		case HPC_FAULT_LED:
1769 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1770 			case LED_OFF:
1771 				hpc_led_info->state = HPC_LED_OFF;
1772 				break;
1773 			case LED_ON:
1774 				hpc_led_info->state = HPC_LED_ON;
1775 				break;
1776 			case LED_FLASH:
1777 				hpc_led_info->state = HPC_LED_BLINK;
1778 				break;
1779 			}
1780 			break;
1781 
1782 		case HPC_POWER_LED:
1783 			switch (schpc_p->schpc_slot[slot].led.led_power) {
1784 			case LED_OFF:
1785 				hpc_led_info->state = HPC_LED_OFF;
1786 				break;
1787 			case LED_ON:
1788 				hpc_led_info->state = HPC_LED_ON;
1789 				break;
1790 			case LED_FLASH:
1791 				hpc_led_info->state = HPC_LED_BLINK;
1792 				break;
1793 			}
1794 			break;
1795 		case HPC_ATTN_LED:
1796 			switch (schpc_p->schpc_slot[slot].led.led_fault) {
1797 			case LED_OFF:
1798 				hpc_led_info->state = HPC_LED_OFF;
1799 				break;
1800 			case LED_ON:
1801 				hpc_led_info->state = HPC_LED_OFF;
1802 				break;
1803 			case LED_FLASH:
1804 				hpc_led_info->state = HPC_LED_ON;
1805 				break;
1806 			}
1807 			break;
1808 		case HPC_ACTIVE_LED:
1809 			switch (schpc_p->schpc_slot[slot].led.led_service) {
1810 			case LED_OFF:
1811 				hpc_led_info->state = HPC_LED_OFF;
1812 				break;
1813 			case LED_ON:
1814 				hpc_led_info->state = HPC_LED_ON;
1815 				break;
1816 			case LED_FLASH:
1817 				hpc_led_info->state = HPC_LED_BLINK;
1818 				break;
1819 			}
1820 			break;
1821 		default:
1822 			SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1823 			    "Invalid LED %x", hpc_led_info->led);
1824 
1825 			mutex_enter(&schpc_p->schpc_mutex);
1826 			schpc_p->schpc_slot[slot].state &=
1827 			    ~SCHPC_SLOTSTATE_EXECUTING;
1828 			cv_signal(&schpc_p->schpc_cv);
1829 			mutex_exit(&schpc_p->schpc_mutex);
1830 
1831 			return (HPC_ERR_FAILED);
1832 		}
1833 
1834 		mutex_enter(&schpc_p->schpc_mutex);
1835 		schpc_p->schpc_slot[slot].state &=
1836 		    ~SCHPC_SLOTSTATE_EXECUTING;
1837 		cv_signal(&schpc_p->schpc_cv);
1838 		mutex_exit(&schpc_p->schpc_mutex);
1839 
1840 		return (0);
1841 
1842 	case HPC_CTRL_SET_LED_STATE:
1843 		hpc_led_info = (hpc_led_info_t *)arg;
1844 
1845 		SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1846 		    "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1847 		    (void *)hpc_led_info);
1848 
1849 		switch (hpc_led_info->led) {
1850 		case HPC_FAULT_LED:
1851 			switch (hpc_led_info->state) {
1852 			case HPC_LED_OFF:
1853 				schpc_p->schpc_slot[slot].led.led_fault =
1854 				    LED_OFF;
1855 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1856 				break;
1857 			case HPC_LED_ON:
1858 				schpc_p->schpc_slot[slot].led.led_fault =
1859 				    LED_ON;
1860 				setslot.slot_led_fault = PCIMSG_LED_ON;
1861 				break;
1862 			case HPC_LED_BLINK:
1863 				schpc_p->schpc_slot[slot].led.led_fault =
1864 				    LED_FLASH;
1865 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1866 				break;
1867 			}
1868 			break;
1869 		case HPC_POWER_LED:
1870 			switch (hpc_led_info->state) {
1871 			case HPC_LED_OFF:
1872 				schpc_p->schpc_slot[slot].led.led_power =
1873 				    LED_OFF;
1874 				setslot.slot_led_power = PCIMSG_LED_OFF;
1875 				break;
1876 			case HPC_LED_ON:
1877 				schpc_p->schpc_slot[slot].led.led_power =
1878 				    LED_ON;
1879 				setslot.slot_led_power = PCIMSG_LED_ON;
1880 				break;
1881 			case HPC_LED_BLINK:
1882 				schpc_p->schpc_slot[slot].led.led_power =
1883 				    LED_FLASH;
1884 				setslot.slot_led_power = PCIMSG_LED_FLASH;
1885 				break;
1886 			}
1887 			break;
1888 		case HPC_ATTN_LED:
1889 			switch (hpc_led_info->state) {
1890 			case HPC_LED_OFF:
1891 				schpc_p->schpc_slot[slot].led.led_fault =
1892 				    LED_OFF;
1893 				setslot.slot_led_fault = PCIMSG_LED_OFF;
1894 				break;
1895 			case HPC_LED_ON:
1896 				schpc_p->schpc_slot[slot].led.led_fault =
1897 				    LED_FLASH;
1898 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1899 				break;
1900 			case HPC_LED_BLINK:
1901 				schpc_p->schpc_slot[slot].led.led_fault =
1902 				    LED_FLASH;
1903 				setslot.slot_led_fault = PCIMSG_LED_FLASH;
1904 				break;
1905 			}
1906 			break;
1907 		case HPC_ACTIVE_LED:
1908 			switch (hpc_led_info->state) {
1909 			case HPC_LED_OFF:
1910 				schpc_p->schpc_slot[slot].led.led_service =
1911 				    LED_OFF;
1912 				setslot.slot_led_service = PCIMSG_LED_OFF;
1913 				break;
1914 			case HPC_LED_ON:
1915 				schpc_p->schpc_slot[slot].led.led_service =
1916 				    LED_ON;
1917 				setslot.slot_led_service = PCIMSG_LED_ON;
1918 				break;
1919 			case HPC_LED_BLINK:
1920 				schpc_p->schpc_slot[slot].led.led_service =
1921 				    LED_FLASH;
1922 				setslot.slot_led_service = PCIMSG_LED_FLASH;
1923 				break;
1924 			}
1925 			break;
1926 		default:
1927 			mutex_enter(&schpc_p->schpc_mutex);
1928 			schpc_p->schpc_slot[slot].state &=
1929 			    ~SCHPC_SLOTSTATE_EXECUTING;
1930 			cv_signal(&schpc_p->schpc_cv);
1931 			mutex_exit(&schpc_p->schpc_mutex);
1932 
1933 			return (0);
1934 		}
1935 
1936 		(void) schpc_setslotstatus(expander, board, slot, &setslot);
1937 
1938 		mutex_enter(&schpc_p->schpc_mutex);
1939 		schpc_p->schpc_slot[slot].state &=
1940 		    ~SCHPC_SLOTSTATE_EXECUTING;
1941 		cv_signal(&schpc_p->schpc_cv);
1942 		mutex_exit(&schpc_p->schpc_mutex);
1943 
1944 		return (0);
1945 
1946 	case HPC_CTRL_ENABLE_AUTOCFG:
1947 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1948 		    "HPC_CTRL_ENABLE_AUTOCFG");
1949 
1950 		schpc_p->schpc_slot[slot].state |=
1951 		    SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1952 
1953 		mutex_enter(&schpc_p->schpc_mutex);
1954 		schpc_p->schpc_slot[slot].state &=
1955 		    ~SCHPC_SLOTSTATE_EXECUTING;
1956 		cv_signal(&schpc_p->schpc_cv);
1957 		mutex_exit(&schpc_p->schpc_mutex);
1958 
1959 		return (0);
1960 
1961 	case HPC_CTRL_DISABLE_AUTOCFG:
1962 		SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1963 		    "HPC_CTRL_DISABLE_AUTOCFG");
1964 		schpc_p->schpc_slot[slot].state &=
1965 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1966 
1967 		mutex_enter(&schpc_p->schpc_mutex);
1968 		schpc_p->schpc_slot[slot].state &=
1969 		    ~SCHPC_SLOTSTATE_EXECUTING;
1970 		cv_signal(&schpc_p->schpc_cv);
1971 		mutex_exit(&schpc_p->schpc_mutex);
1972 
1973 		return (0);
1974 
1975 	case HPC_CTRL_DISABLE_ENUM:
1976 	case HPC_CTRL_ENABLE_ENUM:
1977 	default:
1978 		mutex_enter(&schpc_p->schpc_mutex);
1979 		schpc_p->schpc_slot[slot].state &=
1980 		    ~SCHPC_SLOTSTATE_EXECUTING;
1981 		cv_signal(&schpc_p->schpc_cv);
1982 		mutex_exit(&schpc_p->schpc_mutex);
1983 
1984 		return (HPC_ERR_NOTSUPPORTED);
1985 	}
1986 }
1987 
1988 /*
1989  * schpc_test
1990  *
1991  * Tests the slot.
1992  */
1993 /*ARGSUSED*/
1994 static void
1995 schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags)
1996 {
1997 	pci_getslot_t	slotstatus;
1998 	pci_setslot_t	setslot;
1999 	int		expander, board;
2000 	int		rval;
2001 	int		retry = 1;
2002 
2003 	SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)",
2004 	    (void *)ops_arg, SCHPC_SLOT_NUM(slot));
2005 
2006 	SCHPC_DEBUG3(D_IOC_TEST,
2007 	    "    schpc_test() Expander=%d Board=%d Slot=%d",
2008 	    schpc_p->schpc_slot[slot].expander,
2009 	    schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot));
2010 
2011 	expander = schpc_p->schpc_slot[slot].expander;
2012 	board = schpc_p->schpc_slot[slot].board;
2013 
2014 restart_test:
2015 	/*
2016 	 * Initial the slot with its occupant and receptacle in good condition.
2017 	 */
2018 	schpc_p->schpc_slot[slot].state |=  SCHPC_SLOTSTATE_REC_GOOD;
2019 	schpc_p->schpc_slot[slot].state |=  SCHPC_SLOTSTATE_OCC_GOOD;
2020 
2021 
2022 	rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
2023 
2024 	if (rval) {
2025 		/*
2026 		 * System Controller/Mailbox failure.
2027 		 */
2028 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2029 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
2030 		    "Communicate with System Controller", expander, board,
2031 		    SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
2032 
2033 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2034 		return;
2035 	}
2036 
2037 	if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
2038 
2039 		cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
2040 		    "is not hot pluggable\n", expander, board,
2041 		    SCHPC_SLOT_NUM(slot));
2042 
2043 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2044 		return;
2045 	}
2046 
2047 	switch (slotstatus.slot_condition) {
2048 	case PCIMSG_SLOTCOND_OCC_FAIL:
2049 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2050 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2051 		    "System Controller/Occupant Failed",
2052 		    expander, board, SCHPC_SLOT_NUM(slot),
2053 		    schpc_p->schpc_slot[slot].ap_id);
2054 
2055 		schpc_setslotled(expander, board, slot,
2056 		    (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON));
2057 
2058 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_OCC_GOOD;
2059 		return;
2060 	case PCIMSG_SLOTCOND_REC_FAIL:
2061 		cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2062 		    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2063 		    "System Controller/Receptacle Failed",
2064 		    expander, board, SCHPC_SLOT_NUM(slot),
2065 		    schpc_p->schpc_slot[slot].ap_id);
2066 
2067 		schpc_setslotled(expander, board, slot,
2068 		    (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON));
2069 
2070 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2071 		return;
2072 	case PCIMSG_SLOTCOND_NOHOTPLUG:
2073 		cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
2074 		    "is not hot pluggable\n", expander, board,
2075 		    SCHPC_SLOT_NUM(slot));
2076 
2077 		schpc_p->schpc_slot[slot].state &=  ~SCHPC_SLOTSTATE_REC_GOOD;
2078 		return;
2079 	}
2080 
2081 	if (slotstatus.slot_power_on) {
2082 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
2083 
2084 		if (!slotstatus.slot_HEALTHY) {
2085 			/*
2086 			 * cPCI Adapter is not asserting HEALTHY#.
2087 			 */
2088 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2089 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2090 			    "PCI adapter not HEALTHY", expander, board,
2091 			    SCHPC_SLOT_NUM(slot),
2092 			    schpc_p->schpc_slot[slot].ap_id);
2093 
2094 			schpc_setslotled(expander, board, slot,
2095 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2096 
2097 			schpc_p->schpc_slot[slot].state &=
2098 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2099 
2100 			return;
2101 		}
2102 
2103 		if (!slotstatus.slot_powergood) {
2104 			/*
2105 			 * PCI Power Input is not good.
2106 			 */
2107 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2108 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2109 			    "System Controller PCI Power Input Not Good",
2110 			    expander, board, SCHPC_SLOT_NUM(slot),
2111 			    schpc_p->schpc_slot[slot].ap_id);
2112 
2113 			schpc_setslotled(expander, board, slot,
2114 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2115 
2116 			schpc_p->schpc_slot[slot].state &=
2117 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2118 
2119 			return;
2120 		}
2121 
2122 		if (slotstatus.slot_powerfault) {
2123 			/*
2124 			 * PCI Power Fault.
2125 			 */
2126 			cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2127 			    "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2128 			    "System Controller PCI Power Fault",
2129 			    expander, board, SCHPC_SLOT_NUM(slot),
2130 			    schpc_p->schpc_slot[slot].ap_id);
2131 
2132 			schpc_setslotled(expander, board, slot,
2133 			    (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2134 
2135 			schpc_p->schpc_slot[slot].state &=
2136 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2137 
2138 			return;
2139 		}
2140 	}
2141 
2142 	SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0");
2143 
2144 	/*
2145 	 * Is the slot empty?
2146 	 */
2147 	if (slotstatus.slot_empty) {
2148 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty");
2149 
2150 		schpc_p->schpc_slot[slot].state &=
2151 		    ~SCHPC_SLOTSTATE_PRESENT;
2152 
2153 		if (slotstatus.slot_power_on) {
2154 
2155 			SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot "
2156 			    "is powered ON");
2157 
2158 			/*
2159 			 * Tests will be retried once after powering off
2160 			 * an empty slot.
2161 			 */
2162 			if (retry) {
2163 
2164 				/*
2165 				 * Turn off the slot and restart test.
2166 				 */
2167 				SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() "
2168 				    "Turning Empty Slot OFF");
2169 
2170 				schpc_init_setslot_message(&setslot);
2171 				setslot.slot_power_off = PCIMSG_ON;
2172 				(void) schpc_setslotstatus(
2173 				    expander, board, slot, &setslot);
2174 
2175 				retry = 0;
2176 
2177 				goto restart_test;
2178 			}
2179 		}
2180 	} else {
2181 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present");
2182 
2183 		if (!slotstatus.slot_power_on) {
2184 			if (retry) {
2185 				/*
2186 				 * If there is a cassette present and the
2187 				 * power is off, try turning the power on and
2188 				 * restart the test. This allows access to
2189 				 * the FRUID when an empty cassette is
2190 				 * installed.
2191 				 */
2192 				SCHPC_DEBUG0(D_IOC_TEST,
2193 				    "schpc_test() Power On Adapter");
2194 				schpc_init_setslot_message(&setslot);
2195 				setslot.slot_power_on = PCIMSG_ON;
2196 				(void) schpc_setslotstatus(
2197 				    expander, board, slot, &setslot);
2198 				retry = 0;
2199 				goto restart_test;
2200 			}
2201 		}
2202 
2203 		schpc_p->schpc_slot[slot].state |=
2204 		    SCHPC_SLOTSTATE_PRESENT;
2205 	}
2206 
2207 	/*
2208 	 * Is the slot powered up?
2209 	 */
2210 	schpc_init_setslot_message(&setslot);
2211 
2212 	if (slotstatus.slot_power_on) {
2213 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On");
2214 
2215 		schpc_p->schpc_slot[slot].state |=
2216 		    SCHPC_SLOTSTATE_CONNECTED;
2217 
2218 		setslot.slot_led_power = PCIMSG_LED_ON;
2219 		setslot.slot_led_service = PCIMSG_LED_OFF;
2220 		setslot.slot_enable_ENUM = PCIMSG_ON;
2221 		setslot.slot_enable_HEALTHY = PCIMSG_ON;
2222 	} else {
2223 		SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off");
2224 
2225 		schpc_p->schpc_slot[slot].state &=
2226 		    ~SCHPC_SLOTSTATE_CONNECTED;
2227 
2228 		setslot.slot_led_power = PCIMSG_LED_OFF;
2229 		setslot.slot_led_service = PCIMSG_LED_ON;
2230 		setslot.slot_disable_ENUM = PCIMSG_ON;
2231 		setslot.slot_disable_HEALTHY = PCIMSG_ON;
2232 	}
2233 
2234 	setslot.slot_led_fault = PCIMSG_LED_OFF;
2235 
2236 	(void) schpc_setslotstatus(expander, board, slot, &setslot);
2237 
2238 	/*
2239 	 * Save LED State.
2240 	 */
2241 	switch (setslot.slot_led_power) {
2242 	case PCIMSG_LED_ON:
2243 		schpc_p->schpc_slot[slot].led.led_power = LED_ON;
2244 		break;
2245 	case PCIMSG_LED_OFF:
2246 		schpc_p->schpc_slot[slot].led.led_power = LED_OFF;
2247 		break;
2248 	case PCIMSG_LED_FLASH:
2249 		schpc_p->schpc_slot[slot].led.led_power = LED_FLASH;
2250 		break;
2251 	}
2252 	switch (setslot.slot_led_service) {
2253 	case PCIMSG_LED_ON:
2254 		schpc_p->schpc_slot[slot].led.led_service = LED_ON;
2255 		break;
2256 	case PCIMSG_LED_OFF:
2257 		schpc_p->schpc_slot[slot].led.led_service = LED_OFF;
2258 		break;
2259 	case PCIMSG_LED_FLASH:
2260 		schpc_p->schpc_slot[slot].led.led_service = LED_FLASH;
2261 		break;
2262 	}
2263 	switch (setslot.slot_led_fault) {
2264 	case PCIMSG_LED_ON:
2265 		schpc_p->schpc_slot[slot].led.led_fault = LED_ON;
2266 		break;
2267 	case PCIMSG_LED_OFF:
2268 		schpc_p->schpc_slot[slot].led.led_fault = LED_OFF;
2269 		break;
2270 	case PCIMSG_LED_FLASH:
2271 		schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH;
2272 		break;
2273 	}
2274 }
2275 
2276 
2277 /*
2278  * schpc_event_handler
2279  *
2280  * Placed on the schpc_event_taskq by schpc_event_filter when an
2281  * unsolicited MBOXSC_MSG_EVENT is received from the SC.  It handles
2282  * things like power insertion/removal, ENUM#, etc.
2283  */
2284 static void
2285 schpc_event_handler(void *arg)
2286 {
2287 	pci_getslot_t	slotstatus;
2288 	uint8_t		expander, board, slot;
2289 	int		rval;
2290 	pcimsg_t *event = (pcimsg_t *)arg;
2291 
2292 	/*
2293 	 * OK, we got an event message. Since the event message only tells
2294 	 * us something has changed and not changed to what, we need to get
2295 	 * the current slot status to find how WHAT was change to WHAT.
2296 	 */
2297 
2298 	slot = event->pcimsg_slot;
2299 	expander = event->pcimsg_node; /* get expander */
2300 	board = event->pcimsg_board; /* get board */
2301 
2302 	SCHPC_DEBUG3(D_EVENT,
2303 	    "schpc_event_handler() - exp=%d board=%d slot=%d",
2304 	    expander, board, slot);
2305 
2306 	/* create a slot table index */
2307 	slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot);
2308 
2309 	SCHPC_DEBUG1(D_EVENT,
2310 	    "schpc_event_handler() - expanded slot %d", slot);
2311 
2312 	if (schpc_p == NULL) {
2313 		cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc");
2314 		kmem_free(event, sizeof (pcimsg_t));
2315 		return;
2316 	}
2317 
2318 	mutex_enter(&schpc_p->schpc_mutex);
2319 
2320 	if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
2321 		SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited");
2322 		mutex_exit(&schpc_p->schpc_mutex);
2323 		kmem_free(event, sizeof (pcimsg_t));
2324 		return;
2325 	}
2326 	/*
2327 	 * Block if another thread is executing a HPC command.
2328 	 */
2329 	while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
2330 		SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy");
2331 		cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
2332 	}
2333 
2334 	schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
2335 
2336 	mutex_exit(&schpc_p->schpc_mutex);
2337 
2338 	rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
2339 
2340 	if (rval) {
2341 		cmn_err(CE_WARN, "schpc/Event Handler - Can not get status "
2342 		    "for expander=%d board=%d slot=%d\n",
2343 		    expander, board, SCHPC_SLOT_NUM(slot));
2344 
2345 		mutex_enter(&schpc_p->schpc_mutex);
2346 		schpc_p->schpc_slot[slot].state &=
2347 		    ~SCHPC_SLOTSTATE_EXECUTING;
2348 		cv_signal(&schpc_p->schpc_cv);
2349 		mutex_exit(&schpc_p->schpc_mutex);
2350 		kmem_free(event, sizeof (pcimsg_t));
2351 		return;
2352 	}
2353 
2354 	if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
2355 		cmn_err(CE_WARN, "schpc/Event Handler - Can not get good "
2356 		    "status for expander=%d board=%d slot=%d\n",
2357 		    expander, board, SCHPC_SLOT_NUM(slot));
2358 
2359 		mutex_enter(&schpc_p->schpc_mutex);
2360 		schpc_p->schpc_slot[slot].state &=
2361 		    ~SCHPC_SLOTSTATE_EXECUTING;
2362 		cv_signal(&schpc_p->schpc_cv);
2363 		mutex_exit(&schpc_p->schpc_mutex);
2364 
2365 		kmem_free(event, sizeof (pcimsg_t));
2366 		return;
2367 	}
2368 
2369 	SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d",
2370 	    expander, board, SCHPC_SLOT_NUM(slot));
2371 
2372 	if (schpc_p->schpc_slot[slot].slot_ops == NULL) {
2373 		SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event "
2374 		    "for unregistered slot for expander=%d board=%d slot=%d",
2375 		    expander, board, SCHPC_SLOT_NUM(slot));
2376 
2377 		mutex_enter(&schpc_p->schpc_mutex);
2378 		schpc_p->schpc_slot[slot].state &=
2379 		    ~SCHPC_SLOTSTATE_EXECUTING;
2380 		cv_signal(&schpc_p->schpc_cv);
2381 		mutex_exit(&schpc_p->schpc_mutex);
2382 
2383 		kmem_free(event, sizeof (pcimsg_t));
2384 		return;
2385 	}
2386 
2387 	/* Slot Power Event */
2388 
2389 	if (event->pcimsg_type.pcimsg_slotevent.slot_power) {
2390 		SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event");
2391 		/*
2392 		 * The SC may have changed to slot power status.
2393 		 */
2394 		if (slotstatus.slot_power_on) {
2395 			schpc_p->schpc_slot[slot].state |=
2396 			    SCHPC_SLOTSTATE_CONNECTED;
2397 
2398 			(void) hpc_slot_event_notify(
2399 			    schpc_p->schpc_slot[slot].slot_handle,
2400 			    HPC_EVENT_SLOT_POWER_ON, 0);
2401 		} else {
2402 			schpc_p->schpc_slot[slot].state &=
2403 			    ~SCHPC_SLOTSTATE_CONNECTED;
2404 
2405 			(void) hpc_slot_event_notify(
2406 			    schpc_p->schpc_slot[slot].slot_handle,
2407 			    HPC_EVENT_SLOT_POWER_OFF, 0);
2408 		}
2409 	}
2410 
2411 	/* Adapter Insertion/Removal Event */
2412 
2413 	if (event->pcimsg_type.pcimsg_slotevent.slot_presence) {
2414 		if (slotstatus.slot_empty == PCIMSG_ON) {
2415 
2416 			/* Adapter Removed */
2417 
2418 			SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed");
2419 
2420 			if (schpc_p->schpc_slot[slot].state &
2421 			    SCHPC_SLOTSTATE_CONNECTED) {
2422 				/*
2423 				 * If the adapter has been removed while
2424 				 * there the slot is connected, it could be
2425 				 * due to a ENUM handling.
2426 				 */
2427 				cmn_err(CE_WARN, "Card removed from "
2428 				    "powered on slot at "
2429 				    "expander=%d board=%d slot=%d\n",
2430 				    expander, board, SCHPC_SLOT_NUM(slot));
2431 
2432 				schpc_p->schpc_slot[slot].state &=
2433 				    ~SCHPC_SLOTSTATE_EXECUTING;
2434 				rval = schpc_disconnect((caddr_t)schpc_p,
2435 				    schpc_p->schpc_slot[slot].slot_handle,
2436 				    0, 0);
2437 				mutex_enter(&schpc_p->schpc_mutex);
2438 				while (schpc_p->schpc_slot[slot].state &
2439 				    SCHPC_SLOTSTATE_EXECUTING) {
2440 					SCHPC_DEBUG0(D_EVENT,
2441 					    "schpc_event_handler - "
2442 					    "Slot is busy");
2443 					cv_wait(&schpc_p->schpc_cv,
2444 					    &schpc_p->schpc_mutex);
2445 				}
2446 
2447 				schpc_p->schpc_slot[slot].state |=
2448 				    SCHPC_SLOTSTATE_EXECUTING;
2449 
2450 				mutex_exit(&schpc_p->schpc_mutex);
2451 			}
2452 			schpc_p->schpc_slot[slot].state |=
2453 			    SCHPC_SLOTSTATE_OCC_GOOD;
2454 
2455 			schpc_p->schpc_slot[slot].state &=
2456 			    ~SCHPC_SLOTSTATE_PRESENT;
2457 
2458 			(void) hpc_slot_event_notify(
2459 			    schpc_p->schpc_slot[slot].slot_handle,
2460 			    HPC_EVENT_SLOT_REMOVAL, 0);
2461 		} else {
2462 
2463 			/* Adapter Inserted */
2464 
2465 			SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted");
2466 
2467 			if (schpc_p->schpc_slot[slot].state &
2468 			    SCHPC_SLOTSTATE_PRESENT) {
2469 				/*
2470 				 * If the adapter is already present
2471 				 * throw the this event away.
2472 				 */
2473 
2474 				SCHPC_DEBUG0(D_EVENT,
2475 				    "Adapter is already present");
2476 
2477 				mutex_enter(&schpc_p->schpc_mutex);
2478 				schpc_p->schpc_slot[slot].state &=
2479 				    ~SCHPC_SLOTSTATE_EXECUTING;
2480 				cv_signal(&schpc_p->schpc_cv);
2481 				mutex_exit(&schpc_p->schpc_mutex);
2482 
2483 				kmem_free(event, sizeof (pcimsg_t));
2484 				return;
2485 			}
2486 
2487 			schpc_p->schpc_slot[slot].state |=
2488 			    SCHPC_SLOTSTATE_PRESENT;
2489 
2490 			schpc_p->schpc_slot[slot].state &=
2491 			    ~SCHPC_SLOTSTATE_CONNECTED;
2492 
2493 			(void) hpc_slot_event_notify(
2494 			    schpc_p->schpc_slot[slot].slot_handle,
2495 			    HPC_EVENT_SLOT_INSERTION, 0);
2496 
2497 			if (schpc_p->schpc_slot[slot].state &
2498 			    SCHPC_SLOTSTATE_AUTOCFG_ENABLE) {
2499 				SCHPC_DEBUG0(D_EVENT, "Auto Configuration "
2500 				    "(Connect/Configure) Started");
2501 
2502 				schpc_p->schpc_slot[slot].state &=
2503 				    ~SCHPC_SLOTSTATE_EXECUTING;
2504 
2505 				rval = schpc_connect((caddr_t)schpc_p,
2506 				    schpc_p->schpc_slot[slot].slot_handle,
2507 				    0, 0);
2508 
2509 				if (rval) {
2510 					cmn_err(CE_WARN, "schpc/Event Handler -"
2511 					    " Can not connect");
2512 
2513 					mutex_enter(&schpc_p->schpc_mutex);
2514 					schpc_p->schpc_slot[slot].state &=
2515 					    ~SCHPC_SLOTSTATE_EXECUTING;
2516 					cv_signal(&schpc_p->schpc_cv);
2517 					mutex_exit(&schpc_p->schpc_mutex);
2518 
2519 					kmem_free(event, sizeof (pcimsg_t));
2520 					return;
2521 				}
2522 				mutex_enter(&schpc_p->schpc_mutex);
2523 				while (schpc_p->schpc_slot[slot].state &
2524 				    SCHPC_SLOTSTATE_EXECUTING) {
2525 					SCHPC_DEBUG0(D_EVENT,
2526 					    "schpc_event_handler - "
2527 					    "Slot is busy");
2528 					cv_wait(&schpc_p->schpc_cv,
2529 					    &schpc_p->schpc_mutex);
2530 				}
2531 
2532 				schpc_p->schpc_slot[slot].state |=
2533 				    SCHPC_SLOTSTATE_EXECUTING;
2534 
2535 				mutex_exit(&schpc_p->schpc_mutex);
2536 
2537 				(void) hpc_slot_event_notify(
2538 				    schpc_p->schpc_slot[slot].slot_handle,
2539 				    HPC_EVENT_SLOT_CONFIGURE, 0);
2540 			} else {
2541 				schpc_setslotled(expander, board, slot,
2542 				    SERVICE_LED_ON);
2543 			}
2544 		}
2545 	}
2546 
2547 	/* ENUM# signal change event */
2548 
2549 	if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) {
2550 		/*
2551 		 * ENUM should only be received to the adapter remove
2552 		 * procedure.
2553 		 */
2554 
2555 		SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted");
2556 
2557 		schpc_setslotled(expander, board, slot, FAULT_LED_FLASH);
2558 
2559 		schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM;
2560 
2561 		(void) hpc_slot_event_notify(
2562 		    schpc_p->schpc_slot[slot].slot_handle,
2563 		    HPC_EVENT_SLOT_ENUM, 0);
2564 	}
2565 
2566 	/* HEALTHY# signal change event */
2567 
2568 	if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) {
2569 
2570 		if (!slotstatus.slot_HEALTHY) {
2571 
2572 			SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED");
2573 
2574 			schpc_p->schpc_slot[slot].state &=
2575 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2576 
2577 			(void) hpc_slot_event_notify(
2578 			    schpc_p->schpc_slot[slot].slot_handle,
2579 			    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2580 
2581 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2582 		} else {
2583 			SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK");
2584 
2585 			schpc_p->schpc_slot[slot].state |=
2586 			    SCHPC_SLOTSTATE_OCC_GOOD;
2587 
2588 			(void) hpc_slot_event_notify(
2589 			    schpc_p->schpc_slot[slot].slot_handle,
2590 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
2591 
2592 			schpc_setslotled(expander, board, slot,
2593 			    FAULT_LED_OFF);
2594 		}
2595 	}
2596 
2597 	/* Good Power change event */
2598 
2599 	if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) {
2600 		if (slotstatus.slot_powergood == PCIMSG_ON) {
2601 
2602 			SCHPC_DEBUG0(D_EVENT,
2603 			    "Event Type: Slot Power Good Detected");
2604 
2605 			schpc_p->schpc_slot[slot].state |=
2606 			    SCHPC_SLOTSTATE_OCC_GOOD;
2607 
2608 			(void) hpc_slot_event_notify(
2609 			    schpc_p->schpc_slot[slot].slot_handle,
2610 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
2611 
2612 			schpc_setslotled(expander, board, slot,
2613 			    FAULT_LED_OFF);
2614 		} else {
2615 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good "
2616 			    "Detected");
2617 
2618 			if (schpc_p->schpc_slot[slot].state &
2619 			    SCHPC_SLOTSTATE_CONNECTED) {
2620 
2621 				SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: "
2622 				    "power failed");
2623 
2624 				schpc_p->schpc_slot[slot].state &=
2625 				    ~SCHPC_SLOTSTATE_OCC_GOOD;
2626 
2627 				(void) hpc_slot_event_notify(
2628 				    schpc_p->schpc_slot[slot].slot_handle,
2629 				    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2630 
2631 				schpc_setslotled(expander, board, slot,
2632 				    FAULT_LED_ON);
2633 			}
2634 		}
2635 	}
2636 
2637 	/* Power Fault change event */
2638 
2639 	if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) {
2640 		if (slotstatus.slot_powerfault == PCIMSG_ON) {
2641 
2642 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2643 			    "Detected");
2644 
2645 			schpc_p->schpc_slot[slot].state &=
2646 			    ~SCHPC_SLOTSTATE_OCC_GOOD;
2647 
2648 			(void) hpc_slot_event_notify(
2649 			    schpc_p->schpc_slot[slot].slot_handle,
2650 			    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2651 
2652 			schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2653 		} else {
2654 			SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2655 			    "Cleared");
2656 
2657 			schpc_p->schpc_slot[slot].state |=
2658 			    SCHPC_SLOTSTATE_OCC_GOOD;
2659 
2660 			(void) hpc_slot_event_notify(
2661 			    schpc_p->schpc_slot[slot].slot_handle,
2662 			    HPC_EVENT_SLOT_HEALTHY_OK, 0);
2663 
2664 			schpc_setslotled(expander, board, slot,
2665 			    FAULT_LED_OFF);
2666 		}
2667 	}
2668 	mutex_enter(&schpc_p->schpc_mutex);
2669 	schpc_p->schpc_slot[slot].state &=
2670 	    ~SCHPC_SLOTSTATE_EXECUTING;
2671 	cv_signal(&schpc_p->schpc_cv);
2672 	mutex_exit(&schpc_p->schpc_mutex);
2673 
2674 	kmem_free(event, sizeof (pcimsg_t));
2675 }
2676 
2677 
2678 /*
2679  * schpc_event_filter
2680  *
2681  * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the
2682  * schpc_event_taskq for processing by the schpc_event_handler _if_
2683  * hotpluggable pci slots have been registered; otherwise, the
2684  * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox
2685  * open for future messages.
2686  */
2687 static void
2688 schpc_event_filter(pcimsg_t *pmsg)
2689 {
2690 	if (slots_registered == B_TRUE) {
2691 
2692 		pcimsg_t *pevent;
2693 
2694 		/*
2695 		 * If hotpluggable pci slots have been registered then enqueue
2696 		 * the event onto the schpc_event_taskq for processing.
2697 		 */
2698 
2699 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2700 		    "slots_registered = B_TRUE");
2701 
2702 		pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP);
2703 		bcopy(pmsg, pevent, sizeof (pcimsg_t));
2704 
2705 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2706 		    "event alloc'd");
2707 
2708 		if (taskq_dispatch(schpc_event_taskq, schpc_event_handler,
2709 		    (void *)pevent, TQ_SLEEP) == NULL) {
2710 			cmn_err(CE_WARN, "schpc: schpc_event_filter - "
2711 			    "taskq_dispatch failed to enqueue event");
2712 			kmem_free(pevent, sizeof (pcimsg_t));
2713 			return;
2714 		}
2715 
2716 		SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2717 		    "event was taskq_dispatch'ed to schpc_event_handler");
2718 	} else {
2719 		/*
2720 		 * Oops, schpc received an event _before_ the slots have been
2721 		 * registered. In that case there is no choice but to toss
2722 		 * the event.
2723 		 */
2724 		cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding "
2725 		    "premature event");
2726 	}
2727 }
2728 
2729 
2730 /*
2731  * schpc_msg_thread
2732  * A stand-alone thread that monitors the incoming mailbox for
2733  * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from
2734  * the mailbox for processing.
2735  *
2736  * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the
2737  * schpc_replylist, and the waiting thread is notified that its REPLY
2738  * message has arrived; otherwise, if no REPLY match is found, then it is
2739  * discarded.
2740  *
2741  * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed
2742  * by the schpc_event_handler.
2743  *
2744  * The schpc_msg_thread is started in _init().
2745  */
2746 void
2747 schpc_msg_thread(void)
2748 {
2749 	int			err;
2750 	uint32_t		type;
2751 	uint32_t		cmd;
2752 	uint64_t		transid;
2753 	uint32_t		length;
2754 	pcimsg_t		msg;
2755 
2756 	SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running");
2757 
2758 	/* CONSTCOND */
2759 	while (1) {
2760 
2761 		/* setup wildcard arguments */
2762 		type = 0;
2763 		cmd = 0;
2764 		transid = 0;
2765 		length = sizeof (pcimsg_t);
2766 		bzero(&msg, sizeof (pcimsg_t));
2767 
2768 		err = mboxsc_getmsg(KEY_SCPC, &type, &cmd,
2769 		    &transid, &length, (void *)&msg,
2770 		    schpc_timeout_getmsg);
2771 
2772 		if (err) {
2773 			switch (err) {
2774 
2775 			/*FALLTHROUGH*/
2776 			case ETIMEDOUT:
2777 			case EAGAIN:
2778 				continue;
2779 
2780 			default:
2781 				/*
2782 				 * unfortunately, we can't do very much here
2783 				 * because we're wildcarding mboxsc_getmsg
2784 				 * so if it encounters an error, we can't
2785 				 * identify which transid it belongs to.
2786 				 */
2787 				cmn_err(CE_WARN,
2788 				"schpc - mboxsc_getmsg failed, err=0x%x", err);
2789 				delay(drv_usectohz(100000));
2790 				continue;
2791 			}
2792 		}
2793 
2794 		if (msg.pcimsg_revision != PCIMSG_REVISION) {
2795 			/*
2796 			 * This version of the schpc driver only understands
2797 			 * version 1.0 of the PCI Hot Plug Message format.
2798 			 */
2799 			cmn_err(CE_WARN, " schpc: schpc_msg_thread - "
2800 			    "discarding event w/ unknown message version %x",
2801 			    msg.pcimsg_revision);
2802 			continue;
2803 		}
2804 
2805 		switch (type) {
2806 
2807 		case MBOXSC_MSG_EVENT:
2808 			schpc_event_filter(&msg);
2809 			break;
2810 
2811 		case MBOXSC_MSG_REPLY:
2812 			schpc_reply_handler(&msg, type, cmd, transid, length);
2813 			break;
2814 
2815 		default:
2816 			cmn_err(CE_WARN,
2817 			    "schpc - mboxsc_getmsg unknown msg"
2818 			    " type=0x%x", type);
2819 			break;
2820 		}
2821 	}
2822 	/* this thread never exits */
2823 }
2824 
2825 
2826 void
2827 schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
2828 			uint64_t transid, uint32_t length)
2829 {
2830 	schpc_replylist_t	*entry;
2831 
2832 	mutex_enter(&schpc_replylist_mutex);
2833 	entry = schpc_replylist_first;
2834 	while (entry != NULL) {
2835 		if (entry->transid == transid) {
2836 			break;
2837 		} else
2838 			entry = entry->next;
2839 	}
2840 	if (entry) {
2841 		SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2842 		    "schpc_reply_handler() - 0x%lx transid reply "
2843 		    "received", transid);
2844 
2845 		mutex_enter(&entry->reply_lock);
2846 		if (entry->reply_cexit == B_FALSE) {
2847 			SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2848 			    "schpc_reply_handler() - 0x%lx transid"
2849 			    " cv_signal waiting thread", transid);
2850 
2851 			/*
2852 			 * emulate mboxsc_getmsg by copying the reply
2853 			 */
2854 			entry->type = type;
2855 			entry->cmd = cmd;
2856 			entry->transid = transid;
2857 			entry->length = length;
2858 			bcopy((caddr_t)pmsg, &entry->reply, length);
2859 
2860 			/* reply was received */
2861 			entry->reply_recvd = B_TRUE;
2862 
2863 			/*
2864 			 * wake up thread waiting for reply with transid
2865 			 */
2866 			cv_signal(&entry->reply_cv);
2867 		}
2868 		mutex_exit(&entry->reply_lock);
2869 	} else {
2870 		cmn_err(CE_WARN, "schpc - no match for transid 0x%lx",
2871 		    transid);
2872 	}
2873 	mutex_exit(&schpc_replylist_mutex);
2874 }
2875 
2876 
2877 /*
2878  * schpc_putrequest
2879  *
2880  * A wrapper around the synchronous call mboxsc_putmsg().
2881  */
2882 int
2883 schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
2884 		uint32_t length, void *datap, clock_t timeout,
2885 		schpc_replylist_t **entryp)
2886 {
2887 	int rval;
2888 
2889 	/* add the request to replylist to keep track of outstanding requests */
2890 	*entryp = schpc_replylist_link(cmd, *transidp, length);
2891 
2892 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2893 	    "0x%lx transid mboxsc_putmsg called", *transidp);
2894 
2895 	/* wait synchronously for request to be sent */
2896 	rval = mboxsc_putmsg(key, type, cmd, transidp, length,
2897 	    (void *)datap, timeout);
2898 
2899 	SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2900 	    "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval);
2901 
2902 	/* if problem is encountered then remove the request from replylist */
2903 	if (rval)
2904 		schpc_replylist_unlink(*entryp);
2905 
2906 	return (rval);
2907 }
2908 
2909 
2910 /*
2911  * schpc_getreply
2912  *
2913  * Wait for the schpc_msg_thread to respond that a matching reply has
2914  * arrived; otherwise, timeout and remove the entry from the schpc_replylist.
2915  */
2916 /*ARGSUSED*/
2917 int
2918 schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
2919 		uint64_t *transidp, uint32_t *lengthp, void *datap,
2920 		clock_t timeout, schpc_replylist_t *listp)
2921 {
2922 	int rc = 0;
2923 
2924 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2925 	    "schpc_getreply() - 0x%lx transid waiting for reply",
2926 	    *transidp);
2927 
2928 	/*
2929 	 * wait here until schpc_msg_thread because it's always
2930 	 * looking for reply messages
2931 	 */
2932 	mutex_enter(&listp->reply_lock);
2933 
2934 	while (listp->reply_recvd == B_FALSE) {
2935 		/*
2936 		 * wait for reply or timeout
2937 		 */
2938 		rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock,
2939 		    ddi_get_lbolt() + drv_usectohz(timeout * 1000));
2940 		switch (rc) {
2941 		case -1: /* most likely a timeout, but check anyway */
2942 
2943 			/* message was received after all */
2944 			if (listp->reply_recvd == B_TRUE)
2945 				break;
2946 
2947 			/* no, it's really a timeout */
2948 			listp->reply_cexit = B_TRUE;
2949 			mutex_exit(&listp->reply_lock);
2950 			cmn_err(CE_WARN,
2951 			"schpc - 0x%lx transid reply timed out", *transidp);
2952 			schpc_replylist_unlink(listp);
2953 			return (ETIMEDOUT);
2954 
2955 		default:
2956 			break;
2957 		}
2958 	}
2959 
2960 	*typep = listp->type;
2961 	*cmdp = listp->cmd;
2962 	*transidp = listp->transid;
2963 	*lengthp = listp->length;
2964 	bcopy((caddr_t)&listp->reply, datap, *lengthp);
2965 	mutex_exit(&listp->reply_lock);
2966 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2967 	    "schpc_getreply() - 0x%lx transid received", *transidp);
2968 	schpc_replylist_unlink(listp);
2969 	return (0);
2970 }
2971 
2972 
2973 /*
2974  * schpc_replylist_unlink
2975  *
2976  * Deallocate a schpc_replylist_t element.
2977  */
2978 void
2979 schpc_replylist_unlink(schpc_replylist_t *entry)
2980 {
2981 #if DEBUG
2982 	schpc_replylist_t *dbg_entry;
2983 #endif	/* DEBUG */
2984 
2985 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2986 	    "schpc_replylist_unlink() - 0x%lx transid deleted from replylist",
2987 	    entry->transid);
2988 
2989 	mutex_enter(&schpc_replylist_mutex);
2990 	if (entry->prev) {
2991 		entry->prev->next = entry->next;
2992 		if (entry->next)
2993 			entry->next->prev = entry->prev;
2994 	} else {
2995 		schpc_replylist_first = entry->next;
2996 		if (entry->next)
2997 			entry->next->prev = NULL;
2998 	}
2999 	if (entry == schpc_replylist_last) {
3000 		schpc_replylist_last = entry->prev;
3001 	}
3002 	kmem_free(entry, sizeof (schpc_replylist_t));
3003 	schpc_replylist_count--;
3004 
3005 #if DEBUG
3006 	if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3007 		dbg_entry = schpc_replylist_first;
3008 		cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist "
3009 		    "count = %d\n", schpc_replylist_count);
3010 		while (dbg_entry != NULL) {
3011 			cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - "
3012 			    "0x%lx transid\n", dbg_entry->transid);
3013 			dbg_entry = dbg_entry->next;
3014 		}
3015 	}
3016 #endif	/* DEBUG  */
3017 
3018 	mutex_exit(&schpc_replylist_mutex);
3019 }
3020 
3021 
3022 /*
3023  * schpc_replylist_link
3024  *
3025  * Allocate and initialize a schpc_replylist_t element.
3026  */
3027 schpc_replylist_t *
3028 schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length)
3029 {
3030 	schpc_replylist_t *entry;
3031 #if DEBUG
3032 	schpc_replylist_t *dbg_entry;
3033 #endif	/* DEBUG */
3034 
3035 	SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
3036 	    "schpc_replylist_link() - 0x%lx transid inserting into replylist",
3037 	    transid);
3038 
3039 	entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP);
3040 	mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL);
3041 	cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL);
3042 	entry->type = MBOXSC_MSG_REPLY;
3043 	entry->cmd  = cmd;
3044 	entry->transid  = transid;
3045 	entry->length  = length;
3046 	entry->reply_recvd = B_FALSE;
3047 	entry->reply_cexit = B_FALSE;
3048 
3049 	mutex_enter(&schpc_replylist_mutex);
3050 	if (schpc_replylist_last) {
3051 		entry->prev = schpc_replylist_last;
3052 		schpc_replylist_last->next = entry;
3053 		schpc_replylist_last = entry;
3054 	} else {
3055 		schpc_replylist_last = schpc_replylist_first = entry;
3056 	}
3057 
3058 	schpc_replylist_count++;
3059 
3060 #if DEBUG
3061 	if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3062 		dbg_entry = schpc_replylist_first;
3063 		cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist "
3064 		    "count = %d\n", schpc_replylist_count);
3065 		while (dbg_entry != NULL) {
3066 			cmn_err(CE_CONT, "schpc: schpc_replylist_link() - "
3067 			    "0x%lx transid\n", dbg_entry->transid);
3068 			dbg_entry = dbg_entry->next;
3069 		}
3070 	}
3071 #endif	/* DEBUG  */
3072 
3073 	mutex_exit(&schpc_replylist_mutex);
3074 
3075 	return (entry);
3076 }
3077 
3078 
3079 /*
3080  * schpc_getslotstatus
3081  *
3082  * Issues a Get Slot Status command to the System Controller
3083  * for a specific slot.
3084  */
3085 static int
3086 schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3087     pci_getslot_t *slotstatus)
3088 {
3089 	pcimsg_t	request;
3090 	pcimsg_t	reply;
3091 	int		rval;
3092 	uint32_t	type, cmd, length;
3093 	uint64_t	transid;
3094 	schpc_replylist_t *entry;
3095 
3096 	SCHPC_DEBUG4(D_GETSLOTSTATUS,
3097 	    "schpc_getslotstatus(expander=%d board=%d "
3098 	    "slot=%d slotstatus=0x%p", expander, board,
3099 	    SCHPC_SLOT_NUM(slot), (void *)slotstatus);
3100 
3101 	if (schpc_p == NULL) {
3102 		return (1);
3103 	}
3104 
3105 	bzero(&request, sizeof (pcimsg_t));
3106 
3107 	request.pcimsg_node = expander;
3108 	request.pcimsg_board = board;
3109 	request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3110 	request.pcimsg_revision = PCIMSG_REVISION;
3111 	request.pcimsg_command = PCIMSG_GETSLOTSTATUS;
3112 
3113 	type = MBOXSC_MSG_REQUEST;
3114 	cmd = PCIMSG_GETSLOTSTATUS;
3115 	transid =  schpc_gettransid(schpc_p, slot);
3116 	length = sizeof (pcimsg_t);
3117 
3118 	SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3119 	    "0x%lx transid schpc_putrequest called", transid);
3120 
3121 	rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3122 	    (void *)&request, schpc_timeout_putmsg, &entry);
3123 
3124 	SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3125 	    "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3126 
3127 	if (rval) {
3128 		return (rval);
3129 	}
3130 
3131 	bzero(&reply, sizeof (pcimsg_t));
3132 	type = MBOXSC_MSG_REPLY;
3133 
3134 	SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3135 	    "0x%lx transid schpc_getreply called", transid);
3136 
3137 	rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3138 	    (void *)&reply, schpc_timeout_getmsg, entry);
3139 
3140 	SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3141 	    "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3142 
3143 	if (rval == 0) {
3144 		*slotstatus = reply.pcimsg_type.pcimsg_getslot;
3145 
3146 		SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()");
3147 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_power_on %x",
3148 		    reply.pcimsg_type.pcimsg_getslot.slot_power_on);
3149 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_powergood %x",
3150 		    reply.pcimsg_type.pcimsg_getslot.slot_powergood);
3151 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_powerfault %x",
3152 		    reply.pcimsg_type.pcimsg_getslot.slot_powerfault);
3153 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_empty %x",
3154 		    reply.pcimsg_type.pcimsg_getslot.slot_empty);
3155 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_freq_cap %x",
3156 		    reply.pcimsg_type.pcimsg_getslot.slot_freq_cap);
3157 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_freq_setting %x",
3158 		    reply.pcimsg_type.pcimsg_getslot.slot_freq_setting);
3159 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_condition %x",
3160 		    reply.pcimsg_type.pcimsg_getslot.slot_condition);
3161 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_HEALTHY %x",
3162 		    reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY);
3163 		SCHPC_DEBUG1(D_GETSLOTSTATUS, "    slot_ENUM %x",
3164 		    reply.pcimsg_type.pcimsg_getslot.slot_ENUM);
3165 	}
3166 
3167 	return (rval);
3168 }
3169 
3170 
3171 /*
3172  * schpc_setslotstatus
3173  *
3174  * Issues a Set Slot Status command to the System Controller
3175  * for a specific slot.
3176  */
3177 static int
3178 schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3179     pci_setslot_t *slotstatus)
3180 {
3181 	pcimsg_t	request;
3182 	pcimsg_t	reply;
3183 	int		rval;
3184 	uint32_t	type, cmd, length;
3185 	uint64_t	transid;
3186 	schpc_replylist_t *entry;
3187 
3188 	SCHPC_DEBUG4(D_SETSLOTSTATUS,
3189 	    "schpc_setslotstatus(expander=%d board=%d "
3190 	    "slot=%d slotstatus=0x%p", expander, board,
3191 	    SCHPC_SLOT_NUM(slot), (void *)slotstatus);
3192 
3193 	bzero(&request, sizeof (pcimsg_t));
3194 
3195 	if (schpc_p == NULL) {
3196 		return (1);
3197 	}
3198 
3199 	request.pcimsg_node = expander;
3200 	request.pcimsg_board = board;
3201 	request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3202 	request.pcimsg_revision = PCIMSG_REVISION;
3203 	request.pcimsg_command = PCIMSG_SETSLOTSTATUS;
3204 
3205 	request.pcimsg_type.pcimsg_setslot = *slotstatus;
3206 
3207 	SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change");
3208 	SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d",
3209 	    slotstatus->slot_led_power,
3210 	    slotstatus->slot_led_service,
3211 	    slotstatus->slot_led_fault);
3212 
3213 	type = MBOXSC_MSG_REQUEST;
3214 	cmd = PCIMSG_SETSLOTSTATUS;
3215 	transid =  schpc_gettransid(schpc_p, slot);
3216 	length = sizeof (pcimsg_t);
3217 
3218 	SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3219 	    "0x%lx transid schpc_putrequest called", transid);
3220 
3221 	rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3222 	    (void *)&request, schpc_timeout_putmsg, &entry);
3223 
3224 	SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3225 	    "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3226 
3227 	if (rval) {
3228 		return (rval);
3229 	}
3230 
3231 	bzero(&reply, sizeof (pcimsg_t));
3232 	type = MBOXSC_MSG_REPLY;
3233 
3234 	SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3235 	    "0x%lx transid schpc_getreply called", transid);
3236 
3237 	rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3238 	    (void *)&reply, schpc_timeout_getmsg, entry);
3239 
3240 	SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3241 	    "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3242 
3243 	if (rval == 0) {
3244 		slotstatus->slot_replystatus =
3245 		    reply.pcimsg_type.pcimsg_setslot.slot_replystatus;
3246 	}
3247 
3248 	return (rval);
3249 }
3250 
3251 /*
3252  * schpc_setslotled
3253  *
3254  * Changes the attention indicators for a given slot.
3255  */
3256 static void
3257 schpc_setslotled(int expander, int board, int slot, uint32_t led_state)
3258 {
3259 
3260 	pci_setslot_t	setslot;
3261 
3262 	if (schpc_p == NULL) {
3263 		return;
3264 	}
3265 
3266 	schpc_init_setslot_message(&setslot);
3267 
3268 	if (led_state & POWER_LED_ON) {
3269 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
3270 	}
3271 	if (led_state & POWER_LED_OFF) {
3272 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF;
3273 	}
3274 	if (led_state & POWER_LED_FLASH) {
3275 		schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH;
3276 	}
3277 	if (led_state & SERVICE_LED_ON) {
3278 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON;
3279 	}
3280 	if (led_state & SERVICE_LED_OFF) {
3281 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF;
3282 	}
3283 	if (led_state & SERVICE_LED_FLASH) {
3284 		schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH;
3285 	}
3286 	if (led_state & FAULT_LED_ON) {
3287 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON;
3288 	}
3289 	if (led_state & FAULT_LED_OFF) {
3290 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF;
3291 	}
3292 	if (led_state & FAULT_LED_FLASH) {
3293 		schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH;
3294 	}
3295 
3296 	switch (schpc_p->schpc_slot[slot].led.led_power) {
3297 	case PCIMSG_LED_ON:
3298 		setslot.slot_led_power = PCIMSG_LED_ON;
3299 		break;
3300 	case PCIMSG_LED_OFF:
3301 		setslot.slot_led_power = PCIMSG_LED_OFF;
3302 		break;
3303 	case PCIMSG_LED_FLASH:
3304 		setslot.slot_led_power = PCIMSG_LED_FLASH;
3305 		break;
3306 	}
3307 	switch (schpc_p->schpc_slot[slot].led.led_service) {
3308 	case PCIMSG_LED_ON:
3309 		setslot.slot_led_service = PCIMSG_LED_ON;
3310 		break;
3311 	case PCIMSG_LED_OFF:
3312 		setslot.slot_led_service = PCIMSG_LED_OFF;
3313 		break;
3314 	case PCIMSG_LED_FLASH:
3315 		setslot.slot_led_service = PCIMSG_LED_FLASH;
3316 		break;
3317 	}
3318 	switch (schpc_p->schpc_slot[slot].led.led_fault) {
3319 	case PCIMSG_LED_ON:
3320 		setslot.slot_led_fault = PCIMSG_LED_ON;
3321 		break;
3322 	case PCIMSG_LED_OFF:
3323 		setslot.slot_led_fault = PCIMSG_LED_OFF;
3324 		break;
3325 	case PCIMSG_LED_FLASH:
3326 		setslot.slot_led_fault = PCIMSG_LED_FLASH;
3327 		break;
3328 	}
3329 
3330 	(void) schpc_setslotstatus(expander, board, slot, &setslot);
3331 }
3332 
3333 /*
3334  * schpc_init_setslot_message
3335  *
3336  * Initialize Set Slot Message before using it.
3337  */
3338 static void
3339 schpc_init_setslot_message(pci_setslot_t *setslot)
3340 {
3341 	/*
3342 	 * Initialize Set Slot Command.
3343 	 */
3344 	setslot->slot_power_on = PCIMSG_OFF;
3345 	setslot->slot_power_off = PCIMSG_OFF;
3346 	setslot->slot_led_power = PCIMSG_LED_OFF;
3347 	setslot->slot_led_service = PCIMSG_LED_OFF;
3348 	setslot->slot_led_fault = PCIMSG_LED_OFF;
3349 	setslot->slot_disable_ENUM = PCIMSG_OFF;
3350 	setslot->slot_enable_ENUM = PCIMSG_OFF;
3351 	setslot->slot_disable_HEALTHY = PCIMSG_OFF;
3352 	setslot->slot_enable_HEALTHY = PCIMSG_OFF;
3353 }
3354 
3355 /*
3356  * schpc_gettransid
3357  *
3358  * Builds a unique transaction ID.
3359  */
3360 static uint64_t
3361 schpc_gettransid(schpc_t *schpc_p, int slot)
3362 {
3363 	uint64_t	trans_id;
3364 
3365 	mutex_enter(&schpc_p->schpc_mutex);
3366 
3367 	if (++schpc_p->schpc_transid == 0)
3368 		schpc_p->schpc_transid = 1;
3369 
3370 	trans_id = (schpc_p->schpc_slot[slot].expander<<24) |
3371 	    (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid;
3372 
3373 	mutex_exit(&schpc_p->schpc_mutex);
3374 
3375 	SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning",
3376 	    trans_id);
3377 
3378 	return (trans_id);
3379 }
3380 
3381 /*
3382  * schpc_slot_get_index
3383  *
3384  * get slot table index from the slot handle
3385  */
3386 static int
3387 schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot)
3388 {
3389 	int	i;
3390 	int	rval = -1;
3391 
3392 	ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex));
3393 
3394 	for (i = 0; i < schpc_p->schpc_number_of_slots; i++) {
3395 		if (schpc_p->schpc_slot[i].slot_handle == slot)
3396 			return (i);
3397 	}
3398 
3399 	return (rval);
3400 }
3401 
3402 /*
3403  * schpc_register_all_slots
3404  *
3405  * Search device tree for pci nodes and register attachment points
3406  * for all hot pluggable slots.
3407  */
3408 /*ARGSUSED*/
3409 static void
3410 schpc_register_all_slots(schpc_t *schpc_p)
3411 {
3412 	int		slot = 0;
3413 	char		caddr[64];
3414 	dev_info_t	*pci_dip = NULL;
3415 	find_dev_t	find_dev;
3416 	int		leaf, schizo, expander, portid, offset;
3417 
3418 	SCHPC_DEBUG1(D_ATTACH,
3419 	    "schpc_register_all_slots(schpc_p=%p)", (void *)schpc_p);
3420 
3421 	/*
3422 	 * Allow the event_handler to start processing unsolicited
3423 	 * events now that slots are about to be registered.
3424 	 */
3425 	slots_registered = B_TRUE;
3426 
3427 	for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) {
3428 
3429 		leaf = SCHPC_SLOT_LEAF(slot);
3430 		schizo = SCHPC_SLOT_SCHIZO(slot);
3431 		expander = SCHPC_SLOT_EXPANDER(slot);
3432 
3433 		if (schizo == 0)
3434 			portid = 0x1c;
3435 		else
3436 			portid = 0x1d;
3437 
3438 		if (leaf == 0)
3439 			offset = 0x600000;
3440 		else
3441 			offset = 0x700000;
3442 
3443 		portid = (expander << 5) | portid;
3444 
3445 		(void) sprintf(caddr, "%x,%x", portid, offset);
3446 
3447 		SCHPC_DEBUG3(D_ATTACH,
3448 		    "schpc_register_all_slots: searching for pci@%s"
3449 		    " schizo=%d, leaf=%d", caddr, schizo, leaf);
3450 
3451 		find_dev.cname = "pci";
3452 		find_dev.caddr = caddr;
3453 		find_dev.schizo = schizo;
3454 		find_dev.leaf = leaf;
3455 		find_dev.dip = NULL;
3456 
3457 		/* root node doesn't have to be held */
3458 		ddi_walk_devs(ddi_root_node(), schpc_match_dip,
3459 		    &find_dev);
3460 
3461 		pci_dip = find_dev.dip;
3462 
3463 		if (pci_dip == NULL) {
3464 
3465 			SCHPC_DEBUG1(D_ATTACH,
3466 			    "schpc_register_all_slots: pci@%s NOT FOUND",
3467 			    caddr);
3468 
3469 			continue;
3470 		}
3471 
3472 		SCHPC_DEBUG2(D_ATTACH,
3473 		    "schpc_register_all_slots: pci@%s FOUND dip=0x%p",
3474 		    caddr, (void *)pci_dip);
3475 
3476 		(void) schpc_add_pci(pci_dip);
3477 
3478 		/*
3479 		 * Release hold acquired in schpc_match_dip()
3480 		 */
3481 		ndi_rele_devi(pci_dip);
3482 	}
3483 
3484 	SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit");
3485 
3486 	thread_exit();
3487 }
3488 
3489 /*
3490  * schpc_add_pci
3491  *
3492  * Routine to add attachments points associated with a pci node.
3493  * Can be call externally by DR when configuring a PCI I/O Board.
3494  */
3495 int
3496 schpc_add_pci(dev_info_t *bdip)
3497 {
3498 	int		portid;
3499 	int		expander, board, schizo, leaf, slot, status;
3500 	char		ap_id[MAXNAMELEN];
3501 	char		caddr[64];
3502 	char		*naddr;
3503 	hpc_slot_info_t	slot_info;
3504 	hpc_slot_ops_t	*slot_ops;
3505 	dev_info_t 	*sdip = bdip;
3506 
3507 	SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", (void *)sdip);
3508 
3509 	if (schpc_p == NULL) {
3510 		/*
3511 		 * The schpc driver has not been attached yet.
3512 		 */
3513 		return (DDI_SUCCESS);
3514 	}
3515 
3516 	if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) {
3517 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n",
3518 		    (void *)sdip);
3519 		return (DDI_FAILURE);
3520 	}
3521 
3522 	expander = schpc_getexpander(sdip);
3523 	board = schpc_getboard(sdip);
3524 
3525 	switch (portid & 0x1f) {
3526 
3527 	case 0x1c:
3528 		schizo = 0;
3529 		break;
3530 	case 0x1d:
3531 		schizo = 1;
3532 		break;
3533 	default:
3534 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3535 		    "Invalid pci portid 0x%x\n", (void *)sdip, portid);
3536 		return (DDI_FAILURE);
3537 	}
3538 
3539 	naddr = ddi_get_name_addr(sdip);
3540 	if (naddr == NULL) {
3541 		SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr"
3542 		    "(0x%p) returns null", (void *)sdip);
3543 		return (DDI_FAILURE);
3544 	}
3545 
3546 	(void) sprintf(caddr, "%x,600000", portid);
3547 
3548 	if (strcmp(caddr, naddr) == 0) {
3549 		leaf = 0;
3550 	} else {
3551 		(void) sprintf(caddr, "%x,700000", portid);
3552 		if (strcmp(caddr, naddr) == 0) {
3553 			char *name;
3554 
3555 			leaf = 1;
3556 			name = ddi_binding_name(sdip);
3557 			if ((strcmp(name, "pci108e,8002") == 0) &&
3558 			    (schizo == 0)) {
3559 				int circ;
3560 				dev_info_t *cdip;
3561 				/*
3562 				 * XMITS 0 Leaf B will have its hot
3563 				 * pluggable slot off a PCI-PCI bridge,
3564 				 * which is the only child.
3565 				 */
3566 				ndi_devi_enter(sdip, &circ);
3567 				cdip = ddi_get_child(sdip);
3568 				if (cdip == NULL) {
3569 					cmn_err(CE_WARN,
3570 					    "schpc_add_pci(dip=0x%p) - "
3571 					    "Invalid pci name addr %s\n",
3572 					    (void *)sdip, naddr);
3573 					ndi_devi_exit(sdip, circ);
3574 					return (DDI_FAILURE);
3575 				}
3576 				ndi_devi_exit(sdip, circ);
3577 				sdip = cdip;
3578 			}
3579 		} else {
3580 			cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3581 			    "Invalid pci name addr %s\n", (void *)sdip, naddr);
3582 			return (DDI_FAILURE);
3583 		}
3584 	}
3585 
3586 	/* create a slot table index */
3587 	slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf);
3588 
3589 	if (schpc_p->schpc_slot[slot].devi) {
3590 		cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3591 		    "pci node already registered\n", (void *)sdip);
3592 		return (DDI_FAILURE);
3593 	}
3594 
3595 	/*
3596 	 * There is no need to hold the dip while saving it in
3597 	 * the devi field below. The dip is never dereferenced.
3598 	 * (If that changes, this code should be modified).
3599 	 * We want to avoid holding the dip here because it
3600 	 * prevents DR.
3601 	 *
3602 	 * NOTE: Even though the slot on XMITS0 Leaf-B
3603 	 * is connected to a pci_pci bridge, we will be saving
3604 	 * the busdip in this datastructure. This will make
3605 	 * it easier to identify the dip being removed in
3606 	 * schpc_remove_pci().
3607 	 */
3608 	schpc_p->schpc_slot[slot].devi = bdip;
3609 
3610 	schpc_p->schpc_slot[slot].expander = expander;
3611 	schpc_p->schpc_slot[slot].board = board;
3612 	schpc_p->schpc_slot[slot].schizo = schizo;
3613 	schpc_p->schpc_slot[slot].leaf = leaf;
3614 
3615 	/*
3616 	 * Starcat PCI slots are always PCI device 1.
3617 	 */
3618 	schpc_p->schpc_slot[slot].pci_id = 1;
3619 
3620 	schpc_buildapid(sdip, slot, (char *)&ap_id);
3621 
3622 	(void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id);
3623 
3624 	/* safe to call ddi_pathname(): bdip is held */
3625 	(void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path);
3626 
3627 	status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot));
3628 	switch (status) {
3629 		case RSV_UNKNOWN:
3630 		case RSV_PRESENT:
3631 		case RSV_MISS:
3632 		case RSV_PASS:
3633 		case RSV_EMPTY_CASSETTE:
3634 
3635 			/*
3636 			 * Test the condition of the slot.
3637 			 */
3638 			schpc_test((caddr_t)schpc_p, slot, 0, 0);
3639 			break;
3640 		case RSV_BLACK:
3641 			schpc_p->schpc_slot[slot].state = 0;
3642 			cmn_err(CE_WARN, "schpc: PCI card blacklisted: "
3643 			    "expander=%d board=%d slot=%d\n", expander,
3644 			    board, SCHPC_SLOT_NUM(slot));
3645 			break;
3646 		default:
3647 			schpc_p->schpc_slot[slot].state = 0;
3648 			cmn_err(CE_WARN, "schpc: PCI card failed by POST: "
3649 			    "expander=%d board=%d slot=%d failure=0x%x\n",
3650 			    expander, board, SCHPC_SLOT_NUM(slot), status);
3651 			break;
3652 	}
3653 
3654 	if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) {
3655 
3656 		/* allocate slot ops */
3657 
3658 		slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
3659 		schpc_p->schpc_slot[slot].slot_ops = slot_ops;
3660 
3661 		/*
3662 		 * Default to Autoconfiguration disabled.
3663 		 */
3664 		schpc_p->schpc_slot[slot].state &=
3665 		    ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
3666 
3667 		/*
3668 		 * Fill in the slot information structure that
3669 		 * describes the slot.
3670 		 */
3671 		slot_info.version = HPC_SLOT_OPS_VERSION;
3672 
3673 		if (schpc_p->schpc_hotplugmodel ==
3674 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG)
3675 			slot_info.slot_type = HPC_SLOT_TYPE_PCI;
3676 		else
3677 			slot_info.slot_type = HPC_SLOT_TYPE_CPCI;
3678 
3679 		slot_info.slot.pci.device_number =
3680 		    schpc_p->schpc_slot[slot].pci_id;
3681 
3682 		slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
3683 
3684 		if (schpc_use_legacy_apid)
3685 			slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE;
3686 		else
3687 			slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
3688 			    HPC_SLOT_CREATE_DEVLINK;
3689 
3690 		(void) strcpy(slot_info.slot.pci.slot_logical_name,
3691 		    schpc_p->schpc_slot[slot].ap_id);
3692 
3693 		/*
3694 		 * Fill in the slot ops structure that tells
3695 		 * the Hot Plug Services what function we
3696 		 * support.
3697 		 */
3698 		slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
3699 		if (schpc_p->schpc_hotplugmodel ==
3700 		    SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
3701 			slot_ops->hpc_op_connect = schpc_connect;
3702 			slot_ops->hpc_op_disconnect = schpc_disconnect;
3703 			slot_ops->hpc_op_insert = NULL;
3704 			slot_ops->hpc_op_remove = NULL;
3705 			slot_ops->hpc_op_control = schpc_pci_control;
3706 		} else {
3707 			slot_ops->hpc_op_connect = NULL;
3708 			slot_ops->hpc_op_disconnect = NULL;
3709 			slot_ops->hpc_op_insert = NULL;
3710 			slot_ops->hpc_op_remove = NULL;
3711 			slot_ops->hpc_op_control = schpc_cpci_control;
3712 		}
3713 
3714 		SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC "
3715 		    "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s",
3716 		    schpc_p->schpc_slot[slot].nexus_path,
3717 		    (void *)schpc_p, SCHPC_SLOT_NUM(slot),
3718 		    slot_info.slot.pci.device_number,
3719 		    slot_info.slot.pci.slot_logical_name);
3720 
3721 		if (hpc_slot_register(schpc_p->schpc_devi,
3722 		    schpc_p->schpc_slot[slot].nexus_path, &slot_info,
3723 		    &schpc_p->schpc_slot[slot].slot_handle,
3724 		    slot_ops, (caddr_t)schpc_p, 0) != 0) {
3725 
3726 			/*
3727 			 * If the slot can not be registered,
3728 			 * then the slot_ops need to be freed.
3729 			 */
3730 			cmn_err(CE_WARN, "schpc%d Unable to Register "
3731 			    "Slot %s", schpc_p->schpc_instance,
3732 			    slot_info.slot.pci.slot_logical_name);
3733 
3734 			hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops);
3735 
3736 			schpc_p->schpc_slot[slot].slot_ops = NULL;
3737 
3738 			return (DDI_FAILURE);
3739 		}
3740 
3741 		/*
3742 		 * We are ready to take commands from the HPC Services.
3743 		 */
3744 		schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED;
3745 	}
3746 
3747 	return (DDI_SUCCESS);
3748 }
3749 
3750 /*
3751  * schpc_remove_pci
3752  *
3753  * Routine to remove attachments points associated with a pci node.
3754  * Can be call externally by DR when unconfiguring a PCI I/O Board.
3755  */
3756 int
3757 schpc_remove_pci(dev_info_t *dip)
3758 {
3759 	int slot;
3760 
3761 	SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", (void *)dip);
3762 
3763 	if (schpc_p == NULL) {
3764 		/*
3765 		 * The schpc driver has not been attached yet.
3766 		 */
3767 		return (DDI_SUCCESS);
3768 	}
3769 
3770 	for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) {
3771 		if (schpc_p->schpc_slot[slot].devi == dip) {
3772 
3773 			if (schpc_p->schpc_slot[slot].slot_ops) {
3774 				if (hpc_slot_unregister(
3775 				    &schpc_p->schpc_slot[slot].slot_handle)) {
3776 					cmn_err(CE_WARN,
3777 					    "schpc_remove_pci(dip=0x%p) - "
3778 					    "unable to unregister pci slots\n",
3779 					    (void *)dip);
3780 					return (DDI_FAILURE);
3781 				} else {
3782 					hpc_free_slot_ops(
3783 					    schpc_p->schpc_slot[slot].slot_ops);
3784 
3785 					schpc_p->schpc_slot[slot].slot_ops =
3786 					    NULL;
3787 
3788 					schpc_p->schpc_slot[slot].devi = NULL;
3789 
3790 					return (DDI_SUCCESS);
3791 				}
3792 			} else {
3793 				schpc_p->schpc_slot[slot].devi = NULL;
3794 
3795 				return (DDI_SUCCESS);
3796 			}
3797 		}
3798 	}
3799 
3800 	cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) "
3801 	    "dip not found\n", (void *)dip);
3802 
3803 	return (DDI_SUCCESS);
3804 }
3805 
3806 /*
3807  * schpc_match_dip
3808  *
3809  * Used by ddi_walk_devs to find PCI Nexus nodes associated with
3810  * Hot Plug Controllers.
3811  */
3812 static int
3813 schpc_match_dip(dev_info_t *dip, void *arg)
3814 {
3815 	char		*naddr;
3816 	find_dev_t	*find_dev = (find_dev_t *)arg;
3817 
3818 	if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 &&
3819 	    ((((naddr = ddi_get_name_addr(dip)) != NULL) &&
3820 	    (strcmp(find_dev->caddr, naddr) == 0)) ||
3821 	    ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) {
3822 		/*
3823 		 * While ddi_walk_devs() holds dips when invoking this
3824 		 * callback, this dip is being saved and will be accessible
3825 		 * to the caller outside ddi_walk_devs(). Therefore it must be
3826 		 * held.
3827 		 */
3828 		ndi_hold_devi(dip);
3829 		find_dev->dip = dip;
3830 
3831 		SCHPC_DEBUG2(D_ATTACH,
3832 		    "schpc_match_dip: pci@%s FOUND dip=0x%p",
3833 		    find_dev->caddr, (void *)find_dev->dip);
3834 
3835 		return (DDI_WALK_TERMINATE);
3836 	}
3837 
3838 	ASSERT(find_dev->dip == NULL);
3839 	return (DDI_WALK_CONTINUE);
3840 }
3841 
3842 /*
3843  * schpc_buildapid
3844  *
3845  * Takes a component address and translates it into a ap_id prefix.
3846  */
3847 static void
3848 schpc_buildapid(dev_info_t *dip, int slot, char *ap_id)
3849 {
3850 	int r, pci_id_cnt, pci_id_bit;
3851 	int slots_before, found;
3852 	unsigned char *slot_names_data, *s;
3853 	int slot_names_size;
3854 	int slot_num;
3855 	unsigned int bit_mask;
3856 
3857 	slot_num = SCHPC_SLOT_NUM(slot);
3858 
3859 	if (schpc_use_legacy_apid) {
3860 		SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot);
3861 
3862 		(void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3863 		    schpc_getboard(dip), slot_num);
3864 
3865 		SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3866 
3867 		return;
3868 	}
3869 
3870 	r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3871 	    "slot-names", (caddr_t)&slot_names_data,
3872 	    &slot_names_size);
3873 
3874 	if (r == DDI_PROP_SUCCESS) {
3875 
3876 		/*
3877 		 * We can try to use the slot-names property to
3878 		 * build our ap-id.
3879 		 */
3880 		bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) |
3881 		    (slot_names_data[1] << 16) | (slot_names_data[0] << 24);
3882 
3883 		pci_id_bit = 1;
3884 		pci_id_cnt = slots_before = found = 0;
3885 
3886 		SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x",
3887 		    slot, bit_mask);
3888 
3889 		/*
3890 		 * Walk the bit mask until we find the bit that corresponds
3891 		 * to our slots device number.  We count how many bits
3892 		 * we find before we find our slot's bit.
3893 		 */
3894 		while (!found && (pci_id_cnt < 32)) {
3895 
3896 			while (schpc_p->schpc_slot[slot].pci_id
3897 			    != pci_id_cnt) {
3898 
3899 				/*
3900 				 * Find the next bit set.
3901 				 */
3902 				while (!(bit_mask & pci_id_bit) &&
3903 				    (pci_id_cnt < 32)) {
3904 					pci_id_bit = pci_id_bit << 1;
3905 					pci_id_cnt++;
3906 				}
3907 
3908 				if (schpc_p->schpc_slot[slot].pci_id !=
3909 				    pci_id_cnt)
3910 					slots_before++;
3911 				else
3912 					found = 1;
3913 			}
3914 		}
3915 
3916 		if (pci_id_cnt < 32) {
3917 
3918 			/*
3919 			 * Set ptr to first string.
3920 			 */
3921 			s = slot_names_data + 4;
3922 
3923 			/*
3924 			 * Increment past all the strings for the slots
3925 			 * before ours.
3926 			 */
3927 			while (slots_before) {
3928 				while (*s != NULL)
3929 					s++;
3930 				s++;
3931 				slots_before--;
3932 			}
3933 
3934 			/*
3935 			 * We should be at our string.
3936 			 */
3937 
3938 			(void) sprintf(ap_id, "IO%d_%s",
3939 			    schpc_getexpander(dip), s);
3940 
3941 			SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s",
3942 			    slot, ap_id);
3943 
3944 			kmem_free(slot_names_data, slot_names_size);
3945 			return;
3946 		}
3947 
3948 		SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found",
3949 		    slot);
3950 
3951 		kmem_free(slot_names_data, slot_names_size);
3952 	} else
3953 		SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found",
3954 		    slot);
3955 
3956 	/*
3957 	 * Build the ap-id using the legacy naming scheme.
3958 	 */
3959 	(void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3960 	    schpc_getboard(dip), slot_num);
3961 
3962 	SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3963 }
3964 
3965 /*
3966  * schpc_getexpander
3967  *
3968  * Returns the Expander Number (0-17) for the dip passed in. The Expander
3969  * Number is extracted from the portid property of the pci node. Portid
3970  * consists of <Expbrd#><1110x>, where x is the schizo number.
3971  */
3972 static int
3973 schpc_getexpander(dev_info_t *dip)
3974 {
3975 	int	id;
3976 
3977 	id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1);
3978 
3979 	if (id != -1)
3980 		return (id >> 5);
3981 	else {
3982 		id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1);
3983 		return (id);
3984 	}
3985 }
3986 
3987 /*
3988  * schpc_getboard
3989  *
3990  * Returns the board number (0 or 1) for the dip passed in.
3991  */
3992 static int
3993 schpc_getboard(dev_info_t *dip)
3994 {
3995 	_NOTE(ARGUNUSED(dip))
3996 
3997 	/*
3998 	 * Hot Pluggable PCI/cPCI slots are only available on
3999 	 * Board 1 (half-bandwidth slot).
4000 	 */
4001 	return (1);
4002 }
4003 
4004 /*ARGSUSED*/
4005 static int
4006 schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot)
4007 {
4008 	gdcd_t *gdcd;
4009 	int prd_slot, status, bus;
4010 
4011 	SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4012 	    "exp=%d board=%d slot=%d", expander, board, slot);
4013 
4014 	if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t),
4015 	    KM_SLEEP)) == NULL) {
4016 		return (RSV_UNDEFINED);
4017 	}
4018 
4019 	/*
4020 	 * Get the Starcat Specific Global DCD Structure from the golden
4021 	 * IOSRAM.
4022 	 */
4023 	if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
4024 		cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
4025 		    "From IOSRAM\n");
4026 		kmem_free(gdcd, sizeof (gdcd_t));
4027 		return (RSV_UNDEFINED);
4028 	}
4029 
4030 	if (gdcd->h.dcd_magic != GDCD_MAGIC) {
4031 
4032 		cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n",
4033 		    gdcd->h.dcd_magic);
4034 
4035 		kmem_free(gdcd, sizeof (gdcd_t));
4036 		return (RSV_UNDEFINED);
4037 	}
4038 
4039 	if (gdcd->h.dcd_version != DCD_VERSION) {
4040 		cmn_err(CE_WARN, "schpc: GDCD Bad Version: "
4041 		    "GDCD Version 0x%x Expecting 0x%x\n",
4042 		    gdcd->h.dcd_version, DCD_VERSION);
4043 
4044 		kmem_free(gdcd, sizeof (gdcd_t));
4045 		return (RSV_UNDEFINED);
4046 	}
4047 
4048 	if (slot < 2)
4049 		prd_slot = 4;
4050 	else
4051 		prd_slot = 5;
4052 
4053 	bus = slot & 0x1;
4054 
4055 	status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0];
4056 
4057 	kmem_free(gdcd, sizeof (gdcd_t));
4058 
4059 	SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4060 	    "prd_slot=%d bus=%d status=%d", prd_slot, bus, status);
4061 
4062 	return (status);
4063 }
4064 
4065 #define	LEAF_SAVE_END			0xff
4066 
4067 typedef struct {
4068 	int	reg;
4069 	int	offset;
4070 	int	access_size;
4071 	int	number;
4072 } save_reg_list_t;
4073 
4074 /*
4075  * Save List Array.  Describes the leaf registers that need to
4076  * be restored after a leaf reset.
4077  *
4078  * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space
4079  * Entry 2 - Offset Start
4080  * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit
4081  * Entry 4 - # of registers to be saved starting at offset,
4082  */
4083 save_reg_list_t	save_reg_list[] = {	0, 0x110, 8, 1,
4084 					0, 0x200, 8, 2,
4085 					0, 0x1000, 8, 0x18,
4086 					0, 0x1a00, 8, 1,
4087 					0, 0x2000, 8, 1,
4088 					0, 0x2020, 8, 1,
4089 					0, 0x2040, 8, 1,
4090 					0, 0x2308, 8, 2,
4091 					0, 0x2800, 8, 1,
4092 					2, 0x04, 2, 1,		/* Command */
4093 					2, 0x0d, 1, 1,		/* Latency */
4094 					2, 0x40, 1, 1,		/* Bus # */
4095 					2, 0x41, 1, 1,		/* Sub. Bus # */
4096 					LEAF_SAVE_END, 0, 0, 0};
4097 
4098 static int
4099 schpc_save_leaf(int slot)
4100 {
4101 	int		save_entry, list_entry, reg;
4102 	caddr_t		leaf_regs;
4103 	ddi_device_acc_attr_t attr;
4104 
4105 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4106 
4107 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4108 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4109 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4110 
4111 	/*
4112 	 * Map in the 3 addresses spaces defined for XMITS.
4113 	 */
4114 	for (reg = 0; reg < 3; reg++) {
4115 		if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg,
4116 		    &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot].
4117 		    saved_handle[reg]) != DDI_SUCCESS) {
4118 			cmn_err(CE_WARN, "Mapin failed\n");
4119 			schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4120 			return (1);
4121 		}
4122 
4123 		schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs;
4124 	}
4125 
4126 
4127 	/*
4128 	 * Determine how many entries are in the list so we can
4129 	 * allocate the save space.
4130 	 */
4131 	list_entry = 0;
4132 	save_entry = 0;
4133 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4134 		save_entry += save_reg_list[list_entry].number;
4135 		list_entry++;
4136 	}
4137 
4138 	schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t));
4139 
4140 	if (schpc_p->schpc_slot[slot].saved_size == 0)
4141 		return (0);
4142 
4143 	schpc_p->schpc_slot[slot].saved_regs =
4144 	    (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size,
4145 	    KM_SLEEP);
4146 
4147 	/*
4148 	 * Walk through the register list and save contents.
4149 	 */
4150 	list_entry = 0;
4151 	save_entry = 0;
4152 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4153 		schpc_save_entry(slot, list_entry, save_entry);
4154 		save_entry += save_reg_list[list_entry].number;
4155 		list_entry ++;
4156 	}
4157 
4158 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4159 
4160 	return (0);
4161 }
4162 
4163 static void
4164 schpc_restore_leaf(int slot)
4165 {
4166 	int	save_entry, list_entry, reg;
4167 
4168 	if (schpc_p->schpc_slot[slot].saved_regs == NULL)
4169 		return;
4170 
4171 	/*
4172 	 * Walk through the register list and restore contents.
4173 	 */
4174 	list_entry = 0;
4175 	save_entry = 0;
4176 	while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4177 
4178 		schpc_restore_entry(slot, list_entry, save_entry);
4179 
4180 		save_entry += save_reg_list[list_entry].number;
4181 		list_entry ++;
4182 	}
4183 
4184 	/*
4185 	 * Free the mapped in registers.
4186 	 */
4187 	for (reg = 0; reg < 3; reg++) {
4188 		if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) {
4189 
4190 			ddi_regs_map_free(
4191 			    &schpc_p->schpc_slot[slot].saved_handle[reg]);
4192 
4193 			schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4194 		}
4195 	}
4196 
4197 	kmem_free(schpc_p->schpc_slot[slot].saved_regs,
4198 	    schpc_p->schpc_slot[slot].saved_size);
4199 
4200 	schpc_p->schpc_slot[slot].saved_size = 0;
4201 	schpc_p->schpc_slot[slot].saved_regs = NULL;
4202 
4203 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot);
4204 }
4205 
4206 static void
4207 schpc_save_entry(int slot, int list_entry, int save_entry)
4208 {
4209 	int reg, reads = 0;
4210 
4211 	reg = save_reg_list[list_entry].reg;
4212 
4213 	while (reads < save_reg_list[list_entry].number) {
4214 		switch (save_reg_list[list_entry].access_size) {
4215 		case 8:
4216 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4217 			    ddi_get64(
4218 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4219 			    (uint64_t *)(schpc_p->schpc_slot[slot].
4220 			    saved_regs_va[reg]
4221 			    + save_reg_list[list_entry].offset +
4222 			    (reads * sizeof (uint64_t))));
4223 #ifdef DEBUG
4224 			if (schpc_dump_save_regs)
4225 				cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg,
4226 				    save_reg_list[list_entry].offset +
4227 				    (reads * sizeof (uint64_t)),
4228 				    schpc_p->schpc_slot[slot].
4229 				    saved_regs[save_entry]);
4230 #endif
4231 
4232 			break;
4233 		case 4:
4234 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4235 			    ddi_get32(
4236 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4237 			    (uint32_t *)(schpc_p->schpc_slot[slot].
4238 			    saved_regs_va[reg]
4239 			    + save_reg_list[list_entry].offset +
4240 			    (reads * sizeof (uint32_t))));
4241 
4242 #ifdef DEBUG
4243 			if (schpc_dump_save_regs)
4244 				cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg,
4245 				    save_reg_list[list_entry].offset +
4246 				    (reads * sizeof (uint32_t)),
4247 				    schpc_p->schpc_slot[slot].
4248 				    saved_regs[save_entry]);
4249 #endif
4250 
4251 			break;
4252 		case 2:
4253 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4254 			    ddi_get16(
4255 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4256 			    (uint16_t *)(schpc_p->schpc_slot[slot].
4257 			    saved_regs_va[reg]
4258 			    + save_reg_list[list_entry].offset +
4259 			    (reads * sizeof (uint16_t))));
4260 
4261 #ifdef DEBUG
4262 			if (schpc_dump_save_regs)
4263 				cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg,
4264 				    save_reg_list[list_entry].offset +
4265 				    (reads * sizeof (uint16_t)),
4266 				    schpc_p->schpc_slot[slot].
4267 				    saved_regs[save_entry]);
4268 #endif
4269 
4270 			break;
4271 		case 1:
4272 			schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4273 			    ddi_get8(
4274 			    schpc_p->schpc_slot[slot].saved_handle[reg],
4275 			    (uint8_t *)(schpc_p->schpc_slot[slot].
4276 			    saved_regs_va[reg]
4277 			    + save_reg_list[list_entry].offset +
4278 			    (reads * sizeof (uint8_t))));
4279 
4280 #ifdef DEBUG
4281 			if (schpc_dump_save_regs)
4282 				cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg,
4283 				    save_reg_list[list_entry].offset +
4284 				    (reads * sizeof (uint8_t)),
4285 				    schpc_p->schpc_slot[slot].
4286 				    saved_regs[save_entry]);
4287 #endif
4288 
4289 			break;
4290 		default:
4291 			cmn_err(CE_WARN,
4292 			    "schpc: Illegal List Entry\n");
4293 		}
4294 		reads++;
4295 		save_entry++;
4296 	}
4297 }
4298 
4299 static void
4300 schpc_restore_entry(int slot, int list_entry, int save_entry)
4301 {
4302 	int reg, writes = 0;
4303 
4304 	reg = save_reg_list[list_entry].reg;
4305 
4306 	while (writes < save_reg_list[list_entry].number) {
4307 		switch (save_reg_list[list_entry].access_size) {
4308 		case 8:
4309 #ifdef DEBUG
4310 			if (schpc_dump_save_regs)
4311 				cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg,
4312 				    save_reg_list[list_entry].offset +
4313 				    (writes * sizeof (uint64_t)),
4314 				    schpc_p->schpc_slot[slot].
4315 				    saved_regs[save_entry]);
4316 #endif
4317 
4318 			ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg],
4319 			    (uint64_t *)(schpc_p->schpc_slot[slot].
4320 			    saved_regs_va[reg]
4321 			    + save_reg_list[list_entry].offset +
4322 			    (writes * sizeof (uint64_t))),
4323 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4324 
4325 			break;
4326 		case 4:
4327 #ifdef DEBUG
4328 			if (schpc_dump_save_regs)
4329 				cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg,
4330 				    save_reg_list[list_entry].offset +
4331 				    (writes * sizeof (uint32_t)),
4332 				    schpc_p->schpc_slot[slot].
4333 				    saved_regs[save_entry]);
4334 #endif
4335 
4336 			ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg],
4337 			    (uint32_t *)(schpc_p->schpc_slot[slot].
4338 			    saved_regs_va[reg]
4339 			    + save_reg_list[list_entry].offset +
4340 			    (writes * sizeof (uint32_t))),
4341 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4342 
4343 			break;
4344 		case 2:
4345 #ifdef DEBUG
4346 			if (schpc_dump_save_regs)
4347 				cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg,
4348 				    save_reg_list[list_entry].offset +
4349 				    (writes * sizeof (uint16_t)),
4350 				    schpc_p->schpc_slot[slot].
4351 				    saved_regs[save_entry]);
4352 #endif
4353 
4354 			ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg],
4355 			    (uint16_t *)(schpc_p->schpc_slot[slot].
4356 			    saved_regs_va[reg]
4357 			    + save_reg_list[list_entry].offset +
4358 			    (writes * sizeof (uint16_t))),
4359 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4360 
4361 			break;
4362 		case 1:
4363 #ifdef DEBUG
4364 			if (schpc_dump_save_regs)
4365 				cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg,
4366 				    save_reg_list[list_entry].offset +
4367 				    (writes * sizeof (uint8_t)),
4368 				    schpc_p->schpc_slot[slot].
4369 				    saved_regs[save_entry]);
4370 #endif
4371 
4372 			ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg],
4373 			    (uint8_t *)(schpc_p->schpc_slot[slot].
4374 			    saved_regs_va[reg]
4375 			    + save_reg_list[list_entry].offset +
4376 			    (writes * sizeof (uint8_t))),
4377 			    schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4378 
4379 			break;
4380 		default:
4381 			cmn_err(CE_WARN,
4382 			    "schpc: Illegal List Entry\n");
4383 		}
4384 		writes++;
4385 		save_entry++;
4386 	}
4387 }
4388 
4389 /*
4390  * Returns TRUE if a leaf reset is required to change frequencies/mode.
4391  */
4392 static int
4393 schpc_is_leaf_reset_required(int slot)
4394 {
4395 	char *name;
4396 	int32_t mod_rev;
4397 
4398 	/*
4399 	 * Only XMITS 3.0 and greater connected slots will require a
4400 	 * reset to switch frequency and/or mode.
4401 	 */
4402 	name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4403 
4404 	if (strcmp(name, "pci108e,8002") == 0) {
4405 		mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4406 		    schpc_p->schpc_slot[slot].devi,
4407 		    DDI_PROP_DONTPASS, "module-revision#", 0);
4408 
4409 		SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4410 
4411 		/*
4412 		 * Check for XMITS 3.0 or greater.
4413 		 */
4414 		if (mod_rev >= XMITS_30) {
4415 
4416 			/*
4417 			 * The leaf attached to C5V0 (slot 1) should
4418 			 * not be reset.
4419 			 */
4420 			if ((slot & 3) == 1) {
4421 
4422 				SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4423 				    "Not Required - C5V0", slot);
4424 
4425 				return (0);
4426 			}
4427 
4428 			SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4429 			    "Required", slot);
4430 
4431 			return (1);
4432 		}
4433 	}
4434 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot);
4435 
4436 	return (0);
4437 }
4438 
4439 /*
4440  * Returns TRUE if the bus can change frequencies.
4441  */
4442 static int
4443 schpc_is_freq_switchable(int slot)
4444 {
4445 	char *name;
4446 	int32_t mod_rev;
4447 
4448 	name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4449 
4450 	if (strcmp(name, "pci108e,8002") == 0) {
4451 		mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4452 		    schpc_p->schpc_slot[slot].devi,
4453 		    DDI_PROP_DONTPASS, "module-revision#", 0);
4454 
4455 		SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4456 
4457 		/*
4458 		 * We will only report back that XMITS 2.0 (mod_rev = 2)
4459 		 * or greater will have the ability to switch frequencies.
4460 		 */
4461 		if (mod_rev >= XMITS_20) {
4462 			SCHPC_DEBUG1(D_FREQCHG, "Slot %d - "
4463 			    "Frequency is switchable", slot);
4464 			return (1);
4465 		}
4466 	}
4467 
4468 	SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot);
4469 	return (0);
4470 }
4471 
4472 /*
4473  * schpc_slot_freq
4474  *
4475  * Convert the slot frequency setting to integer value.
4476  */
4477 static int
4478 schpc_slot_freq(pci_getslot_t *getslotp)
4479 {
4480 	switch (getslotp->slot_freq_setting) {
4481 	case PCIMSG_FREQ_33MHZ:
4482 		return (SCHPC_33MHZ);
4483 	case PCIMSG_FREQ_66MHZ:
4484 		return (SCHPC_66MHZ);
4485 	case PCIMSG_FREQ_90MHZ:
4486 		return (SCHPC_90MHZ);
4487 	case PCIMSG_FREQ_133MHZ:
4488 		return (SCHPC_133MHZ);
4489 	default:
4490 		return (0);
4491 	}
4492 }
4493 
4494 /*
4495  * schpc_find_dip
4496  *
4497  * Used by ddi_walk_devs to find the dip which belongs
4498  * to a certain slot.
4499  *
4500  * When this function returns, the dip is held.  It is the
4501  * responsibility of the caller to release the dip.
4502  */
4503 static int
4504 schpc_find_dip(dev_info_t *dip, void *arg)
4505 {
4506 	find_dev_t	*find_dev = (find_dev_t *)arg;
4507 	char		*pathname = find_dev->caddr;
4508 
4509 	(void) ddi_pathname(dip, pathname);
4510 	if (strcmp(find_dev->cname, pathname) == 0) {
4511 		ndi_hold_devi(dip);
4512 		find_dev->dip = dip;
4513 		return (DDI_WALK_TERMINATE);
4514 	}
4515 	return (DDI_WALK_CONTINUE);
4516 }
4517