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