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
55int	sghsc_configure_ack = 0;
56int	cpci_enable = 1;
57#ifdef	DEBUG
58#define	SGHSC_DEBUG
59#endif
60
61#ifdef	SGHSC_DEBUG
62int	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 */
76static void *sghsc_state;		/* soft state */
77static 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 */
83static kthread_t *sghsc_event_thread;
84static kmutex_t sghsc_event_thread_mutex;
85static kcondvar_t sghsc_event_thread_cv;
86static boolean_t sghsc_event_thread_exit = B_FALSE;
87
88static 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
113static int sghsc_attach(dev_info_t *, ddi_attach_cmd_t);
114static int sghsc_detach(dev_info_t *, ddi_detach_cmd_t);
115
116static 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
131static struct modldrv modldrv = {
132	&mod_driverops,
133	"Serengeti CompactPCI HSC",
134	&sghsc_dev_ops,
135};
136
137static struct modlinkage modlinkage = {
138	MODREV_1,
139	&modldrv,
140	NULL
141};
142
143/*
144 * Function prototype for HP support
145 */
146static int sghsc_connect(caddr_t, hpc_slot_t slot, void *, uint_t);
147static int sghsc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
148static int sghsc_control(caddr_t, hpc_slot_t, int, caddr_t);
149
150/*
151 * Function prototypes for internal functions
152 */
153static int sghsc_register_slots(sghsc_t *, int);
154static int sghsc_get_slotnum(sghsc_t *, hpc_slot_t);
155static int sghsc_scctl(int, int, int, int, int *);
156static void sghsc_freemem(sghsc_t *);
157static hpc_slot_t sghsc_find_sloth(int, int, int);
158static sghsc_t *sghsc_find_softstate(int, int, int);
159static int sghsc_led_state(sghsc_t *, hpc_slot_t, int, hpc_led_info_t *);
160static void sghsc_rb_setup(sghsc_rb_head_t *);
161static void sghsc_rb_teardown(sghsc_rb_head_t *);
162static int sghsc_rb_get(sghsc_rb_head_t *, sghsc_event_t *);
163static int sghsc_rb_put(sghsc_rb_head_t *, sghsc_event_t *);
164
165/*
166 * Patchable timeout value
167 */
168int sghsc_mbx_timeout = SGHSC_MBX_TIMEOUT;
169
170/*
171 * Data for self-identification. This will help enumerate all soft states.
172 */
173static 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 */
181static 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};
187static 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};
193static 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};
201static 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 */
217int sghsc_event_init = 0;
218static uint_t sghsc_event_handler(char *);
219static void sghsc_event_thread_code(void);
220
221/*
222 * DR event msg and payload
223 */
224static sbbc_msg_t event_msg;
225static sghsc_event_t payload;
226
227/*
228 * Event lock and state
229 */
230static kmutex_t sghsc_event_lock;
231int sghsc_event_state;
232
233int
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
257int
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
303int
304_info(struct modinfo *modinfop)
305{
306	return (mod_info(&modlinkage, modinfop));
307}
308
309/*
310 * sghsc_attach()
311 */
312/* ARGSUSED */
313static int
314sghsc_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
467cleanup:
468	/*
469	 * Free up allocated resources and return error
470	 * sghsc_register_slots => unregister all slots
471	 */
472	sghsc_freemem(sghsc);
473
474cleanup_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 */
487static int
488sghsc_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 */
552static int
553sghsc_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 */
730static int
731sghsc_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 */
821static int
822sghsc_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*/
877static int
878sghsc_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 */
1140static int
1141sghsc_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 */
1195static int
1196sghsc_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 */
1219static int
1220sghsc_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 */
1413static void
1414sghsc_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 */
1441static hpc_slot_t
1442sghsc_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 */
1483uint_t
1484sghsc_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 */
1595static void
1596sghsc_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 */
1697static sghsc_t *
1698sghsc_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 */
1734static void
1735sghsc_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 */
1755static void
1756sghsc_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 */
1778static int
1779sghsc_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 + 1) & (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 */
1800static int
1801sghsc_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 + 1) & (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