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