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