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