xref: /titanic_51/usr/src/uts/sun4u/serengeti/io/sghsc.c (revision bb1fad37c75defa7a6ae25f00c1d4b356713b734)
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  *
30  *	Serengeti CompactPCI Hot Swap Controller Driver.
31  *
32  */
33 
34 #include <sys/types.h>
35 #include <sys/cmn_err.h>
36 #include <sys/kmem.h>
37 #include <sys/errno.h>
38 #include <sys/cpuvar.h>
39 #include <sys/open.h>
40 #include <sys/stat.h>
41 #include <sys/conf.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <sys/modctl.h>
45 #include <sys/ksynch.h>
46 #include <sys/pci.h>
47 #include <sys/serengeti.h>
48 #include <sys/sghsc.h>
49 #include <sys/promif.h>
50 
51 /*
52  * Debug flags
53  */
54 
55 int	sghsc_configure_ack = 0;
56 int	cpci_enable = 1;
57 #ifdef	DEBUG
58 #define	SGHSC_DEBUG
59 #endif
60 
61 #ifdef	SGHSC_DEBUG
62 int	sghsc_debug = 0;
63 #define	DEBUGF(level, args) \
64 	{ if (sghsc_debug >= (level)) cmn_err args; }
65 #define	DEBUGON  sghsc_debug = 3
66 #define	DEBUGOFF sghsc_debug = 0
67 #else
68 #define	DEBUGF(level, args)	/* nothing */
69 #define	DEBUGON
70 #define	DEBUGOFF
71 #endif
72 
73 /*
74  * Global data
75  */
76 static void *sghsc_state;		/* soft state */
77 static sghsc_rb_head_t sghsc_rb_header;	/* ring buffer header */
78 
79 /*
80  * Definitions for events thread (outside interrupt context), mutex and
81  * condition variable.
82  */
83 static kthread_t *sghsc_event_thread;
84 static kmutex_t sghsc_event_thread_mutex;
85 static kcondvar_t sghsc_event_thread_cv;
86 static boolean_t sghsc_event_thread_exit = B_FALSE;
87 
88 static struct cb_ops sghsc_cb_ops = {
89 	nodev,			/* open */
90 	nodev,			/* close */
91 	nodev,			/* strategy */
92 	nodev,			/* print */
93 	nodev,			/* dump */
94 	nodev,			/* read */
95 	nodev,			/* write */
96 	nodev,			/* ioctl */
97 	nodev,			/* devmap */
98 	nodev,			/* mmap */
99 	nodev,			/* segmap */
100 	nochpoll,		/* poll */
101 	ddi_prop_op,		/* prop_op */
102 	0,			/* streamtab  */
103 	D_NEW | D_MP,		/* Driver compatibility flag */
104 	CB_REV,			/* rev */
105 	nodev,			/* int (*cb_aread)() */
106 	nodev			/* int (*cb_awrite)() */
107 };
108 
109 /*
110  * Function prototype for dev_ops
111  */
112 
113 static int sghsc_attach(dev_info_t *, ddi_attach_cmd_t);
114 static int sghsc_detach(dev_info_t *, ddi_detach_cmd_t);
115 
116 static struct dev_ops sghsc_dev_ops = {
117 	DEVO_REV,		/* devo_rev, */
118 	0,			/* refcnt  */
119 	nulldev,		/* get_dev_info */
120 	nulldev,		/* identify */
121 	nulldev,		/* probe */
122 	sghsc_attach,		/* attach */
123 	sghsc_detach,		/* detach */
124 	nodev,			/* reset */
125 	&sghsc_cb_ops,		/* driver operations */
126 	(struct bus_ops *)0,	/* no bus operations */
127 	NULL,			/* power */
128 	ddi_quiesce_not_needed,		/* quiesce */
129 };
130 
131 static struct modldrv modldrv = {
132 	&mod_driverops,
133 	"Serengeti CompactPCI HSC",
134 	&sghsc_dev_ops,
135 };
136 
137 static struct modlinkage modlinkage = {
138 	MODREV_1,
139 	&modldrv,
140 	NULL
141 };
142 
143 /*
144  * Function prototype for HP support
145  */
146 static int sghsc_connect(caddr_t, hpc_slot_t slot, void *, uint_t);
147 static int sghsc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
148 static int sghsc_control(caddr_t, hpc_slot_t, int, caddr_t);
149 
150 /*
151  * Function prototypes for internal functions
152  */
153 static int sghsc_register_slots(sghsc_t *, int);
154 static int sghsc_get_slotnum(sghsc_t *, hpc_slot_t);
155 static int sghsc_scctl(int, int, int, int, int *);
156 static void sghsc_freemem(sghsc_t *);
157 static hpc_slot_t sghsc_find_sloth(int, int, int);
158 static sghsc_t *sghsc_find_softstate(int, int, int);
159 static int sghsc_led_state(sghsc_t *, hpc_slot_t, int, hpc_led_info_t *);
160 static void sghsc_rb_setup(sghsc_rb_head_t *);
161 static void sghsc_rb_teardown(sghsc_rb_head_t *);
162 static int sghsc_rb_get(sghsc_rb_head_t *, sghsc_event_t *);
163 static int sghsc_rb_put(sghsc_rb_head_t *, sghsc_event_t *);
164 
165 /*
166  * Patchable timeout value
167  */
168 int sghsc_mbx_timeout = SGHSC_MBX_TIMEOUT;
169 
170 /*
171  * Data for self-identification. This will help enumerate all soft states.
172  */
173 static int sghsc_maxinst;
174 
175 /*
176  * Six slot boat and four slot boats are different in topology (slot to
177  * bus assignment) and here we should have 2 separate maps (the first 3
178  * slots have the same topology). The map is in the "delta" form. Logical
179  * slots correspond to indexes in the map.
180  */
181 static sdesc_t four_slot_wib_bd[] = {
182 	0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
183 	1, 0, 2, 0,		/* logical/physical slot 1 - paroli2 */
184 	1, 0, 0, 0,		/* logical/physical slot 2 - paroli0 */
185 	0, 7, 1, HPC_SLOT_TYPE_CPCI  /* logical/physical slot 3 - Schizo0/B */
186 };
187 static sdesc_t four_slot_bd[] = {
188 	0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
189 	1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */
190 	0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */
191 	1, 7, 1, HPC_SLOT_TYPE_CPCI  /* logical/physical slot 3 - Schizo1/B */
192 };
193 static sdesc_t six_slot_wib_bd[] = {
194 	0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
195 	1, 0, 2, 0,		/* logical/physical slot 1 - paroli2 */
196 	1, 0, 0, 0,		/* logical/physical slot 2 - paroli0 */
197 	0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */
198 	0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo0/B */
199 	0, 7, 3, HPC_SLOT_TYPE_CPCI  /* logical/physical slot 5 - Schizo0/B */
200 };
201 static sdesc_t six_slot_bd[] = {
202 	0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
203 	1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */
204 	0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */
205 	0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */
206 	1, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo1/B */
207 	1, 7, 2, HPC_SLOT_TYPE_CPCI  /* logical/physical slot 5 - Schizo1/B */
208 };
209 
210 /*
211  * DR event handlers
212  * We want to register the event handlers once for all instances. In the
213  * other hand we have register them after the sghsc has been attached.
214  * event_initialize gives us the logic of only registering the events only
215  * once. The event thread will do all the work when called from interrupts.
216  */
217 int sghsc_event_init = 0;
218 static uint_t sghsc_event_handler(char *);
219 static void sghsc_event_thread_code(void);
220 
221 /*
222  * DR event msg and payload
223  */
224 static sbbc_msg_t event_msg;
225 static sghsc_event_t payload;
226 
227 /*
228  * Event lock and state
229  */
230 static kmutex_t sghsc_event_lock;
231 int sghsc_event_state;
232 
233 int
234 _init(void)
235 {
236 	int error;
237 
238 	sghsc_maxinst = 0;
239 
240 	if ((error = ddi_soft_state_init(&sghsc_state,
241 	    sizeof (sghsc_t), 1)) != 0)
242 		return (error);
243 
244 	if ((error = mod_install(&modlinkage)) != 0) {
245 		ddi_soft_state_fini(&sghsc_state);
246 		return (error);
247 	}
248 
249 	sghsc_rb_header.buf = NULL;
250 
251 	mutex_init(&sghsc_event_thread_mutex, NULL, MUTEX_DRIVER, NULL);
252 	cv_init(&sghsc_event_thread_cv, NULL, CV_DRIVER, NULL);
253 
254 	return (error);
255 }
256 
257 int
258 _fini(void)
259 {
260 	int error;
261 
262 	if ((error = mod_remove(&modlinkage)) != 0)
263 		return (error);
264 	/*
265 	 * Unregister the event handler
266 	 */
267 	(void) sbbc_mbox_unreg_intr(MBOX_EVENT_CPCI_ENUM, sghsc_event_handler);
268 	mutex_destroy(&sghsc_event_lock);
269 
270 	/*
271 	 * Kill the event thread if it is running.
272 	 */
273 	if (sghsc_event_thread != NULL) {
274 		mutex_enter(&sghsc_event_thread_mutex);
275 		sghsc_event_thread_exit = B_TRUE;
276 		/*
277 		 * Goes to the thread at once.
278 		 */
279 		cv_signal(&sghsc_event_thread_cv);
280 		/*
281 		 * Waiting for the response from the thread.
282 		 */
283 		cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
284 		mutex_exit(&sghsc_event_thread_mutex);
285 		sghsc_event_thread = NULL;
286 	}
287 	mutex_destroy(&sghsc_event_thread_mutex);
288 	cv_destroy(&sghsc_event_thread_cv);
289 
290 	/*
291 	 * tear down shared, global ring buffer now that it is safe to
292 	 * do so because sghsc_event_handler has been unregistered and
293 	 * sghsc_event_thread_code has exited
294 	 */
295 	sghsc_rb_teardown(&sghsc_rb_header);
296 
297 	sghsc_maxinst = 0;
298 	ddi_soft_state_fini(&sghsc_state);
299 
300 	return (0);
301 }
302 
303 int
304 _info(struct modinfo *modinfop)
305 {
306 	return (mod_info(&modlinkage, modinfop));
307 }
308 
309 /*
310  * sghsc_attach()
311  */
312 /* ARGSUSED */
313 static int
314 sghsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
315 {
316 	sghsc_t *sghsc;
317 	uint_t instance;
318 	uint_t portid;
319 	int rc;
320 	int board_type = 0;
321 
322 	instance = ddi_get_instance(dip);
323 
324 	switch (cmd) {
325 		case DDI_RESUME:
326 			return (DDI_SUCCESS);
327 
328 		case DDI_ATTACH:
329 			break;
330 		default:
331 			cmn_err(CE_WARN, "sghsc%d: unsupported cmd %d",
332 			    instance, cmd);
333 			return (DDI_FAILURE);
334 	}
335 
336 	DEBUGF(1, (CE_NOTE, "attach sghsc driver. "));
337 
338 	/* Fetch Safari Extended Agent ID of this device. */
339 	portid = (uint_t)ddi_getprop(DDI_DEV_T_ANY, dip,
340 	    DDI_PROP_DONTPASS, "portid", -1);
341 
342 	if (!SG_PORTID_IS_IO_TYPE(portid)) {
343 		cmn_err(CE_WARN, "sghsc%d: property %s out of bounds %d\n",
344 		    instance, "portid", portid);
345 		return (DDI_FAILURE);
346 	}
347 
348 	if (ddi_soft_state_zalloc(sghsc_state, instance) != DDI_SUCCESS)
349 		return (DDI_FAILURE);
350 
351 	sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
352 
353 	sghsc->sghsc_dip = dip;
354 	sghsc->sghsc_instance = instance;
355 	sghsc->sghsc_board = SG_PORTID_TO_BOARD_NUM(portid);
356 	sghsc->sghsc_node_id = SG_PORTID_TO_NODEID(portid);
357 	sghsc->sghsc_portid = portid;
358 
359 	ddi_set_driver_private(dip, sghsc);
360 
361 	mutex_init(SGHSC_MUTEX(sghsc), NULL, MUTEX_DRIVER, NULL);
362 
363 	rc = sghsc_scctl(SGHSC_GET_NUM_SLOTS, sghsc->sghsc_node_id,
364 	    sghsc->sghsc_board, 0, (int *)&sghsc->sghsc_num_slots);
365 
366 	if (rc) {
367 		cmn_err(CE_WARN, "sghsc%d: unable to size node %d / board %d",
368 		    instance, sghsc->sghsc_node_id, sghsc->sghsc_board);
369 		goto cleanup_stage2;
370 	}
371 
372 	DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d  has %d slots",
373 	    instance, sghsc->sghsc_node_id, sghsc->sghsc_board,
374 	    sghsc->sghsc_num_slots));
375 
376 	switch (sghsc->sghsc_num_slots) {
377 		case 4:
378 		case 6:
379 			rc = 0;
380 			break;
381 		default:
382 			rc = -1;
383 			break;
384 	}
385 
386 	if (rc) {
387 		cmn_err(CE_WARN, "sghsc%d: wrong num of slots %d for node %d"
388 		    " / board %d", instance, sghsc->sghsc_num_slots,
389 		    sghsc->sghsc_node_id, sghsc->sghsc_board);
390 		goto cleanup_stage2;
391 	}
392 
393 	rc = sghsc_scctl(SGHSC_GET_CPCI_BOARD_TYPE, sghsc->sghsc_node_id,
394 	    sghsc->sghsc_board, 0, &board_type);
395 
396 	DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d is type %d",
397 	    instance, sghsc->sghsc_node_id, sghsc->sghsc_board, board_type));
398 
399 	sghsc->sghsc_slot_table = (sghsc_slot_t *)kmem_zalloc((size_t)
400 	    (sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)), KM_SLEEP);
401 
402 
403 	if (sghsc_register_slots(sghsc, board_type) != DDI_SUCCESS) {
404 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_register_slots"
405 		    " failed for node %d / board %d",
406 		    instance, sghsc->sghsc_node_id, sghsc->sghsc_board));
407 		goto cleanup;
408 	}
409 
410 	if (sghsc_connect((caddr_t)sghsc, 0, 0, SGHSC_ALL_SLOTS_ENABLE)
411 	    != HPC_SUCCESS) {
412 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_connect failed for"
413 		    " node %d / board %d", instance, sghsc->sghsc_node_id,
414 		    sghsc->sghsc_board));
415 		goto cleanup;
416 	}
417 
418 
419 	if (sghsc_event_init == 0) {
420 
421 		/*
422 		 * allocate shared, global ring buffer before registering
423 		 * sghsc_event_handler and before starting
424 		 * sghsc_event_thread_code
425 		 */
426 		sghsc_rb_setup(&sghsc_rb_header);
427 
428 		/*
429 		 * Regiter cpci DR event handler
430 		 *
431 		 */
432 		mutex_init(&sghsc_event_lock,  NULL, MUTEX_DRIVER, NULL);
433 		event_msg.msg_buf = (caddr_t)&payload;
434 		event_msg.msg_len = sizeof (payload);
435 		rc = sbbc_mbox_reg_intr(MBOX_EVENT_CPCI_ENUM,
436 		    sghsc_event_handler, &event_msg,
437 		    (uint_t *)&sghsc_event_state, &sghsc_event_lock);
438 
439 		if (rc != 0)
440 			cmn_err(CE_WARN, "sghsc%d: failed to register events"
441 			    " for node %d", instance, sghsc->sghsc_node_id);
442 
443 		sghsc_event_init = 1;
444 
445 		/*
446 		 * Create the event thread if it is not already created.
447 		 */
448 		if (sghsc_event_thread == NULL) {
449 			DEBUGF(1, (CE_NOTE, "sghsc: creating event thread"
450 			    "for node %d", sghsc->sghsc_node_id));
451 			sghsc_event_thread = thread_create(NULL, 0,
452 			    sghsc_event_thread_code, NULL, 0, &p0,
453 			    TS_RUN, minclsyspri);
454 		}
455 	}
456 
457 	ddi_report_dev(dip);
458 
459 	/*
460 	 * Grossly bump up the instance counter. We may have holes inside.
461 	 */
462 	sghsc_maxinst++;
463 	sghsc->sghsc_valid = 1;
464 
465 	return (DDI_SUCCESS);
466 
467 cleanup:
468 	/*
469 	 * Free up allocated resources and return error
470 	 * sghsc_register_slots => unregister all slots
471 	 */
472 	sghsc_freemem(sghsc);
473 
474 cleanup_stage2:
475 	DEBUGF(1, (CE_NOTE, "sghsc%d: attach failed for node %d",
476 	    instance, sghsc->sghsc_node_id));
477 	mutex_destroy(SGHSC_MUTEX(sghsc));
478 	ddi_set_driver_private(dip, NULL);
479 	ddi_soft_state_free(sghsc_state, instance);
480 	return (DDI_FAILURE);
481 }
482 
483 /*
484  * detach(9E)
485  */
486 /* ARGSUSED */
487 static int
488 sghsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
489 {
490 	sghsc_t *sghsc;
491 	int instance;
492 	int i;
493 
494 	instance = ddi_get_instance(dip);
495 	sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
496 
497 	if (sghsc == NULL)
498 		return (DDI_FAILURE);
499 
500 	switch (cmd) {
501 		case DDI_DETACH:
502 		/*
503 		 * We don't allow to detach in case the pci nexus
504 		 * didn't run pcihp_uninit(). The buses should be
505 		 * unregistered by now, otherwise slot info will be
506 		 * corrupted on the next 'cfgadm'.
507 		 */
508 		for (i = 0; i < sghsc->sghsc_num_slots; i++) {
509 			if (sghsc->sghsc_slot_table[i].handle &&
510 			    hpc_bus_registered(
511 			    sghsc->sghsc_slot_table[i].handle)) {
512 				cmn_err(CE_WARN,
513 				    "sghsc: must detach buses first");
514 				return (DDI_FAILURE);
515 			}
516 		}
517 
518 		if (mutex_tryenter(&sghsc_event_thread_mutex) == 0)
519 			return (EBUSY);
520 
521 		sghsc->sghsc_valid = 0;
522 		sghsc_freemem(sghsc);
523 		mutex_destroy(SGHSC_MUTEX(sghsc));
524 		ddi_set_driver_private(dip, NULL);
525 		ddi_soft_state_free(sghsc_state, instance);
526 
527 		/*
528 		 * Grossly decrement the counter. We may have holes inside.
529 		 */
530 		if (instance == (sghsc_maxinst - 1))
531 			sghsc_maxinst--;
532 		mutex_exit(&sghsc_event_thread_mutex);
533 		return (DDI_SUCCESS);
534 
535 		case DDI_SUSPEND:
536 		return (DDI_SUCCESS);
537 
538 		default:
539 		return (DDI_FAILURE);
540 	}
541 }
542 
543 
544 /*
545  * Set up and register slot 0 to num_slots with hotplug
546  *     framework
547  * 	Assume SGHSC_MUTEX is held
548  *
549  * Return val: DDI_SUCCESS
550  *	       DDI_FAILURE
551  */
552 static int
553 sghsc_register_slots(sghsc_t *sghsc, int board_type)
554 {
555 	int  i;
556 	dev_info_t	*dip = sghsc->sghsc_dip;
557 	hpc_slot_ops_t	*slot_ops = NULL;
558 	sdesc_t 	*slot2bus;
559 
560 
561 	DEBUGF(1, (CE_NOTE, "sghsc%d: slot table has %d entries for "
562 	    "node %d / board %d", sghsc->sghsc_instance, sghsc->sghsc_num_slots,
563 	    sghsc->sghsc_node_id, sghsc->sghsc_board));
564 
565 	if ((cpci_enable == 0) || (sg_prom_cpci_dr_check() != 0))
566 		return (DDI_SUCCESS);
567 
568 	if (sghsc->sghsc_slot_table == NULL)
569 		return (DDI_FAILURE);
570 
571 	switch (board_type) {
572 		/*
573 		 * If the GET_CPCI_BOARD_TYPE request failed, board type
574 		 * will be NO_BOARD_TYPE.  In that case, assume it is an
575 		 * io boat and make board type determination based on the
576 		 * number of slots.
577 		 */
578 		case NO_BOARD_TYPE:
579 		case CPCI_BOARD:
580 		case SP_CPCI_BOARD:
581 			switch (sghsc->sghsc_num_slots) {
582 			case 4:
583 				slot2bus = four_slot_bd;
584 				break;
585 			case 6:
586 				slot2bus = six_slot_bd;
587 				break;
588 			default:
589 				cmn_err(CE_WARN, "sghsc%d: unknown size %d for"
590 				    " node %d / board %d",
591 				    sghsc->sghsc_instance,
592 				    sghsc->sghsc_num_slots,
593 				    sghsc->sghsc_node_id, sghsc->sghsc_board);
594 				break;
595 			}
596 			break;
597 		case WCI_CPCI_BOARD:
598 			slot2bus = four_slot_wib_bd;
599 			break;
600 		case WCI_SP_CPCI_BOARD:
601 			slot2bus = six_slot_wib_bd;
602 			break;
603 		default:
604 			cmn_err(CE_WARN, "sghsc%d: unknown type %d  for"
605 			    " node %d / board %d", sghsc->sghsc_instance,
606 			    board_type, sghsc->sghsc_node_id,
607 			    sghsc->sghsc_board);
608 			return (DDI_FAILURE);
609 	}
610 
611 	/*
612 	 * constructing the slot table array and register the
613 	 * slot with the HPS
614 	 * we don't depend on the .conf file
615 	 */
616 	for (i = 0; i < sghsc->sghsc_num_slots; i++) {
617 		char	*nexuspath;
618 		hpc_slot_info_t  *slot_info;
619 		uint32_t base_id;
620 
621 		/*
622 		 * Some kind of black list may be needed
623 		 */
624 
625 		/*
626 		 * Need to talk to SC and get slot info and set slot state:
627 		 * 1. slot status
628 		 * 2. slot capabilities
629 		 * 3. LED status
630 		 * 4. get bus num
631 		 */
632 
633 		/*
634 		 * fill up nexuspath, extended id is used instead of the
635 		 * local one, the node id is encoded in the path twice.
636 		 */
637 		base_id = sghsc->sghsc_portid & SGHSC_SAFARI_ID_EVEN;
638 		nexuspath = sghsc->sghsc_slot_table[i].nexus_path;
639 
640 		(void) sprintf(nexuspath, SGHSC_PATH, sghsc->sghsc_node_id,
641 		    (base_id + slot2bus[i].agent_delta), slot2bus[i].off);
642 		sghsc->sghsc_slot_table[i].pci_device_num =
643 		    slot2bus[i].pcidev;
644 
645 		/*
646 		 * fill up slot_info
647 		 */
648 		slot_info = &sghsc->sghsc_slot_table[i].slot_info;
649 
650 		slot_info->version = HPC_SLOT_INFO_VERSION;
651 		slot_info->slot_type = slot2bus[i].slot_type;
652 		/* capabilities need to be discovered via SC */
653 		slot_info->pci_slot_capabilities = HPC_SLOT_64BITS;
654 		slot_info->pci_dev_num = slot2bus[i].pcidev;
655 
656 		(void) sprintf(slot_info->pci_slot_name,
657 		    "sg%dslot%d", sghsc->sghsc_board, i);
658 		DEBUGF(1, (CE_NOTE, "pci_slot_name is %s at pci_dev_num %d"
659 		    " on node %d / board %d", slot_info->pci_slot_name,
660 		    slot_info->pci_dev_num, sghsc->sghsc_node_id,
661 		    sghsc->sghsc_board));
662 
663 		/*
664 		 * allocate and fill up slot_ops
665 		 */
666 		slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
667 		sghsc->sghsc_slot_table[i].slot_ops = slot_ops;
668 
669 		/* assign slot ops for HPS */
670 		slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
671 		slot_ops->hpc_op_connect = sghsc_connect;
672 		slot_ops->hpc_op_disconnect = sghsc_disconnect;
673 		slot_ops->hpc_op_insert = nodev;
674 		slot_ops->hpc_op_remove = nodev;
675 		slot_ops->hpc_op_control = sghsc_control;
676 
677 		/*
678 		 * HA (Full Hot Swap) is the default mode of operation
679 		 * but the type of the board is set conservstively as
680 		 * sghsc has no way of knowing it. The HP Framwork will
681 		 * overwrite the value set at boot time.
682 		 */
683 		sghsc->sghsc_slot_table[i].flags = SGHSC_SLOT_AUTO_CFG_EN;
684 		sghsc->sghsc_slot_table[i].board_type = HPC_BOARD_UNKNOWN;
685 
686 		/* Only register CPCI slots */
687 		if (slot_info->slot_type != HPC_SLOT_TYPE_CPCI) {
688 			DEBUGF(1, (CE_NOTE, "sghsc_register_slots: "
689 			    "slot %d is non-cpci", i));
690 			continue;
691 		}
692 
693 		/*
694 		 *  register slots
695 		 */
696 		if ((hpc_slot_register(dip, nexuspath, slot_info,
697 		    &sghsc->sghsc_slot_table[i].handle,
698 		    slot_ops, (caddr_t)sghsc, 0)) != 0) {
699 
700 			/*
701 			 * return failure and let attach()
702 			 * do the cleanup
703 			 */
704 			cmn_err(CE_WARN, "sghsc%d: Slot <%s> failed during HPS"
705 			    " registration process for node %d / board %d",
706 			    sghsc->sghsc_instance, slot_info->pci_slot_name,
707 			    sghsc->sghsc_node_id, sghsc->sghsc_board);
708 			return (DDI_FAILURE);
709 		}
710 
711 	}
712 	DEBUGF(1, (CE_NOTE, "sghsc registered successfully for"
713 	    " node %d / board %d", sghsc->sghsc_node_id, sghsc->sghsc_board));
714 	return (DDI_SUCCESS);
715 }
716 
717 /*
718  * Connecting a slot or all slots
719  *	State Diagram:
720  *	     states
721  *	hw bits		EMPTY	DISCONNECT	CONNECT
722  *	slot_enable	 NO	   NO		  YES
723  *	card_present	 NO	   YES		  YES
724  *	slot_switch	 N/A	   NO/YES	  YES
725  *
726  * Return val:	HPC_SUCCESS if the slot(s) are enabled
727  * 		HPC_ERR_FAILED if the slot can't be enabled
728  */
729 /* ARGSUSED */
730 static int
731 sghsc_connect(caddr_t op_arg, hpc_slot_t sloth, void *data,
732     uint_t flag)
733 {
734 	int i = 0;
735 	sghsc_t *sghsc = (sghsc_t *)op_arg;
736 	int rc;
737 	int result;
738 	int	slot_num = sghsc_get_slotnum(sghsc, sloth);
739 
740 	switch (flag) {
741 
742 		case SGHSC_ALL_SLOTS_ENABLE:
743 		for (i = 0; i < sghsc->sghsc_num_slots; i++) {
744 			/*
745 			 * All slots will be marked 'empty' as HP Framework
746 			 * will try to connect those which have no kernel node.
747 			 */
748 			sghsc->sghsc_slot_table[i].slot_status =
749 			    HPC_SLOT_EMPTY;
750 		}
751 
752 		return (HPC_SUCCESS);
753 	}
754 
755 	if (slot_num == -1)
756 		return (HPC_ERR_INVALID);
757 
758 	SGHSC_MUTEX_ENTER(sghsc);
759 
760 	DEBUGF(1, (CE_NOTE, "sghsc%d: connecting logical slot%d for"
761 	    " node %d / board %d", sghsc->sghsc_instance, slot_num,
762 	    sghsc->sghsc_node_id, sghsc->sghsc_board));
763 
764 	/*
765 	 * Powering an empty slot is highly illegal so far
766 	 * (before SC implemented a constant poll). Otherwise
767 	 * it breaks ddi framework and HP. The workaround
768 	 * is to check for a card first.
769 	 */
770 	rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
771 	    sghsc->sghsc_board, slot_num, &result);
772 
773 	if (rc == ETIMEDOUT) {
774 		SGHSC_MUTEX_EXIT(sghsc);
775 		return (HPC_ERR_FAILED);
776 	}
777 
778 	if (rc) {
779 		cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for"
780 		    " node %d / board %d", sghsc->sghsc_instance, slot_num,
781 		    sghsc->sghsc_node_id, sghsc->sghsc_board);
782 		sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_UNKNOWN;
783 		SGHSC_MUTEX_EXIT(sghsc);
784 		return (HPC_ERR_FAILED);
785 	}
786 
787 
788 	if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
789 		sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_EMPTY;
790 		SGHSC_MUTEX_EXIT(sghsc);
791 		return (HPC_ERR_FAILED);
792 	}
793 
794 	rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_ON, sghsc->sghsc_node_id,
795 	    sghsc->sghsc_board, slot_num, &result);
796 	if (rc) {
797 		cmn_err(CE_WARN, "sghsc%d: unable to poweron slot %d for"
798 		    " node %d / board %d", sghsc->sghsc_instance,
799 		    slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
800 		SGHSC_MUTEX_EXIT(sghsc);
801 		return (HPC_ERR_FAILED);
802 	} else {
803 		sghsc->sghsc_slot_table[slot_num].slot_status =
804 		    HPC_SLOT_CONNECTED;
805 	}
806 
807 	SGHSC_MUTEX_EXIT(sghsc);
808 
809 	return (HPC_SUCCESS);
810 }
811 
812 
813 /*
814  * Disconnecting a slot or slots
815  *
816  * return:  HPC_SUCCESS if slot(s) are successfully disconnected
817  *          HPC_ERR_FAILED if slot(s) can't be disconnected
818  *
819  */
820 /* ARGSUSED */
821 static int
822 sghsc_disconnect(caddr_t op_arg, hpc_slot_t sloth, void *data,
823     uint_t flag)
824 {
825 	sghsc_t *sghsc = (sghsc_t *)op_arg;
826 	int rc;
827 	int result;
828 	int slot_num = sghsc_get_slotnum(sghsc, sloth);
829 
830 	switch (flag) {
831 		case SGHSC_ALL_SLOTS_DISABLE:
832 		return (HPC_SUCCESS);
833 
834 	}
835 
836 	if (slot_num == -1)
837 		return (HPC_ERR_INVALID);
838 
839 	SGHSC_MUTEX_ENTER(sghsc);
840 
841 	/*
842 	 * Disconnecting an empty or disconnected slot
843 	 * does't make sense.
844 	 */
845 	if (sghsc->sghsc_slot_table[slot_num].slot_status !=
846 	    HPC_SLOT_CONNECTED) {
847 		SGHSC_MUTEX_EXIT(sghsc);
848 		return (HPC_SUCCESS);
849 	}
850 
851 	rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_OFF, sghsc->sghsc_node_id,
852 	    sghsc->sghsc_board, slot_num, &result);
853 	if (rc) {
854 		cmn_err(CE_WARN, "sghsc%d: unable to poweroff slot %d for"
855 		    " node %d / board %d", sghsc->sghsc_instance,
856 		    slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
857 		SGHSC_MUTEX_EXIT(sghsc);
858 		return (HPC_ERR_FAILED);
859 	} else {
860 		sghsc->sghsc_slot_table[slot_num].slot_status =
861 		    HPC_SLOT_DISCONNECTED;
862 	}
863 
864 	SGHSC_MUTEX_EXIT(sghsc);
865 
866 	return (HPC_SUCCESS);
867 }
868 
869 /*
870  * Entry point from the hotplug framework to do
871  *   the main hotplug operations
872  * Return val:	HPC_SUCCESS  success on ops
873  *		HPC_NOT_SUPPORTED not supported feature
874  *		HPC_ERR_FAILED	ops failed
875  */
876 /*ARGSUSED*/
877 static int
878 sghsc_control(caddr_t op_arg, hpc_slot_t sloth, int request,
879     caddr_t arg)
880 {
881 	sghsc_t *sghsc = (sghsc_t *)op_arg;
882 	int slot = sghsc_get_slotnum(sghsc, sloth);
883 	int error = HPC_SUCCESS;
884 	int rc;
885 	int result;
886 
887 	if ((sghsc == NULL) || (slot < 0) ||
888 	    (slot >= sghsc->sghsc_num_slots)) {
889 		cmn_err(CE_WARN, "sghsc%d: sghsc_control fails with slot = %d"
890 		    " max = %d, sloth = 0x%p for node %d / board %d",
891 		    sghsc->sghsc_instance, slot, sghsc->sghsc_num_slots,
892 		    sloth, sghsc->sghsc_node_id, sghsc->sghsc_board);
893 		return (HPC_ERR_INVALID);
894 	}
895 
896 	SGHSC_MUTEX_ENTER(sghsc);
897 
898 	switch (request) {
899 	case HPC_CTRL_GET_LED_STATE: {
900 		/* arg == hpc_led_info_t */
901 
902 		hpc_led_info_t *ledinfo;
903 
904 		ledinfo = (hpc_led_info_t *)arg;
905 
906 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
907 		    " HPC_CTRL_GET_LED_STATE for node %d / board %d slot %d",
908 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
909 		    sghsc->sghsc_board, slot));
910 
911 		switch (ledinfo->led) {
912 		case HPC_POWER_LED:
913 		case HPC_ATTN_LED:
914 		case HPC_FAULT_LED:
915 		case HPC_ACTIVE_LED:
916 			error = sghsc_led_state(sghsc, sloth,
917 			    HPC_CTRL_GET_LED_STATE, ledinfo);
918 			break;
919 		default:
920 			cmn_err(CE_WARN, "sghsc%d: sghsc_control"
921 			    " HPC_CTRL_GET_LED_STATE "
922 			    " unknown led state %d for node %d / board %d"
923 			    " slot handle 0x%p", sghsc->sghsc_instance,
924 			    ledinfo->led, sghsc->sghsc_node_id,
925 			    sghsc->sghsc_board, sloth);
926 			error = HPC_ERR_NOTSUPPORTED;
927 			break;
928 		}
929 
930 		break;
931 	}
932 
933 	case HPC_CTRL_SET_LED_STATE: {
934 		/* arg == hpc_led_info_t */
935 		hpc_led_info_t *ledinfo;
936 
937 		ledinfo = (hpc_led_info_t *)arg;
938 
939 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
940 		    " HPC_CTRL_SET_LED_STATE for node %d / board %d slot %d",
941 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
942 		    sghsc->sghsc_board, slot));
943 
944 		switch (ledinfo->led) {
945 		case HPC_POWER_LED:
946 		case HPC_ATTN_LED:
947 		case HPC_FAULT_LED:
948 		case HPC_ACTIVE_LED:
949 			DEBUGF(1, (CE_NOTE, "sghsc:"
950 			    " LED writing not supported "));
951 			break;
952 
953 		default:
954 			DEBUGF(1, (CE_NOTE, "sghsc:"
955 			    " LED not supported "));
956 			error = HPC_ERR_NOTSUPPORTED;
957 		}
958 		break;
959 	}
960 
961 	case HPC_CTRL_GET_SLOT_STATE: {
962 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
963 		    " HPC_CTRL_GET_SLOT_STATE for node %d / board %d slot %d",
964 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
965 		    sghsc->sghsc_board, slot));
966 
967 		/*
968 		 * Send mailbox cmd to SC to query the latest state
969 		 */
970 		rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
971 		    sghsc->sghsc_board, slot, &result);
972 
973 		if (rc == ETIMEDOUT) {
974 			error = HPC_ERR_FAILED;
975 			break;
976 		}
977 
978 		if (rc) {
979 			cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for "
980 			    "node %d / board %d", sghsc->sghsc_instance, slot,
981 			    sghsc->sghsc_node_id, sghsc->sghsc_board);
982 			sghsc->sghsc_slot_table[slot].slot_status =
983 			    HPC_SLOT_UNKNOWN;
984 			*(hpc_slot_state_t *)arg = HPC_SLOT_UNKNOWN;
985 			break;
986 		}
987 
988 		/*
989 		 * Update the cached state if needed. Initally all
990 		 * slots are marked as empty for the Hot Plug Framwork.
991 		 */
992 		if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
993 			sghsc->sghsc_slot_table[slot].slot_status =
994 			    HPC_SLOT_EMPTY;
995 		} else if ((result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT) {
996 			sghsc->sghsc_slot_table[slot].slot_status =
997 			    HPC_SLOT_CONNECTED;
998 		} else if (sghsc->sghsc_slot_table[slot].slot_status ==
999 		    HPC_SLOT_EMPTY ||
1000 		    sghsc->sghsc_slot_table[slot].slot_status ==
1001 		    HPC_SLOT_UNKNOWN) {
1002 			sghsc->sghsc_slot_table[slot].slot_status =
1003 			    HPC_SLOT_DISCONNECTED;
1004 		}
1005 		/*
1006 		 * No change
1007 		 */
1008 		*(hpc_slot_state_t *)arg =
1009 		    sghsc->sghsc_slot_table[slot].slot_status;
1010 
1011 		break;
1012 	}
1013 
1014 	case HPC_CTRL_DEV_CONFIGURED:
1015 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1016 		    " HPC_CTRL_DEV_CONFIGURED for node %d / board %d slot %d",
1017 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
1018 		    sghsc->sghsc_board, slot));
1019 
1020 		if (sghsc_configure_ack)
1021 			cmn_err(CE_NOTE, "sghsc%d:"
1022 			    " node %d / board %d slot %d configured",
1023 			    sghsc->sghsc_instance, sghsc->sghsc_node_id,
1024 			    sghsc->sghsc_board, slot);
1025 		/*
1026 		 * This is important to tell SC:
1027 		 * "start looking for ENUMs"
1028 		 */
1029 		if (sghsc->sghsc_slot_table[slot].flags &
1030 		    SGHSC_SLOT_AUTO_CFG_EN)
1031 			(void) sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
1032 			    sghsc->sghsc_node_id, sghsc->sghsc_board,
1033 			    slot, &result);
1034 
1035 		break;
1036 
1037 	case HPC_CTRL_DEV_UNCONFIGURED:
1038 		/*
1039 		 * due to unclean drivers, unconfigure may leave
1040 		 * some state on card, configure may actually
1041 		 * use these invalid values. therefore, may force
1042 		 * disconnect.
1043 		 */
1044 
1045 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control "
1046 		    "HPC_CTRL_DEV_UNCONFIGURED for node %d / board %d slot %d",
1047 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
1048 		    sghsc->sghsc_board, slot));
1049 
1050 		SGHSC_MUTEX_EXIT(sghsc);
1051 		if (sghsc_disconnect(op_arg, sloth, 0,
1052 		    0) != HPC_SUCCESS) {
1053 			DEBUGF(1, (CE_NOTE, "sghsc_control: "
1054 			    "disconnect failed"));
1055 			error = HPC_ERR_FAILED;
1056 		}
1057 
1058 		cmn_err(CE_NOTE, "sghsc%d: node %d / board %d "
1059 		    "slot %d unconfigured", sghsc->sghsc_instance,
1060 		    sghsc->sghsc_node_id, sghsc->sghsc_board, slot);
1061 		return (error);
1062 
1063 
1064 	case HPC_CTRL_GET_BOARD_TYPE: {
1065 		/* arg = hpc_board_type_t */
1066 
1067 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1068 		    " HPC_CTRL_GET_BOARD_TYPE for node %d / board %d slot %d",
1069 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
1070 		    sghsc->sghsc_board, slot));
1071 
1072 		*(hpc_board_type_t *)arg =
1073 		    sghsc->sghsc_slot_table[slot].board_type;
1074 
1075 		break;
1076 	}
1077 
1078 	case HPC_CTRL_ENABLE_AUTOCFG:
1079 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1080 		    " HPC_CTRL_ENABLE_AUTOCFG for node %d / board %d slot %d",
1081 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
1082 		    sghsc->sghsc_board, slot));
1083 
1084 		sghsc->sghsc_slot_table[slot].flags |= SGHSC_SLOT_AUTO_CFG_EN;
1085 		(void) hpc_slot_event_notify(sloth, HPC_EVENT_ENABLE_ENUM,
1086 		    HPC_EVENT_NORMAL);
1087 
1088 		/*
1089 		 * Tell SC to start looking for ENUMs on this slot.
1090 		 */
1091 		rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED, sghsc->sghsc_node_id,
1092 		    sghsc->sghsc_board, slot, &result);
1093 
1094 		if (rc)
1095 			cmn_err(CE_WARN, "sghsc%d: unable to arm ENUM for"
1096 			    " node %d / board %d, slot %d",
1097 			    sghsc->sghsc_instance, sghsc->sghsc_node_id,
1098 			    sghsc->sghsc_board, slot);
1099 		break;
1100 
1101 	case HPC_CTRL_DISABLE_AUTOCFG:
1102 		DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1103 		    " HPC_CTRL_DISABLE_AUTOCFG for node %d / board %d slot %d",
1104 		    sghsc->sghsc_instance, sghsc->sghsc_node_id,
1105 		    sghsc->sghsc_board, slot));
1106 
1107 		sghsc->sghsc_slot_table[slot].flags &= ~SGHSC_SLOT_AUTO_CFG_EN;
1108 		(void) hpc_slot_event_notify(sloth, HPC_EVENT_DISABLE_ENUM,
1109 		    HPC_EVENT_NORMAL);
1110 		break;
1111 
1112 	case HPC_CTRL_DISABLE_SLOT:
1113 	case HPC_CTRL_ENABLE_SLOT:
1114 		break;
1115 
1116 	/*  need to add support for enable/disable_ENUM */
1117 	case HPC_CTRL_DISABLE_ENUM:
1118 	case HPC_CTRL_ENABLE_ENUM:
1119 	default:
1120 		DEBUGF(1, (CE_CONT, "sghsc%d: sghsc_control "
1121 		    "request (0x%x) not supported", sghsc->sghsc_instance,
1122 		    request));
1123 
1124 		/* invalid request */
1125 		error = HPC_ERR_NOTSUPPORTED;
1126 	}
1127 
1128 	SGHSC_MUTEX_EXIT(sghsc);
1129 
1130 	return (error);
1131 }
1132 
1133 /*
1134  * Read/write slot's led
1135  *	Assume MUTEX_HELD
1136  *
1137  * return:  HPC_SUCCESS if the led's status is avaiable,
1138  *          SC return status otherwise.
1139  */
1140 static int
1141 sghsc_led_state(sghsc_t *sghsc, hpc_slot_t sloth, int op,
1142     hpc_led_info_t *ledinfo)
1143 {
1144 	int rval;
1145 	int slot_num;
1146 	int result;
1147 
1148 	slot_num = sghsc_get_slotnum(sghsc, sloth);
1149 	rval = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
1150 	    sghsc->sghsc_board, slot_num, &result);
1151 	if (rval != HPC_SUCCESS)
1152 		return (rval);
1153 
1154 	switch (op) {
1155 	case HPC_CTRL_GET_LED_STATE:
1156 		switch (ledinfo->led) {
1157 		case HPC_POWER_LED:
1158 			if ((result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
1159 				ledinfo->state = HPC_LED_ON;
1160 			else
1161 				ledinfo->state = HPC_LED_OFF;
1162 			break;
1163 
1164 		case HPC_ATTN_LED:
1165 		case HPC_FAULT_LED:
1166 			if ((result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
1167 				ledinfo->state = HPC_LED_ON;
1168 			else
1169 				ledinfo->state = HPC_LED_OFF;
1170 			break;
1171 
1172 		case HPC_ACTIVE_LED:
1173 			if ((result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
1174 				ledinfo->state = HPC_LED_ON;
1175 			else
1176 				ledinfo->state = HPC_LED_OFF;
1177 			break;
1178 		}
1179 
1180 		break;
1181 
1182 	case HPC_CTRL_SET_LED_STATE:
1183 		return (HPC_ERR_NOTSUPPORTED);
1184 	}
1185 
1186 	return (HPC_SUCCESS);
1187 }
1188 
1189 /*
1190  * sghsc_get_slotnum()
1191  *	get slot number from the slot handle
1192  * returns non-negative value to indicate slot number
1193  *	  -1 for failure
1194  */
1195 static int
1196 sghsc_get_slotnum(sghsc_t *sghsc, hpc_slot_t sloth)
1197 {
1198 	int i;
1199 
1200 	if (sloth == NULL || sghsc == NULL)
1201 		return (-1);
1202 
1203 	for (i = 0; i < sghsc->sghsc_num_slots; i++) {
1204 
1205 		if (sghsc->sghsc_slot_table[i].handle == sloth)
1206 			return (i);
1207 	}
1208 
1209 	return (-1);
1210 
1211 }
1212 
1213 /*
1214  * sghsc_scctl()
1215  *      mailbox interface
1216  *
1217  * return result code from mailbox operation
1218  */
1219 static int
1220 sghsc_scctl(int cmd, int node_id, int board, int slot, int *resultp)
1221 {
1222 	int		ret = 0xbee;
1223 	bitcmd_info_t	cmd_info, *cmd_infop = &cmd_info;
1224 	bitcmd_resp_t	cmd_info_r, *cmd_info_r_p = &cmd_info_r;
1225 	sbbc_msg_t	request, *reqp = &request;
1226 	sbbc_msg_t	response, *resp = &response;
1227 
1228 	cmd_infop->cmd_id = 0x01234567;
1229 	cmd_infop->node_id = node_id;
1230 	cmd_infop->board = board;
1231 	cmd_infop->slot = slot;
1232 
1233 	reqp->msg_type.type = CPCI_MBOX;
1234 	reqp->msg_status = 0xeeeeffff;
1235 	reqp->msg_len = sizeof (cmd_info);
1236 	reqp->msg_bytes = 8;
1237 	reqp->msg_buf = (caddr_t)cmd_infop;
1238 	reqp->msg_data[0] = 0;
1239 	reqp->msg_data[1] = 0;
1240 
1241 	bzero(resp, sizeof (*resp));
1242 	bzero(cmd_info_r_p, sizeof (*cmd_info_r_p));
1243 
1244 	resp->msg_buf = (caddr_t)cmd_info_r_p;
1245 	resp->msg_len = sizeof (cmd_info_r);
1246 
1247 	resp->msg_type.type = CPCI_MBOX;
1248 	resp->msg_bytes = 8;
1249 	resp->msg_status = 0xddddffff;
1250 
1251 	switch (cmd) {
1252 	case SGHSC_GET_SLOT_STATUS:
1253 		reqp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
1254 		resp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
1255 		reqp->msg_len -= 4;
1256 		break;
1257 	case SGHSC_GET_NUM_SLOTS:
1258 		reqp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
1259 		resp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
1260 		reqp->msg_len -= 8;
1261 		break;
1262 	case SGHSC_SET_SLOT_STATUS_RESET:
1263 		reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1264 		resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1265 		cmd_infop->info = CPCI_SET_STATUS_SLOT_RESET;
1266 		break;
1267 	case SGHSC_SET_SLOT_STATUS_READY:
1268 		reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1269 		resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1270 		cmd_infop->info = CPCI_SET_STATUS_SLOT_READY;
1271 		break;
1272 	case SGHSC_SET_SLOT_FAULT_LED_ON:
1273 		reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1274 		resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1275 		cmd_infop->info = CPCI_SET_FAULT_LED_ON;
1276 		break;
1277 	case SGHSC_SET_SLOT_FAULT_LED_OFF:
1278 		reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1279 		resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1280 		cmd_infop->info = CPCI_SET_FAULT_LED_OFF;
1281 		break;
1282 	case SGHSC_SET_SLOT_FAULT_LED_KEEP:
1283 		reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1284 		resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1285 		cmd_infop->info = CPCI_SET_FAULT_LED_KEEP;
1286 		break;
1287 	case SGHSC_SET_SLOT_FAULT_LED_TOGGLE:
1288 		reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1289 		resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1290 		cmd_infop->info = CPCI_SET_FAULT_LED_TOGGLE;
1291 		break;
1292 	case SGHSC_SET_SLOT_POWER_OFF:
1293 		reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1294 		resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1295 		cmd_infop->info = CPCI_POWER_OFF;
1296 		break;
1297 	case SGHSC_SET_SLOT_POWER_ON:
1298 		reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1299 		resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1300 		cmd_infop->info = CPCI_POWER_ON;
1301 		break;
1302 	case SGHSC_GET_CPCI_BOARD_TYPE:
1303 		reqp->msg_type.sub_type = CPCI_BOARD_TYPE;
1304 		resp->msg_type.sub_type = CPCI_BOARD_TYPE;
1305 		reqp->msg_len -= 8;
1306 		break;
1307 	case SGHSC_SET_ENUM_CLEARED:
1308 		reqp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
1309 		resp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
1310 		break;
1311 	default:
1312 		cmn_err(CE_WARN, "sghsc: unrecognized action code 0x%x\n",
1313 		    cmd);
1314 	}
1315 
1316 	DEBUGF(1, (CE_NOTE,
1317 	    "sghsc: sending mbox command type=%d subtype=0x%x size=%d buf=%p",
1318 	    reqp->msg_type.type, reqp->msg_type.sub_type,
1319 	    reqp->msg_len, (void *)reqp->msg_buf));
1320 
1321 	DEBUGF(1, (CE_NOTE,
1322 	    "sghsc: sending buf  cmd_id=0x%x node_id=0x%x board=0x%x "
1323 	    "slot=0x%x info=0x%x", cmd_infop->cmd_id, cmd_infop->node_id,
1324 	    cmd_infop->board, cmd_infop->slot, cmd_infop->info));
1325 
1326 
1327 	ret = sbbc_mbox_request_response(reqp, resp, sghsc_mbx_timeout);
1328 
1329 	/*
1330 	 * The resp->msg_status field may contain an SC error or a common
1331 	 * error such as ETIMEDOUT.
1332 	 */
1333 	if ((ret != 0) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
1334 		DEBUGF(1, (CE_NOTE, "sghsc: mailbox command error = 0x%x, "
1335 		    "status = 0x%x", ret, resp->msg_status));
1336 		return (-1);
1337 	}
1338 
1339 	DEBUGF(1, (CE_NOTE, "sghsc: reply request status=0x%x",
1340 	    reqp->msg_status));
1341 	DEBUGF(1, (CE_NOTE, "sghsc: reply resp status=0x%x",
1342 	    resp->msg_status));
1343 	DEBUGF(1, (CE_NOTE, "sghsc: reply buf  cmd_id=0x%x result=0x%x\n",
1344 	    cmd_info_r_p->cmd_id, cmd_info_r_p->result));
1345 
1346 #ifdef DEBUG_EXTENDED
1347 	if (cmd == SGHSC_GET_NUM_SLOTS) {
1348 		DEBUGF(1, (CE_NOTE, "sghsc:  node %d / board %d has %d slots",
1349 		    cmd_infop->node_id, cmd_infop->board,
1350 		    cmd_info_r_p->result));
1351 		*resultp = cmd_info_r_p->result;
1352 		return (0);
1353 	}
1354 
1355 	if ((cmd_info_r_p->result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT)
1356 		DEBUGF(1, (CE_NOTE, "sghsc: cpower on"));
1357 
1358 	if ((cmd_info_r_p->result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
1359 		DEBUGF(1, (CE_NOTE, "sghsc: power led on"));
1360 
1361 	if ((cmd_info_r_p->result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
1362 		DEBUGF(1, (CE_NOTE, "sghsc: fault led on"));
1363 
1364 	if ((cmd_info_r_p->result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
1365 		DEBUGF(1, (CE_NOTE, "sghsc: remove(hp) led on"));
1366 
1367 	if ((cmd_info_r_p->result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT)
1368 		DEBUGF(1, (CE_NOTE, "sghsc: slot empty"));
1369 
1370 	tmp = ((cmd_info_r_p->result >> CPCI_STAT_HOT_SWAP_STATUS_SHIFT) &
1371 	    THREE_BITS);
1372 	if (tmp)
1373 		DEBUGF(1, (CE_NOTE,
1374 		    "sghsc: slot condition(hot swap status) is 0x%x", tmp));
1375 
1376 	if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_CAP)
1377 		DEBUGF(1, (CE_NOTE,
1378 		    "sghsc: freq cap %x", cmd_info_r_p->result &
1379 		    CPCI_GET_STAT_SLOT_HZ_CAP));
1380 
1381 	if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_SET)
1382 		DEBUGF(1, (CE_NOTE,
1383 		    "sghsc: freq setting %x", cmd_info_r_p->result &
1384 		    CPCI_GET_STAT_SLOT_HZ_SET));
1385 
1386 
1387 	if ((cmd_info_r_p->result >> CPCI_STAT_HEALTHY_SHIFT) & ONE_BIT)
1388 		DEBUGF(1, (CE_NOTE, "sghsc: healthy"));
1389 
1390 	if ((cmd_info_r_p->result >> CPCI_STAT_RESET_SHIFT) & ONE_BIT)
1391 		DEBUGF(1, (CE_NOTE, "sghsc: in reset"));
1392 
1393 	if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_GOOD)
1394 		DEBUGF(1, (CE_NOTE, "sghsc: power good"));
1395 
1396 	if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_FAULT)
1397 		DEBUGF(1, (CE_NOTE, "sghsc: power fault"));
1398 
1399 	if (cmd_info_r_p->result & CPCI_GET_STAT_PCI_PRESENT)
1400 		DEBUGF(1, (CE_NOTE, "sghsc: pci present"));
1401 #endif
1402 
1403 	*resultp = cmd_info_r_p->result;
1404 	return (0);
1405 }
1406 
1407 
1408 /*
1409  * sghsc_freemem()
1410  *	deallocates memory resources
1411  *
1412  */
1413 static void
1414 sghsc_freemem(sghsc_t *sghsc)
1415 {
1416 	int i;
1417 
1418 	/*
1419 	 * Free up allocated resources
1420 	 * sghsc_register_slots => unregister all slots
1421 	 */
1422 	for (i = 0; i < sghsc->sghsc_num_slots; i++) {
1423 		if (sghsc->sghsc_slot_table[i].slot_ops)
1424 			hpc_free_slot_ops(sghsc->sghsc_slot_table[i].slot_ops);
1425 		if (sghsc->sghsc_slot_table[i].handle)
1426 			(void) hpc_slot_unregister(
1427 			    &sghsc->sghsc_slot_table[i].handle);
1428 	}
1429 
1430 	/* finally free up slot_table */
1431 	kmem_free(sghsc->sghsc_slot_table,
1432 	    (size_t)(sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)));
1433 
1434 }
1435 
1436 /*
1437  * sghsc_find_sloth()
1438  *      Find slot handle by node id, board number and slot numbert
1439  * Returns slot handle or 0 if slot not found.
1440  */
1441 static hpc_slot_t
1442 sghsc_find_sloth(int node_id, int board, int slot)
1443 {
1444 	int instance;
1445 	sghsc_t *sghsc;
1446 
1447 	for (instance = 0; instance < sghsc_maxinst; instance++) {
1448 		sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
1449 
1450 		if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
1451 		    sghsc->sghsc_board != board)
1452 			continue;
1453 
1454 		DEBUGF(1, (CE_NOTE, "sghsc_find_sloth on board %d at node %d"
1455 		    " slot %d", board, node_id, slot))
1456 
1457 		if (sghsc->sghsc_num_slots < (slot + 1)) {
1458 			cmn_err(CE_WARN, "sghsc%d: slot data corruption at"
1459 			    "node %d / board %d", instance, node_id, board);
1460 			return (NULL);
1461 		}
1462 
1463 		if (sghsc->sghsc_valid == 0)
1464 			return (NULL);
1465 
1466 		/*
1467 		 * Found matching slot, return handle.
1468 		 */
1469 		return (sghsc->sghsc_slot_table[slot].handle);
1470 	}
1471 
1472 	DEBUGF(1, (CE_WARN, "sghsc_find_sloth: slot %d not found for node %d"
1473 	" / board %d", slot, node_id, board));
1474 	return (NULL);
1475 }
1476 
1477 /*
1478  * sghsc_event_handler()
1479  *      Event Handler. This is what for other platforms was an interrupt
1480  * Handler servicing events. It accepts an event and signals it to
1481  * non-interrupt thread.
1482  */
1483 uint_t
1484 sghsc_event_handler(char *arg)
1485 {
1486 	sghsc_event_t *rsp_data;
1487 	hpc_slot_t sloth;
1488 	sghsc_t *enum_state;
1489 
1490 	DEBUGF(1, (CE_NOTE, "sghsc: sghsc_event_handler called"))
1491 
1492 	rsp_data = (sghsc_event_t *)(((sbbc_msg_t *)arg)->msg_buf);
1493 
1494 	if (rsp_data == NULL) {
1495 		cmn_err(CE_WARN,
1496 		    ("sghsc: sghsc_event_handler argument is null\n"));
1497 		return (DDI_INTR_CLAIMED);
1498 	}
1499 
1500 	sloth = sghsc_find_sloth(rsp_data->node_id, rsp_data->board,
1501 	    rsp_data->slot);
1502 	/*
1503 	 * On a board disconnect sghsc soft state may not exist
1504 	 * when the interrupt occurs. We should treat these
1505 	 * interrupts as noise and but them.
1506 	 */
1507 	if (sloth == NULL) {
1508 		DEBUGF(1, (CE_WARN, "sghsc: slot info not available for"
1509 		    " node %d / board %d slot %d. CPCI event rejected",
1510 		    rsp_data->node_id, rsp_data->board, rsp_data->slot));
1511 		return (DDI_INTR_CLAIMED);
1512 	}
1513 
1514 	enum_state = sghsc_find_softstate(rsp_data->node_id, rsp_data->board,
1515 	    rsp_data->slot);
1516 	if (enum_state == NULL) {
1517 		cmn_err(CE_WARN, "sghsc: soft state not available for"
1518 		    " node %d / board %d slot %d", rsp_data->node_id,
1519 		    rsp_data->board, rsp_data->slot);
1520 		return (DDI_INTR_UNCLAIMED);
1521 	}
1522 
1523 	DEBUGF(1, (CE_NOTE, "sghsc: node %d", rsp_data->node_id));
1524 	DEBUGF(1, (CE_NOTE, "sghsc: board %d", rsp_data->board));
1525 	DEBUGF(1, (CE_NOTE, "sghsc: slot %d", rsp_data->slot));
1526 	DEBUGF(1, (CE_NOTE, "sghsc: event info %d", rsp_data->info));
1527 
1528 	switch (rsp_data->info) {
1529 	case SGHSC_EVENT_CARD_INSERT:
1530 		DEBUGF(1, (CE_NOTE, "sghsc: card inserted node %d / board %d"
1531 		    " slot %d", rsp_data->node_id, rsp_data->board,
1532 		    rsp_data->slot));
1533 		enum_state->sghsc_slot_table[rsp_data->slot].board_type =
1534 		    HPC_BOARD_CPCI_HS;
1535 		enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
1536 		    HPC_SLOT_DISCONNECTED;
1537 		break;
1538 	case SGHSC_EVENT_CARD_REMOVE:
1539 		DEBUGF(1, (CE_NOTE, "sghsc: card removed node %d / board %d"
1540 		    " slot %d", rsp_data->node_id, rsp_data->board,
1541 		    rsp_data->slot));
1542 		enum_state->sghsc_slot_table[rsp_data->slot].board_type =
1543 		    HPC_BOARD_UNKNOWN;
1544 		enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
1545 		    HPC_SLOT_EMPTY;
1546 		return (DDI_INTR_CLAIMED);
1547 	case SGHSC_EVENT_POWER_ON:
1548 		DEBUGF(1, (CE_NOTE, "sghsc: power on node %d / board %d"
1549 		    " slot %d", rsp_data->node_id, rsp_data->board,
1550 		    rsp_data->slot));
1551 		return (DDI_INTR_CLAIMED);
1552 	case SGHSC_EVENT_POWER_OFF:
1553 		DEBUGF(1, (CE_NOTE, "sghsc: power off node %d / board %d"
1554 		    " slot %d", rsp_data->node_id, rsp_data->board,
1555 		    rsp_data->slot));
1556 		return (DDI_INTR_CLAIMED);
1557 	case SGHSC_EVENT_HEALTHY_LOST:
1558 		DEBUGF(1, (CE_NOTE, "sghsc: healthy lost node %d / board %d"
1559 		    " slot %d", rsp_data->node_id, rsp_data->board,
1560 		    rsp_data->slot));
1561 		return (DDI_INTR_CLAIMED);
1562 	case SGHSC_EVENT_LEVER_ACTION:
1563 		DEBUGF(1, (CE_NOTE, "sghsc: ENUM generated for node %d /"
1564 		    "board %d slot %d", rsp_data->node_id, rsp_data->board,
1565 		    rsp_data->slot));
1566 		break;
1567 	default:
1568 		DEBUGF(1, (CE_NOTE, "sghsc: unrecognized event info for"
1569 		    " node %d / board %d slot %d", rsp_data->node_id,
1570 		    rsp_data->board, rsp_data->slot));
1571 		return (DDI_INTR_CLAIMED);
1572 	}
1573 
1574 	/*
1575 	 * Signal the ENUM event to the non-interrupt thread as the Hot
1576 	 * Plug Framework will eventually call sghsc_control() but all
1577 	 * the mailbox messages are not allowed from interrupt context.
1578 	 */
1579 
1580 	if (sghsc_rb_put(&sghsc_rb_header, rsp_data) != DDI_SUCCESS) {
1581 		cmn_err(CE_WARN, "sghsc: no space to store #ENUM info");
1582 		return (DDI_INTR_UNCLAIMED);
1583 	}
1584 
1585 	cv_signal(&sghsc_event_thread_cv);
1586 
1587 	return (DDI_INTR_CLAIMED);
1588 }
1589 
1590 /*
1591  * sghsc_event_thread_code()
1592  *      Event Thread. This is non-interrupt thread servicing #ENUM, Insert,
1593  *      Remove, Power on/off, Healthy lost events.
1594  */
1595 static void
1596 sghsc_event_thread_code(void)
1597 {
1598 	int	rc;
1599 	int	result;
1600 	hpc_slot_t sloth;
1601 	sghsc_t *sghsc;
1602 	sghsc_event_t rsp_data;
1603 
1604 	mutex_enter(&sghsc_event_thread_mutex);
1605 
1606 	for (;;) {
1607 		/*
1608 		 * Wait for Event handler to signal event or self destruction.
1609 		 * Assuming the mutex will be automatically reaccuired.
1610 		 */
1611 		cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
1612 
1613 		if (sghsc_event_thread_exit)
1614 			break;
1615 
1616 		/*
1617 		 * Pick up all the relevant events from the ring buffer.
1618 		 */
1619 		while (sghsc_rb_get(&sghsc_rb_header, &rsp_data) ==
1620 		    DDI_SUCCESS) {
1621 
1622 			sghsc = sghsc_find_softstate(rsp_data.node_id,
1623 			    rsp_data.board, rsp_data.slot);
1624 			if (sghsc == NULL)
1625 				continue;
1626 			sloth = sghsc_find_sloth(rsp_data.node_id,
1627 			    rsp_data.board, rsp_data.slot);
1628 			if (sloth == NULL)
1629 				continue;
1630 
1631 			if (!(sghsc->sghsc_slot_table[rsp_data.slot].flags &
1632 			    SGHSC_SLOT_AUTO_CFG_EN))
1633 				continue;
1634 			/*
1635 			 * Insert event leads only to the electrical
1636 			 * connection.
1637 			 */
1638 			if (rsp_data.info == SGHSC_EVENT_CARD_INSERT) {
1639 				rc = sghsc_connect((caddr_t)sghsc, sloth,
1640 				    NULL, 0);
1641 				if (rc != HPC_SUCCESS)
1642 					cmn_err(CE_WARN, "sghsc:"
1643 					    " could not connect inserted card,"
1644 					    " node %d / board %d slot %d",
1645 					    rsp_data.node_id, rsp_data.board,
1646 					    rsp_data.slot);
1647 				continue;
1648 			}
1649 
1650 			/*
1651 			 * ENUM event received.
1652 			 * Reset ENUM and notify SC to poll for the next one.
1653 			 */
1654 			rc = hpc_slot_event_notify(sloth, HPC_EVENT_CLEAR_ENUM,
1655 			    HPC_EVENT_SYNCHRONOUS);
1656 
1657 			if (rc == HPC_EVENT_UNCLAIMED) {
1658 				DEBUGF(1, (CE_WARN,
1659 				    "sghsc: unable to clear ENUM"));
1660 				continue;
1661 			}
1662 
1663 			rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
1664 			    rsp_data.node_id, rsp_data.board,
1665 			    rsp_data.slot, &result);
1666 			if (rc) {
1667 				DEBUGF(1, (CE_WARN,
1668 				    "sghsc: unable to ACK cleared ENUM"));
1669 				continue;
1670 			}
1671 
1672 			/*
1673 			 * process the ENUM.
1674 			 */
1675 			rc = hpc_slot_event_notify(sloth,
1676 			    HPC_EVENT_PROCESS_ENUM, HPC_EVENT_SYNCHRONOUS);
1677 
1678 			if (rc == HPC_EVENT_UNCLAIMED) {
1679 				DEBUGF(1, (CE_WARN,
1680 				    "sghsc: could not process ENUM"));
1681 			}
1682 		}
1683 	}
1684 
1685 	DEBUGF(1, (CE_NOTE, "sghsc: thread_exit"));
1686 	cv_signal(&sghsc_event_thread_cv);
1687 	mutex_exit(&sghsc_event_thread_mutex);
1688 	thread_exit();
1689 }
1690 
1691 /*
1692  * sghsc_find_softstate()
1693  *      Find softstate by node id and board number. Slot number is used for
1694  *      verification.
1695  * Returns board's softstate or 0 if not found.
1696  */
1697 static sghsc_t *
1698 sghsc_find_softstate(int node_id, int board, int slot)
1699 {
1700 	int instance;
1701 	sghsc_t *sghsc;
1702 
1703 	for (instance = 0; instance < sghsc_maxinst; instance++) {
1704 		sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
1705 
1706 		if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
1707 		    sghsc->sghsc_board != board)
1708 			continue;
1709 
1710 		if (sghsc->sghsc_num_slots < (slot + 1)) {
1711 			cmn_err(CE_WARN, "sghsc%d: "
1712 			    "slot data corruption", instance);
1713 			return (NULL);
1714 		}
1715 
1716 		if (sghsc->sghsc_valid == 0)
1717 			return (NULL);
1718 
1719 		/*
1720 		 * Found matching data, return soft state.
1721 		 */
1722 		return (sghsc);
1723 	}
1724 
1725 	cmn_err(CE_WARN, "sghsc: soft state not found");
1726 	return (NULL);
1727 }
1728 
1729 /*
1730  * sghsc_rb_setup()
1731  *      Initialize the event ring buffer with a fixed size. It may require
1732  *      a more elaborate scheme with buffer extension
1733  */
1734 static void
1735 sghsc_rb_setup(sghsc_rb_head_t *rb_head)
1736 {
1737 	if (rb_head->buf == NULL) {
1738 		rb_head->put_idx = 0;
1739 		rb_head->get_idx = 0;
1740 		rb_head->size = SGHSC_RING_BUFFER_SZ;
1741 		rb_head->state = SGHSC_RB_EMPTY;
1742 
1743 		/*
1744 		 * Allocate space for event ring buffer
1745 		 */
1746 		rb_head->buf = (sghsc_event_t *)kmem_zalloc(
1747 		    sizeof (sghsc_event_t) * rb_head->size, KM_SLEEP);
1748 	}
1749 }
1750 
1751 /*
1752  * sghsc_rb_teardown()
1753  *      Free event ring buffer resources.
1754  */
1755 static void
1756 sghsc_rb_teardown(sghsc_rb_head_t *rb_head)
1757 {
1758 	if (rb_head->buf != NULL) {
1759 		/*
1760 		 * Deallocate space for event ring buffer
1761 		 */
1762 		kmem_free(rb_head->buf,
1763 		    (size_t)(sizeof (sghsc_event_t) * rb_head->size));
1764 
1765 		rb_head->buf = NULL;
1766 		rb_head->put_idx = 0;
1767 		rb_head->get_idx = 0;
1768 		rb_head->size = 0;
1769 		rb_head->state = SGHSC_RB_EMPTY;
1770 	}
1771 }
1772 
1773 /*
1774  * sghsc_rb_put()
1775  *      Insert an event info into the event ring buffer.
1776  * Returns DDI_FAILURE if the buffer is full, DDI_SUCCESS otherwise
1777  */
1778 static int
1779 sghsc_rb_put(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
1780 {
1781 	if (rb_head->state == SGHSC_RB_FULL)
1782 		return (DDI_FAILURE);
1783 
1784 	rb_head->buf[rb_head->put_idx] = *event;
1785 
1786 	rb_head->put_idx = ++rb_head->put_idx & (rb_head->size - 1);
1787 
1788 	if (rb_head->put_idx == rb_head->get_idx)
1789 		rb_head->state = SGHSC_RB_FULL;
1790 	else
1791 		rb_head->state = SGHSC_RB_FLOAT;
1792 
1793 	return (DDI_SUCCESS);
1794 }
1795 /*
1796  * sghsc_rb_get()
1797  *      Remove an event info from the event  ring buffer.
1798  * Returns DDI_FAILURE if the buffer is empty, DDI_SUCCESS otherwise.
1799  */
1800 static int
1801 sghsc_rb_get(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
1802 {
1803 
1804 	if (rb_head->state == SGHSC_RB_EMPTY)
1805 		return (DDI_FAILURE);
1806 
1807 	*event = rb_head->buf[rb_head->get_idx];
1808 
1809 	rb_head->get_idx = ++rb_head->get_idx & (rb_head->size - 1);
1810 
1811 	if (rb_head->get_idx == rb_head->put_idx)
1812 		rb_head->state = SGHSC_RB_EMPTY;
1813 	else
1814 		rb_head->state = SGHSC_RB_FLOAT;
1815 
1816 	return (DDI_SUCCESS);
1817 }
1818