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