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  * Copyright (c) 2019 Peter Tribble.
  26  */
  27 
  28 /*
  29  * Netra ct800 and Netra ct400 (MonteCarlo/Tonga)
  30  * System Controller and Status Boards STREAMS driver.
  31  *
  32  * This driver handles all communications with the Netra ct400 and ct800
  33  * System Controller Boards.
  34  * I/O to the SCB is through the PCF8584 I2C controller.
  35  * The SCB I2C interface and driver interface are provided by the
  36  * Xilinx XCS40XL.
  37  *
  38  * N.B.: The design choice of using STREAMS was dictated because
  39  *       the original system monitor card had to multiplex 2 pcf8574's
  40  *       as one device.
  41  */
  42 
  43 #include <sys/types.h>
  44 #include <sys/param.h>
  45 #include <sys/cred.h>
  46 #include <sys/log.h>
  47 #include <sys/uio.h>
  48 #include <sys/stat.h>
  49 #include <sys/vnode.h>
  50 #include <sys/file.h>
  51 #include <sys/open.h>
  52 #include <sys/kmem.h>
  53 #include <sys/kstat.h>
  54 #include <sys/signal.h>
  55 
  56 #include <sys/stream.h>
  57 #include <sys/strsubr.h>
  58 #include <sys/strsun.h>
  59 #include <sys/poll.h>
  60 
  61 #include <sys/debug.h>
  62 
  63 #include <sys/conf.h>
  64 #include <sys/ddi.h>
  65 #include <sys/sunddi.h>
  66 #include <sys/modctl.h>
  67 
  68 #include <sys/i2c/misc/i2c_svc.h>
  69 
  70 #include <sys/mct_topology.h>
  71 #include <sys/netract_gen.h>
  72 #include <sys/scsbioctl.h>
  73 #include <sys/scsb.h>
  74 #include <sys/scsb_cbi.h>
  75 
  76 #include <sys/hotplug/hpctrl.h>
  77 #include <sys/hsc.h>
  78 #include <sys/hscimpl.h>
  79 
  80 #define CPCI_HOTSWAP_SUPPORT
  81 
  82 #define ALARM_CARD_ON_SLOT      1
  83 #define SCSB_FRU_OP_GET_REG     1
  84 #define SCSB_FRU_OP_SET_REGBIT  2
  85 #define SCSB_FRU_OP_GET_BITVAL  3
  86 #define SCSB_FRU_OP_GET_REGDATA 4
  87 
  88 /*
  89  * (internal only)
  90  * scsb build version format is "CCYYMMDD"
  91  * for integer compares.
  92  */
  93 #define SCSB_BUILD_VERSION      "20001206"
  94 
  95 #define MUTEX_UNINIT    0
  96 #define MUTEX_INIT      2
  97 
  98 static  int scsb_err_threshold = 0; /* max allowed i2c errors */
  99 static  int scsb_freeze_count = 3; /* #I2C errors to indicate SCB removal */
 100 static  int scsb_shutdown_count = 5; /* #polls before passing shutdown evt */
 101 static  int scsb_in_postintr = 0;       /* 1 if scsb is processing intr */
 102 static  kmutex_t *scb_intr_mutex;        /* SCSB interrupt mutex */
 103 static  int     nct_mutex_init = MUTEX_UNINIT;
 104 
 105 extern  int     scsb_hsc_board_healthy();
 106 
 107 static  char    *scsb_name = SCSB_DEVICE_NAME;
 108 static  char    *scsb_clone_name = SCSB_DEVICE_NAME "clone";
 109 static  char    *scsb_build_version = SCSB_BUILD_VERSION;
 110 /*
 111  * cb_ops section of scsb driver.
 112  */
 113 static  int     sm_open(queue_t *, dev_t *, int, int, cred_t *);
 114 static  int     sm_close(queue_t *, int, cred_t *);
 115 
 116 static  int     sm_rput(queue_t *, mblk_t *);   /* from i2c below */
 117 static  int     sm_wput(queue_t *, mblk_t *);   /* from above */
 118 
 119 uint_t  scsb_intr_preprocess(caddr_t arg);
 120 void    scsb_intr(caddr_t arg);
 121 static  void    smf_ioctl(queue_t *, mblk_t *);
 122 static  void    sm_ioc_rdwr(queue_t *, mblk_t *, int);
 123 
 124 static int scsb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
 125 static int scsb_attach(dev_info_t *, ddi_attach_cmd_t);
 126 static int scsb_detach(dev_info_t *, ddi_detach_cmd_t);
 127 static int initialize_scb(scsb_state_t *);
 128 
 129 static dev_info_t *scsb_dip;            /* private copy of devinfo pointer */
 130 
 131 static struct module_info info = {
 132         0, SCSB_DEVICE_NAME, 0, INFPSZ, 512, 128
 133 };
 134 
 135 static struct qinit sm_rinit = {
 136         sm_rput, NULL, sm_open, sm_close, NULL, &info
 137 };
 138 
 139 static struct qinit sm_winit = {
 140         sm_wput, NULL, sm_open, sm_close, NULL, &info
 141 };
 142 
 143 struct streamtab sm_st  = {
 144         &sm_rinit, &sm_winit, NULL, NULL
 145 };
 146 
 147 static struct cb_ops scsb_cb_ops = {
 148 
 149         nulldev,                /* open */
 150         nulldev,                /* close */
 151         nodev,                  /* strategy */
 152         nodev,                  /* print */
 153         nodev,                  /* dump */
 154         nodev,                  /* read */
 155         nodev,                  /* write */
 156         nodev,                  /* ioctl */
 157         nodev,                  /* devmap */
 158         nodev,                  /* mmap */
 159         nodev,                  /* segmap */
 160         nochpoll,               /* poll */
 161         ddi_prop_op,            /* cb_prop_op */
 162         &sm_st,                     /* streamtab  */
 163         D_MP,                   /* Driver compatibility flag */
 164         CB_REV,                         /* rev */
 165         nodev,                          /* int (*cb_aread)() */
 166         nodev                           /* int (*cb_awrite)() */
 167 };
 168 
 169 static struct dev_ops scsb_ops = {
 170 
 171         DEVO_REV,               /* devo_rev, */
 172         0,                      /* refcnt  */
 173         scsb_info,              /* info */
 174         nulldev,                /* identify */
 175         nulldev,                /* probe */
 176         scsb_attach,            /* attach */
 177         scsb_detach,            /* detach */
 178         nodev,                  /* reset */
 179         &scsb_cb_ops,               /* driver operations */
 180         (struct bus_ops *)0,    /* bus operations */
 181         NULL,                   /* power */
 182         ddi_quiesce_not_supported,      /* devo_quiesce */
 183 };
 184 
 185 /*
 186  * Module linkage information for the kernel.
 187  */
 188 
 189 static struct modldrv modldrv = {
 190         &mod_driverops, /* Type of module.  This one is a pseudo driver */
 191 #ifdef DEBUG
 192         "SCB/SSB driver DBG" SCSB_BUILD_VERSION,
 193 #else
 194         "v1.33 Netra ct System Control/Status Board driver",
 195 #endif
 196         &scsb_ops,  /* driver ops */
 197 };
 198 
 199 static struct modlinkage modlinkage = {
 200         MODREV_1,
 201         (void *)&modldrv,
 202         NULL
 203 };
 204 
 205 /*
 206  * local declarations and definitions
 207  */
 208 #if defined(DEBUG)
 209         uint32_t        scsb_debug = 0x00000000;
 210 #else
 211 static  uint32_t        scsb_debug = 0;
 212 #endif
 213 
 214 static  hrtime_t scb_pre_s, scb_pre_e, scb_post_s, scb_post_e;
 215 
 216 static  int             scsb_pil = SCSB_INTR_PIL;
 217 static  int             hsc_pil  = SCSB_INTR_PIL;
 218 static  void            *scsb_state;
 219 static  uint32_t        scsb_global_state;
 220 static  uint32_t        scsb_event_code;        /* for event polling */
 221 static  struct system_info      mct_system_info;
 222 static  int             scsb_healthy_poll_count = 16;
 223 
 224 static fru_id_t         fru_id_table[MCT_MAX_FRUS];
 225 static uchar_t          scb_intr_regs[SCTRL_MAX_GROUP_NUMREGS];
 226 
 227 static  uint32_t        evc_fifo[EVC_FIFO_SIZE];
 228 static  uint32_t        evc_fifo_count = 0;
 229 static  uint32_t        *evc_rptr = evc_fifo;
 230 static  uint32_t        *evc_wptr = evc_fifo;
 231 static  void            *evc_procs[EVC_PROCS_MAX];
 232 static  int             evc_proc_count = 0;
 233 static timeout_id_t scsb_intr_tid;
 234 
 235 int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran);
 236 
 237 /*
 238  * kstat functions
 239  */
 240 static  int     scsb_alloc_kstats(scsb_state_t *);
 241 static  void    scsb_free_kstats(scsb_state_t *);
 242 static  int     update_ks_leddata(kstat_t *, int);
 243 static  int     update_ks_state(kstat_t *, int);
 244 static  int     update_ks_topology(kstat_t *, int);
 245 static  int     update_ks_evcreg(kstat_t *, int);
 246 
 247 /*
 248  * local functions
 249  */
 250 static  void    free_resources(dev_info_t *, scsb_state_t *, int);
 251 static  i2c_transfer_t  *scsb_alloc_i2ctx(i2c_client_hdl_t, uint_t);
 252 static  fru_info_t      *find_fru_info(fru_id_t fru_id);
 253 static  int     scsb_fake_intr(scsb_state_t *, uint32_t);
 254 static  int     scsb_get_status(scsb_state_t *, scsb_status_t *);
 255 static  int     scsb_leds_switch(scsb_state_t *, scsb_ustate_t);
 256 static  void    scsb_freeze(scsb_state_t *scsb);
 257 static  void    scsb_freeze_check(scsb_state_t *scsb);
 258 static  void    scsb_restore(scsb_state_t *scsb);
 259 static  int     scsb_polled_int(scsb_state_t *, int, uint32_t *);
 260 static  int     scsb_check_config_status(scsb_state_t *scsb);
 261 static  int     scsb_set_scfg_pres_leds(scsb_state_t *, fru_info_t *);
 262 static  void    scsb_set_topology(scsb_state_t *);
 263 static  void    scsb_free_topology(scsb_state_t *);
 264 int     scsb_read_bhealthy(scsb_state_t *scsb);
 265 int     scsb_read_slot_health(scsb_state_t *, int);
 266 static  void    tonga_slotnum_check(scsb_state_t *scsb, scsb_uinfo_t *suip);
 267 static  int     tonga_psl_to_ssl(scsb_state_t *scsb, int slotnum);
 268 static  uchar_t tonga_slotnum_led_shift(scsb_state_t *scsb, uchar_t data);
 269 static  int     scsb_clear_intptrs(scsb_state_t *scsb);
 270 static  int     scsb_clear_intmasks(scsb_state_t *scsb);
 271 static  int     scsb_setall_intmasks(scsb_state_t *scsb);
 272 static  int     scsb_write_mask(scsb_state_t *, uchar_t, uchar_t, uchar_t,
 273                                 uchar_t);
 274 static  int     scsb_rdwr_register(scsb_state_t *, int, uchar_t, int,
 275                                 uchar_t *, int);
 276 static  int     scsb_readall_regs(scsb_state_t *);
 277 static  int     scsb_get_led_regnum(scsb_state_t *, scsb_uinfo_t *, uchar_t *,
 278                                 int *, scsb_led_t);
 279 static  void    scsb_free_i2ctx(i2c_client_hdl_t, i2c_transfer_t *);
 280 static  void    check_fru_info(scsb_state_t *, int);
 281 static  void    update_fru_info(scsb_state_t *, fru_info_t *);
 282 static  int     event_to_index(uint32_t);
 283 static  void    add_event_code(scsb_state_t *, uint32_t);
 284 static  uint32_t        del_event_code();
 285 static  uint32_t        get_event_code();
 286 static  int     add_event_proc(scsb_state_t *, pid_t);
 287 static  int     del_event_proc(scsb_state_t *, pid_t);
 288 static  void    rew_event_proc(scsb_state_t *);
 289 static  int     event_proc_count(scsb_state_t *);
 290 static  int     find_evc_proc(pid_t pid);
 291 static  void    signal_evc_procs(scsb_state_t *);
 292 static  int     check_event_procs();
 293 static  int     scsb_is_alarm_card_slot(scsb_state_t *, int);
 294         int     scsb_get_slot_state(scsb_state_t *, int, int *);
 295 static  int     scsb_fru_op(scsb_state_t *, scsb_utype_t, int, int, int);
 296 static  int     scsb_queue_put(queue_t *, int, uint32_t *, char *);
 297 static  int     scsb_queue_ops(scsb_state_t *, int, int, void *, char *);
 298 static  int scsb_blind_read(scsb_state_t *, int, uchar_t, int, uchar_t *, int);
 299 static  int scsb_toggle_psmint(scsb_state_t *, int);
 300 static  int scsb_quiesce_psmint(scsb_state_t *);
 301 static  int scsb_invoke_intr_chain();
 302 int     scsb_intr_register(int (*)(void *), void *, fru_id_t);
 303 void scsb_intr_unregister(fru_id_t);
 304 
 305 #ifdef  DEBUG
 306 static  void    mct_topology_dump(scsb_state_t *, int);
 307 static  void    scsb_failing_event(scsb_state_t *scsb);
 308 #endif
 309 
 310 int
 311 _init(void)
 312 {
 313         int     i, status;
 314 
 315         if (scsb_debug & 0x0005)
 316                 cmn_err(CE_NOTE, "scsb: _init()");
 317         (void) ddi_soft_state_init(&scsb_state, sizeof (scsb_state_t),
 318             SCSB_NO_OF_BOARDS);
 319         (void) hsc_init();
 320         if ((status = mod_install(&modlinkage)) != 0) {
 321                 if (scsb_debug & 0x0006)
 322                         cmn_err(CE_NOTE, "scsb: _init(): mod_install failed");
 323                 ddi_soft_state_fini(&scsb_state);
 324                 (void) hsc_fini();
 325                 return (status);
 326         }
 327         /*
 328          * initialize the FRU ID Table, using real FRU IDs where available
 329          * such as I2C Addresses for FRUs with I2C support
 330          */
 331         for (i = 0; i < MCT_MAX_FRUS; ++i)
 332                 fru_id_table[i] = i + 1;
 333         fru_id_table[event_to_index(SCTRL_EVENT_PS1)] = (fru_id_t)MCT_I2C_PS1;
 334         fru_id_table[event_to_index(SCTRL_EVENT_PS2)] = (fru_id_t)MCT_I2C_PS2;
 335         fru_id_table[event_to_index(SCTRL_EVENT_FAN1)] = (fru_id_t)MCT_I2C_FAN1;
 336         fru_id_table[event_to_index(SCTRL_EVENT_FAN2)] = (fru_id_t)MCT_I2C_FAN2;
 337         fru_id_table[event_to_index(SCTRL_EVENT_FAN3)] = (fru_id_t)MCT_I2C_FAN3;
 338         fru_id_table[event_to_index(SCTRL_EVENT_SCB)] = (fru_id_t)MCT_I2C_SCB;
 339         return (status);
 340 }
 341 
 342 int
 343 _fini(void)
 344 {
 345         int     status;
 346 
 347         if (scsb_debug & 0x0005)
 348                 cmn_err(CE_NOTE, "scsb: _fini()");
 349 
 350         if ((status = mod_remove(&modlinkage)) == 0) {
 351                 ddi_soft_state_fini(&scsb_state);
 352                 (void) hsc_fini();
 353         }
 354         if (scsb_debug & 0x0006)
 355                 cmn_err(CE_NOTE, "scsb: _fini, error %x\n", status);
 356 
 357         return (status);
 358 }
 359 
 360 int
 361 _info(struct modinfo *modinfop)
 362 {
 363         if (scsb_debug & 0x0005)
 364                 cmn_err(CE_NOTE, "scsb: _info()");
 365 
 366         return (mod_info(&modlinkage, modinfop));
 367 }
 368 
 369 static int
 370 scsb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 371 {
 372         int             instance;
 373         scsb_state_t    *scsb;
 374         register int    i;
 375         int             *regs;
 376         uint_t          len;
 377         uchar_t         reg, wdata, rmask;
 378 
 379         instance = ddi_get_instance(dip);
 380 
 381         if (scsb_debug & 0x0005)
 382                 cmn_err(CE_NOTE, "scsb_attach[%d]", instance);
 383 
 384         if (cmd != DDI_ATTACH) {
 385                 if (scsb_debug & 0x0006)
 386                         cmn_err(CE_NOTE,
 387                             "scsb_attach[%d]: cmd 0x%x != DDI_ATTACH",
 388                             instance, cmd);
 389                 return (DDI_FAILURE);
 390         }
 391 
 392         if (ddi_soft_state_zalloc(scsb_state, instance) != DDI_SUCCESS) {
 393                 cmn_err(CE_WARN, "scsb%d: cannot allocate soft state",
 394                     instance);
 395                 return (DDI_FAILURE);
 396         }
 397 
 398         scsb = (scsb_state_t *)ddi_get_soft_state(scsb_state, instance);
 399         if (scsb == NULL) {
 400                 cmn_err(CE_WARN, "scsb%d: cannot get soft state", instance);
 401                 ddi_soft_state_free(scsb_state, instance);
 402                 return (DDI_FAILURE);
 403         }
 404         scsb->scsb_instance = instance;
 405         scsb->scsb_state = 0;        /* just checking strange mutex behavior */
 406 
 407         /*
 408          * make sure this is the SCB's known address
 409          */
 410         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
 411             "reg", &regs, &len) != DDI_PROP_SUCCESS) {
 412                 cmn_err(CE_WARN,
 413                     "scsb%d: Failed to get \"reg\" property", instance);
 414                 ddi_soft_state_free(scsb_state, instance);
 415                 return (DDI_FAILURE);
 416         }
 417         scsb->scsb_i2c_addr = regs[1] & SCSB_I2C_ADDR_MASK;
 418         if (scsb->scsb_i2c_addr != SCSB_I2C_ADDR) {
 419                 cmn_err(CE_WARN, "scsb%d: I2C Addr reg %x %x must be %x",
 420                     instance, regs[0], regs[1], SCSB_I2C_ADDR);
 421                 ddi_soft_state_free(scsb_state, instance);
 422                 ddi_prop_free(regs);
 423                 return (DDI_FAILURE);
 424         }
 425         /* done with array lookup, free resource */
 426         ddi_prop_free(regs);
 427         /*
 428          * initialize synchronization mutex and condition var.
 429          * for this instance.
 430          */
 431         mutex_init(&scsb->scsb_mutex, NULL, MUTEX_DRIVER, NULL);
 432         scsb->scsb_state |= SCSB_UMUTEX;
 433         cv_init(&scsb->scsb_cv, NULL, CV_DRIVER, NULL);
 434         scsb->scsb_state |= SCSB_CONDVAR;
 435 
 436         /*
 437          * 1. Read interrupt property of the board and register its handler.
 438          * 2. Get scsb private handle for communication via I2C Services.
 439          * 3. Allocate and save an i2c_transfer_t for I2C transfers.
 440          */
 441         /* 1 */
 442         if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
 443             DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
 444             "interrupt-priorities") != 1) {
 445                 int tmp[2];
 446                 tmp[0] = scsb_pil;
 447                 tmp[1] = hsc_pil;
 448                 (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
 449                 "interrupt-priorities", tmp, 2);
 450                 scsb->scsb_state |= SCSB_PROP_CREATE;
 451         }
 452         if ((i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 453             DDI_PROP_DONTPASS, "interrupts", -1)) >= 0)
 454                 scsb->scsb_state |= SCSB_P06_INTR_ON;
 455         else
 456                 scsb->scsb_state |= SCSB_P06_NOINT_KLUGE;
 457 
 458         /*
 459          * Look for the device-err-threshold property which specifies
 460          * on how many errors will scsb send a warning event about it's
 461          * health. The scsb_err_threshold is 10 by default.
 462          */
 463         if ((i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 464             DDI_PROP_DONTPASS, "device-err-threshold", -1)) >= 0) {
 465                 scsb_err_threshold = i;
 466 #ifdef  DEBUG
 467                 cmn_err(CE_NOTE, "?scsb_attach: Found device-err-threshold"
 468                     " property, value %d", scsb_err_threshold);
 469 #endif
 470         }
 471         scsb->scsb_i2c_errcnt = 0;
 472         scsb->scsb_err_flag = B_FALSE;
 473         scsb->scsb_kstat_flag = B_FALSE;
 474 
 475         /*
 476          * If all went well, create the minor node for user level access.
 477          */
 478         if (ddi_create_minor_node(dip, scsb_name, S_IFCHR, instance,
 479             "ddi_ctl:pcihpc", NULL) == DDI_FAILURE) {
 480                 cmn_err(CE_WARN, "scsb_attach: Failed to create minor node");
 481                 free_resources(dip, scsb, instance);
 482                 return (DDI_FAILURE);
 483         }
 484         scsb->scsb_state |= SCSB_MINOR_NODE;
 485         scsb->scsb_dev = dip;
 486         if (ddi_create_minor_node(dip, scsb_clone_name, S_IFCHR,
 487             instance|SCSB_CLONE, "ddi_ctl:pcihpc", NULL)
 488             == DDI_FAILURE) {
 489                 cmn_err(CE_WARN, "scsb_attach: Failed to create clone node");
 490                 free_resources(dip, scsb, instance);
 491                 return (DDI_FAILURE);
 492         }
 493         /* CLONE */
 494         bzero(scsb->clone_devs, sizeof (clone_dev_t) * SCSB_CLONES_MAX);
 495         /* 2 */
 496         if (i2c_client_register(dip, &scsb->scsb_phandle) != I2C_SUCCESS) {
 497                 cmn_err(CE_WARN,
 498                     "scsb_attach: Failed I2C Services registration");
 499                 free_resources(dip, scsb, instance);
 500                 return (DDI_FAILURE);
 501         }
 502         scsb->scsb_state |= SCSB_I2C_PHANDLE;
 503         /* 3 */
 504         if ((scsb->scsb_i2ctp = scsb_alloc_i2ctx(scsb->scsb_phandle,
 505             I2C_SLEEP)) == NULL) {
 506                 cmn_err(CE_WARN,
 507                     "scsb%d: i2c_transfer allocation failed", instance);
 508                 free_resources(dip, scsb, instance);
 509                 return (DDI_FAILURE);
 510         }
 511         scsb->scsb_state |= SCSB_I2C_TRANSFER;
 512         /*
 513          * Now it's time to INITIALIZE the boards.
 514          *
 515          *  1. make sure we can do I2C bus transfers to/from the SCB.
 516          *      Read the SCB PROM version for a check.
 517          *  2. set SCB_INITIALIZED bit in SysCommand registers (SYS_CMD_BASE)
 518          *  3. clear all LED Data registers (8) by writing 0's to turn off
 519          *      all LEDs on the SSB.
 520          *  4. read System Configuration Status registers (SCTRL_CFG)
 521          *      to find present FRUs and set corresponding FRU bits at
 522          *      LED_DATA_BASE.
 523          *      Also enable devices in Topology map for the current MP_ID
 524          *      and set the OK LEDs on the SSB.
 525          *  5. read Brd_Hlthy registers (2 @ BRD_HLTHY_BASE)
 526          *  6. Disable PSM Interrupts during initialization, mask all
 527          *      interrupts, and clear Interrupt Pointer registers
 528          *      by writing 0xFF to each register.
 529          *  7. set SCB EEPROM address bits SPA2-SPA0 at SYS_CMD_BASE + 1
 530          *  8. Install the interrupt handler if appropriate.
 531          *  9. clear appropriate bits in Interrupt Mask register for those
 532          *      devices that can be present for this MP_ID Topology.
 533          * 10. enable PSM Interrupt by writing '1' to PSM_INT_EN bit at
 534          *      SYS_CMD_BASE + 1
 535          *      Also update all shadow registers for test utility
 536          *      if scsb_debug is set.
 537          * 11. Check if Alarm Card present at boot and set flags
 538          * 12. Call hsc_attach() for slot registration.
 539          * 13. Allocate, initialze, and install the kstat structures.
 540          * 14. Set scsb_state_t flags to indicate SCB is ready
 541          *      and announce the driver is loaded.
 542          */
 543 
 544         /* 1. through 7. */
 545         if (initialize_scb(scsb) != DDI_SUCCESS) {
 546                 if (!(scsb_debug)) {
 547                         free_resources(dip, scsb, instance);
 548                         return (DDI_FAILURE);
 549                 }
 550         }
 551         /* 8. */
 552         /*
 553          * P0.6 No Interrupt Support
 554          * Instead of installing the handler, it will be called from a user
 555          * program via smf_ioctl().  This flag provides knowledge of the
 556          * necessary workarounds to several scsb routines.
 557          */
 558         /*
 559          * Now Install interrupt handler
 560          */
 561         if (scsb->scsb_state & SCSB_P06_INTR_ON) {
 562                 if (ddi_get_iblock_cookie(dip, instance,
 563                     &scsb->scsb_iblock) == DDI_SUCCESS) {
 564                         mutex_init(&scsb->scsb_imutex, NULL, MUTEX_DRIVER,
 565                             (void *)scsb->scsb_iblock);
 566                         scsb->scsb_state |= SCSB_IMUTEX;
 567                         if (ddi_add_intr(dip, instance, &scsb->scsb_iblock,
 568                             NULL, scsb_intr_preprocess,
 569                             (caddr_t)scsb) != DDI_SUCCESS) {
 570                                 cmn_err(CE_WARN,
 571                                     "scsb_attach: failed interrupt "
 572                                     "handler registration");
 573                                 free_resources(dip, scsb, instance);
 574                                 return (DDI_FAILURE);
 575                         }
 576                         scb_intr_mutex = &scsb->scsb_imutex;
 577                         nct_mutex_init |= MUTEX_INIT;
 578                 } else {
 579                         cmn_err(CE_WARN, "scsb_attach: failed interrupt "
 580                             "mutex initialization");
 581                         if (scsb_debug) {
 582                                 scsb->scsb_state |= SCSB_P06_NOINT_KLUGE;
 583                                 scsb->scsb_state &= ~SCSB_P06_INTR_ON;
 584                         } else {
 585                                 free_resources(dip, scsb, instance);
 586                                 return (DDI_FAILURE);
 587                         }
 588                 }
 589         }
 590         /* 9. */
 591         if (i = scsb_clear_intmasks(scsb)) {
 592                 cmn_err(CE_WARN,
 593                     "scsb%d: I2C TRANSFER Failed", instance);
 594                 if (!scsb_debug) {
 595                         free_resources(dip, scsb, instance);
 596                         return (DDI_FAILURE);
 597                 }
 598         }
 599 
 600         /* 10. */
 601         /*
 602          * For P0.6 No Interrupt Support, don't enable PSM Interrupt
 603          */
 604         if (!(scsb->scsb_state & SCSB_P06_NOINT_KLUGE)) {
 605                 rmask = 0x00;
 606                 wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
 607                 i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE,
 608                     SCTRL_SYS_CMD_BASE);
 609                 reg = SCSB_REG_ADDR(i);
 610                 if (i = scsb_write_mask(scsb, reg, rmask, wdata, (uchar_t)0)) {
 611                         cmn_err(CE_WARN,
 612                             "scsb%d: I2C TRANSFER Failed", instance);
 613                         if (!scsb_debug) {
 614                                 free_resources(dip, scsb, instance);
 615                                 return (DDI_FAILURE);
 616                         }
 617                 } else
 618                         scsb->scsb_state |= SCSB_PSM_INT_ENABLED;
 619         }
 620         if (scsb_debug) {
 621                 /*
 622                  * For smctrl test utility,
 623                  * so all data is available in shadow registers
 624                  *
 625                  * DEBUG_MODE enables private testing interfaces
 626                  * DIAGS_MODE permits limited testing interfaces
 627                  */
 628                 scsb->scsb_state |= SCSB_DEBUG_MODE;
 629                 mutex_enter(&scsb->scsb_mutex);
 630                 if (scsb_readall_regs(scsb))
 631                         cmn_err(CE_WARN,
 632                             "scsb_attach: scsb_readall FAILED");
 633                 mutex_exit(&scsb->scsb_mutex);
 634         }
 635         /* 11. */
 636         /* Check if Alarm Card present at boot and set flags */
 637         if (scsb_fru_op(scsb, ALARM, 1, SCTRL_SYSCFG_BASE,
 638             SCSB_FRU_OP_GET_BITVAL))
 639                 scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
 640 
 641         /* 12. */
 642         if (scsb_debug & 0x0004)
 643                 cmn_err(CE_NOTE,
 644                     "scsb_attach: registering cPCI slots");
 645         if (scsb_hsc_attach(dip, scsb, instance) != DDI_SUCCESS) {
 646                 if (scsb_debug & 0x00008000) {
 647                         cmn_err(CE_WARN,
 648                         "scsb: Hotswap controller initialisation"
 649                             " failed\n");
 650                 }
 651         } else
 652                 scsb->scsb_hsc_state |= SCSB_HSC_INIT;
 653         /* 13. */
 654         /*
 655          * allocate and install the kstat data structures
 656          */
 657         if (scsb_alloc_kstats(scsb) != DDI_SUCCESS) {
 658                 if (scsb_debug & 0x0006)
 659                         cmn_err(CE_WARN, "scsb_attach: ERROR adding kstats");
 660         }
 661         /* 14. */
 662         scsb->scsb_state |= SCSB_UP;
 663         scsb_global_state |= SCSB_UP;
 664         ddi_report_dev(scsb->scsb_dev);
 665         cmn_err(CE_CONT, "?%s%d: "
 666         "Prom Version %s, Midplane Id %x\n",
 667             ddi_driver_name(scsb->scsb_dev),
 668             scsb->scsb_instance,
 669             (scsb->scsb_state & SCSB_P06_PROM) ? "0.6" :
 670             (scsb->scsb_state & SCSB_P10_PROM) ? "1.0" :
 671             (scsb->scsb_state & SCSB_P15_PROM) ? "1.5" :
 672             (scsb->scsb_state & SCSB_P20_PROM) ? "2.0" : "Unknown",
 673             mct_system_info.mid_plane.fru_id);
 674         return (DDI_SUCCESS);
 675 }
 676 
 677 /*
 678  * This funciton is called from scsb_attach(), and from scsb_intr() as part
 679  * of Hot Insertion support, to check the SCB PROM ID register and set
 680  * scsb_state bits and register table pointers as necessary.
 681  */
 682 static int
 683 scb_check_version(scsb_state_t *scsb)
 684 {
 685         int             hotswap = 0;
 686         uchar_t         data;
 687         if (scsb->scsb_state & SCSB_UP) {
 688                 /*
 689                  * If driver is UP, then this call is from scsb_intr()
 690                  * as part of Hot Insertion support.
 691                  */
 692                 hotswap = 1;
 693         }
 694         /* Read the SCB PROM ID */
 695         if (scsb_rdwr_register(scsb, I2C_WR_RD, (uchar_t)SCTRL_PROM_VERSION, 1,
 696             &data, 1)) {
 697                 if (!(hotswap && scsb->scsb_state & SCSB_FROZEN))
 698                         cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
 699                             scsb->scsb_instance);
 700                 if (scsb_debug & 0x0006) {
 701                                 cmn_err(CE_WARN,
 702                                     "scsb_attach(%d): failed read of PROM ID",
 703                                     scsb->scsb_instance);
 704                 }
 705                 return (DDI_FAILURE);
 706         }
 707         /*
 708          * compare with stored version number, and if different,
 709          * report a warning and keep the driver FROZEN
 710          */
 711         if (hotswap) {
 712                 if (((mct_system_info.fru_info_list[SCB])[0].fru_version & 0xf)
 713                     == (data & 0xf)) {
 714                         return (DDI_SUCCESS);
 715                 }
 716                 if (scsb_debug & 0x00020000) {
 717                         cmn_err(CE_NOTE,
 718                             "scb_check_version: SCB version %d "
 719                             "replacing version %d", data,
 720                             (mct_system_info.fru_info_list[SCB])[0].
 721                             fru_version & 0xf);
 722                 }
 723         }
 724         if ((data & 0xf) == SCTRL_PROM_P06) {
 725                 scsb->scsb_state |= SCSB_P06_PROM;
 726         } else if ((data & 0xf) == SCTRL_PROM_P10) {
 727                 scsb->scsb_state |= SCSB_P10_PROM;
 728         } else if ((data & 0xf) == SCTRL_PROM_P15) {
 729                 scsb->scsb_state |= SCSB_P15_PROM;
 730         } else if ((data & 0xf) == SCTRL_PROM_P20) {
 731                 scsb->scsb_state |= SCSB_P20_PROM;
 732         }
 733         if (!(scsb->scsb_state & SCSB_SCB_PRESENT))
 734                 scsb->scsb_state |= SCSB_SCB_PRESENT;
 735         if (IS_SCB_P10) {
 736                 scb_reg_index  = scb_10_reg_index;
 737                 scb_numregs    = scb_10_numregs;
 738                 scb_fru_offset = scb_10_fru_offset;
 739                 scb_sys_offset = scb_10_sys_offset;
 740         } else { /* if (IS_SCB_P15) */
 741                 scb_reg_index  = scb_15_reg_index;
 742                 scb_numregs    = scb_15_numregs;
 743                 scb_fru_offset = scb_15_fru_offset;
 744                 scb_sys_offset = scb_15_sys_offset;
 745         }
 746         if (!(IS_SCB_P15) && !(IS_SCB_P10)) {
 747                 cmn_err(CE_WARN, "scsb%d: SCB Version %d not recognized",
 748                     scsb->scsb_instance, data);
 749                 if (hotswap)
 750                         scsb->scsb_state |= SCSB_FROZEN;
 751                 if (!(scsb_debug)) {
 752                         return (DDI_FAILURE);
 753                 }
 754                 /*
 755                  * DEBUG: Assume SCB15
 756                  */
 757                 scsb->scsb_state |= SCSB_P15_PROM;
 758         }
 759         return (DDI_SUCCESS);
 760 }
 761 
 762 /*
 763  * SCB initialization steps to be called from scsb_attach()
 764  * or from scsb_intr() calling scsb_restore() on Hot Insertion.
 765  */
 766 static int
 767 initialize_scb(scsb_state_t *scsb)
 768 {
 769         register int    i;
 770         uchar_t         reg, wdata, rmask;
 771         /*
 772          * If called from scsb_intr(), we've already done this
 773          */
 774         if (!(scsb->scsb_state & SCSB_IN_INTR))
 775                 if (scb_check_version(scsb) != DDI_SUCCESS)
 776                         return (DDI_FAILURE);
 777         /*
 778          * 2. Set the SCB_INIT bit in the System Command register
 779          */
 780         rmask = 0x00;   /* P1.0: 0x60; */
 781         wdata = 1 << SYS_OFFSET(SCTRL_SYS_SCB_INIT);
 782         i = SYS_REG_INDEX(SCTRL_SYS_SCB_INIT, SCTRL_SYS_CMD_BASE);
 783         reg = SCSB_REG_ADDR(i);
 784         if (i = scsb_write_mask(scsb, reg, rmask, wdata, 0)) {
 785                 cmn_err(CE_WARN,
 786                     "scsb%d: I2C TRANSFER Failed", scsb->scsb_instance);
 787                 if (scsb_debug & 0x0006) {
 788                         cmn_err(CE_NOTE,
 789                         "scsb_attach: failed to set SCB_INIT");
 790                 }
 791                 return (DDI_FAILURE);
 792         }
 793         /* 3. For P1.0 and previous system, turn off all LEDs */
 794         if (IS_SCB_P10) {
 795                 if (scsb_debug & 0x0004) {
 796                         cmn_err(CE_NOTE, "scsb_attach(%d): turning LEDs off",
 797                             scsb->scsb_instance);
 798                 }
 799                 if (i = scsb_leds_switch(scsb, OFF)) {
 800                         cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
 801                             scsb->scsb_instance);
 802                         return (DDI_FAILURE);
 803                 }
 804         }
 805         /* 4. Read the SYSCFG registers, update FRU info and SSB LEDs */
 806         if (scsb_debug & 0x0004)
 807                 cmn_err(CE_NOTE, "scsb_attach(%d): reading config registers",
 808                     scsb->scsb_instance);
 809         if ((i = scsb_check_config_status(scsb)) == 0) {
 810                 if (!(scsb->scsb_state & SCSB_TOPOLOGY)) {
 811                         scsb_set_topology(scsb);
 812                         if (scsb_debug & 0x0004)
 813                                 cmn_err(CE_NOTE, "scsb_attach(%d): mpid = 0x%x",
 814                                     scsb->scsb_instance,
 815                                     mct_system_info.mid_plane.fru_id);
 816                 } else {
 817                         fru_info_t      *fru_ptr;
 818                         /*
 819                          * walk through FRUs and update FRU info
 820                          */
 821                         for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
 822                                 fru_ptr = mct_system_info.fru_info_list[i];
 823                                 while (fru_ptr != NULL) {
 824                                         update_fru_info(scsb, fru_ptr);
 825                                         fru_ptr = fru_ptr->next;
 826                                 }
 827                         }
 828                 }
 829                 i = scsb_set_scfg_pres_leds(scsb, NULL);
 830         }
 831         if (i) {
 832                 cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
 833                     scsb->scsb_instance);
 834                 return (DDI_FAILURE);
 835         }
 836         /* 5. read the Board Healthy registers */
 837         if (scsb_debug & 0x0004)
 838                 cmn_err(CE_NOTE, "scsb_attach(%d): reading Brd_Hlthy registers",
 839                     scsb->scsb_instance);
 840         i = scsb_read_bhealthy(scsb);
 841         if (i) {
 842                 cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
 843                     scsb->scsb_instance);
 844                 return (DDI_FAILURE);
 845         }
 846         /* 6. Clear Interrupt Source registers */
 847         /*
 848          * Due to some registration problems, we must first disable
 849          * global interrupts which may be the default reset value
 850          * itself. However, this is a safe step to do in case of
 851          * implementation changes.
 852          *
 853          * Disable Global SCB Interrupts now
 854          */
 855         rmask = 0x00;   /* P1.0: 0x60; */
 856         wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
 857         i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, SCTRL_SYS_CMD_BASE);
 858         reg = SCSB_REG_ADDR(i);
 859         if (i = scsb_write_mask(scsb, reg, rmask, (uchar_t)0, wdata)) {
 860                 cmn_err(CE_WARN, "scsb%d: Cannot turn off PSM_INT",
 861                     scsb->scsb_instance);
 862                 return (DDI_FAILURE);
 863         }
 864         /* Mask all interrupt sources */
 865         if (i = scsb_setall_intmasks(scsb)) {
 866                 cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
 867                     scsb->scsb_instance);
 868                 return (DDI_FAILURE);
 869         }
 870         /* Clear any latched interrupts */
 871         if (i = scsb_clear_intptrs(scsb)) {
 872                 cmn_err(CE_WARN, "scsb%d: I2C TRANSFER Failed",
 873                     scsb->scsb_instance);
 874                 return (DDI_FAILURE);
 875         }
 876         /* 7. set SCB EEPROM address: NOT USED */
 877         return (DDI_SUCCESS);
 878 }
 879 
 880 /*
 881  * Based on MC conditions, scsb_detach should eventually be made to always
 882  * return FAILURE, as the driver should not be allowed to detach after some
 883  * hs slots have been used.
 884  */
 885 static int
 886 scsb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 887 {
 888         int             instance;
 889         scsb_state_t    *scsb;
 890         uchar_t         reg, wdata;
 891 
 892         /*
 893          * TBD: make sure there are no outstanding operations on the system
 894          * monitor card before detaching.
 895          */
 896         instance = ddi_get_instance(dip);
 897         if (scsb_debug & 0x0005)
 898                 cmn_err(CE_NOTE, "scsb_detach[%d]", instance);
 899         if (cmd != DDI_DETACH) {
 900                 if (scsb_debug & 0x0006)
 901                         cmn_err(CE_NOTE,
 902                             "scsb_detach(%d): command %x is not DDI_DETACH\n",
 903                             instance, cmd);
 904                 return (DDI_FAILURE);
 905         }
 906         scsb = (scsb_state_t *)ddi_get_soft_state(scsb_state, instance);
 907         scsb->scsb_state &= ~SCSB_UP;
 908         scsb_global_state &= ~SCSB_UP;
 909         if (scsb->scsb_hsc_state & SCSB_HSC_INIT) {
 910                 (void) scsb_hsc_detach(dip, scsb, instance);
 911                 scsb->scsb_hsc_state &= ~SCSB_HSC_INIT;
 912         }
 913         if (scsb->scsb_state & SCSB_PSM_INT_ENABLED) {
 914                 /*
 915                  * Disable Global SCB Interrupts now
 916                  */
 917                 wdata = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
 918                 reg = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE,
 919                     SCTRL_SYS_CMD_BASE);
 920                 if (scsb_write_mask(scsb, reg, (uchar_t)0, (uchar_t)0, wdata)) {
 921                         cmn_err(CE_WARN,
 922                             "scsb%d: Cannot turn off PSM_INT", instance);
 923                         if (!scsb_debug) {
 924                                 (void) free_resources(dip, scsb, instance);
 925                                 return (DDI_FAILURE);
 926                         }
 927                 }
 928                 /* Mask all interrupts */
 929                 if (scsb_setall_intmasks(scsb)) {
 930                         cmn_err(CE_WARN,
 931                             "scsb%d: I2C TRANSFER Failed", instance);
 932                         if (!scsb_debug) {
 933                                 (void) free_resources(dip, scsb, instance);
 934                                 return (DDI_FAILURE);
 935                         }
 936                 }
 937                 /* Clear all latched interrupts */
 938                 if (scsb_clear_intptrs(scsb)) {
 939                         cmn_err(CE_WARN,
 940                             "scsb%d: I2C TRANSFER Failed", instance);
 941                         if (!scsb_debug) {
 942                                 (void) free_resources(dip, scsb, instance);
 943                                 return (DDI_FAILURE);
 944                         }
 945                 }
 946         }
 947         if (scsb->scsb_opens && scsb->scsb_rq != NULL)
 948                 qprocsoff(scsb->scsb_rq);
 949         /* CLONE */
 950         (void) scsb_queue_ops(scsb, QPROCSOFF, 0, NULL, NULL);
 951         /*
 952          * free the allocated resources
 953          */
 954         free_resources(dip, scsb, instance);
 955         return (DDI_SUCCESS);
 956 }
 957 
 958 static void
 959 free_resources(dev_info_t *dip, scsb_state_t *scsb, int instance)
 960 {
 961         if (scsb_debug & 0x0005) {
 962                 cmn_err(CE_NOTE, "free_resources[%d], scsb_state=0x%x",
 963                     instance, scsb->scsb_state);
 964                 drv_usecwait(500000);
 965         }
 966         if (scsb->scsb_state & SCSB_P06_INTR_ON &&
 967             scsb->scsb_state & SCSB_IMUTEX) {
 968                 scsb->scsb_state &= ~SCSB_P06_INTR_ON;
 969                 ddi_remove_intr(dip, 0, scsb->scsb_iblock);
 970         }
 971         if (scsb->scsb_state & SCSB_KSTATS) {
 972                 scsb_free_kstats(scsb);
 973                 scsb->scsb_state &= ~SCSB_KSTATS;
 974         }
 975         if (scsb->scsb_state & SCSB_TOPOLOGY) {
 976                 scsb_free_topology(scsb);
 977                 scsb->scsb_state &= ~SCSB_TOPOLOGY;
 978         }
 979 
 980         nct_mutex_init = MUTEX_UNINIT;
 981         if (scsb->scsb_state & SCSB_IMUTEX) {
 982                 scsb->scsb_state &= ~SCSB_IMUTEX;
 983                 mutex_destroy(&scsb->scsb_imutex);
 984         }
 985         if (scsb->scsb_state & SCSB_I2C_TRANSFER) {
 986                 scsb->scsb_state &= ~SCSB_I2C_TRANSFER;
 987                 i2c_transfer_free(scsb->scsb_phandle, scsb->scsb_i2ctp);
 988         }
 989         if (scsb->scsb_state & SCSB_I2C_PHANDLE) {
 990                 scsb->scsb_state &= ~SCSB_I2C_PHANDLE;
 991                 i2c_client_unregister(scsb->scsb_phandle);
 992         }
 993         if (scsb->scsb_state & SCSB_MINOR_NODE) {
 994                 scsb->scsb_state &= ~SCSB_MINOR_NODE;
 995                 ddi_remove_minor_node(dip, NULL);
 996         }
 997         if (scsb->scsb_state & SCSB_PROP_CREATE) {
 998                 scsb->scsb_state &= ~SCSB_PROP_CREATE;
 999                 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
1000                     "interrupt-priorities");
1001         }
1002         /* ddi_prop_remove_all(dip); */
1003         if (scsb->scsb_state & SCSB_CONDVAR) {
1004                 scsb->scsb_state &= ~SCSB_CONDVAR;
1005                 cv_destroy(&scsb->scsb_cv);
1006         }
1007         if (scsb->scsb_state & SCSB_UMUTEX) {
1008                 scsb->scsb_state &= ~SCSB_UMUTEX;
1009                 mutex_destroy(&scsb->scsb_mutex);
1010         }
1011         ddi_soft_state_free(scsb_state, instance);
1012 }
1013 
1014 /*
1015  * Just for testing scsb's poll function
1016  */
1017 static int
1018 scsb_fake_intr(scsb_state_t *scsb, uint32_t evcode)
1019 {
1020         if (evcode == 0)
1021                 evcode = scsb_event_code;
1022         else
1023                 scsb_event_code = evcode;
1024         if (scsb_debug & 0x4001) {
1025                 cmn_err(CE_NOTE, "scsb_fake_intr: event = 0x%x, scsb_rq=0x%p",
1026                     scsb_event_code, (void *)scsb->scsb_rq);
1027         }
1028         /*
1029          * Allow access to shadow registers even though SCB is removed
1030          *
1031          * if (scsb->scsb_state & SCSB_FROZEN) {
1032          *      return (EAGAIN);
1033          * }
1034          */
1035         if (scsb_debug & 0x00040000) {
1036                 check_fru_info(scsb, evcode);
1037                 add_event_code(scsb, evcode);
1038         }
1039         /* just inform user-level via poll about this event */
1040         if (scsb_queue_ops(scsb, QPUT_INT32, 1, &evcode, "scsb_fake_intr")
1041             == QOP_FAILED)
1042                 return (ENOMEM);
1043         return (0);
1044 }
1045 
1046 /* ARGSUSED */
1047 static int
1048 scsb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1049 {
1050         int     retval = DDI_FAILURE;
1051 
1052         if (scsb_debug & 0x0001)
1053                 cmn_err(CE_NOTE, "scsb_info()");
1054 
1055         switch (infocmd) {
1056         case DDI_INFO_DEVT2DEVINFO:
1057                 if (getminor((dev_t)arg) == 0 && scsb_dip != NULL) {
1058                         *result = (void *) scsb_dip;
1059                         retval = DDI_SUCCESS;
1060                 }
1061                 break;
1062 
1063         case DDI_INFO_DEVT2INSTANCE:
1064                 if (getminor((dev_t)arg) == 0) {
1065                         *result = (void *)0;
1066                         retval = DDI_SUCCESS;
1067                 }
1068                 break;
1069 
1070         default:
1071                 break;
1072         }
1073 
1074         return (retval);
1075 }
1076 
1077 
1078 /*
1079  * SCSB STREAMS routines
1080  */
1081 /*ARGSUSED*/
1082 static int
1083 sm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
1084 {
1085         int             instance, clone;
1086         minor_t         minor_dev;
1087         clone_dev_t     *clptr;
1088         scsb_state_t    *scsb;
1089 
1090         minor_dev = getminor(*devp);
1091         instance = SCSB_GET_INSTANCE(minor_dev);
1092         scsb = ddi_get_soft_state(scsb_state, instance);
1093         if (scsb == NULL)
1094                 return (ENXIO);
1095 
1096         if (scsb_debug & 0x0009) {
1097                 cmn_err(CE_NOTE, "sm_open(%d) q=0x%p", instance, (void *)q);
1098         }
1099         if (!(scsb->scsb_state & SCSB_UP)) {
1100                 return (ENODEV);
1101         }
1102         /*
1103          * Don't fail the open if SCB removed since we still want to satisfy
1104          * read requests from the shadow registers, the last know register
1105          * contents.  On new SCB insertion, all will be re-initialized,
1106          * including envmond and it's policies.
1107          *
1108          * if (scsb->scsb_state & SCSB_FROZEN) {
1109          *      return (EAGAIN);
1110          * }
1111          */
1112         ASSERT(credp != NULL);
1113         /*
1114          * XXX check for root access here, return EPERM if not root open
1115          */
1116         if (sflag == MODOPEN) {
1117                 /* scsb module is being pushed */
1118                 if (scsb_debug & 0x0008)
1119                         cmn_err(CE_NOTE, "sm_open(%d): MODOPEN", instance);
1120                 /*
1121                  * this is no longer supported
1122                  */
1123                 return (ENXIO);
1124         } else if (sflag == CLONEOPEN) {
1125                 /* scsb is being opened as a clonable driver */
1126                 if (scsb_debug & 0x0008)
1127                         cmn_err(CE_NOTE, "sm_open(%d): CLONEOPEN", instance);
1128                 /*
1129                  * The cloned stream is not handled via the clone driver.
1130                  * See the minor device code below.
1131                  */
1132                 return (ENXIO);
1133         } else if (minor_dev & SCSB_CLONE) {
1134                 /*
1135                  * First check for the SCSB_CLONE device.
1136                  *      Find an available clone_devs[] entry, or return ENXIO.
1137                  *      Make new dev_t and store in *devp.
1138                  */
1139                 if (scsb_debug & 0x0008)
1140                         cmn_err(CE_NOTE,
1141                             "sm_open(%d): SCSB_CLONE OPEN", instance);
1142                 mutex_enter(&scsb->scsb_mutex);
1143                 if ((clone = scsb_queue_ops(scsb, QFIRST_AVAILABLE, 0, NULL,
1144                 "scsb_open")) == QOP_FAILED) {
1145                         mutex_exit(&scsb->scsb_mutex);
1146                         return (ENXIO);
1147                 }
1148                 clptr = &scsb->clone_devs[clone];
1149                 clptr->cl_flags = SCSB_OPEN;
1150                 clptr->cl_rq = RD(q);
1151                 clptr->cl_minor = SCSB_MAKE_MINOR(instance, clone);
1152                 *devp = makedevice(getmajor(*devp), clptr->cl_minor);
1153                 scsb->scsb_clopens++;
1154                 if (scsb_debug & 0x0008)
1155                         cmn_err(CE_NOTE,
1156                             "sm_open(%d): new clone device minor: 0x%x"
1157                             " stream queue is 0x%p",
1158                             instance, clptr->cl_minor, (void *)q);
1159         } else {
1160                 /* scsb is being opened as a regular driver */
1161                 if (scsb_debug & 0x0008)
1162                         cmn_err(CE_NOTE, "sm_open(%d): DEVOPEN", instance);
1163                 mutex_enter(&scsb->scsb_mutex);
1164                 if (scsb->scsb_state & SCSB_EXCL) {
1165                         if (scsb_debug & 0x0008)
1166                                 cmn_err(CE_NOTE,
1167                                     "sm_open(%d): can't open, state is EXCL",
1168                                     instance);
1169                         mutex_exit(&scsb->scsb_mutex);
1170                         return (EBUSY);
1171                 }
1172                 if (flag & FEXCL) {
1173                         if (scsb_debug & 0x0008)
1174                                 cmn_err(CE_NOTE, "sm_open(%d): is EXCL",
1175                                     instance);
1176                         if (scsb->scsb_state & SCSB_OPEN) {
1177                                 if (scsb_debug & 0x0008)
1178                                         cmn_err(CE_NOTE,
1179                                             "sm_open(%d): cannot open EXCL",
1180                                             instance);
1181                                 mutex_exit(&scsb->scsb_mutex);
1182                                 return (EBUSY);
1183                         }
1184                         scsb->scsb_state |= SCSB_EXCL;
1185                 }
1186                 if (scsb->scsb_opens && scsb->scsb_rq != NULL &&
1187                     scsb->scsb_rq != RD(q)) {
1188                         if (scsb_debug & 0x000a)
1189                                 cmn_err(CE_WARN, "sm_open[%d]: q (0x%p) != "
1190                                     "scsb_rq (0x%p)",
1191                                     instance, (void *)RD(q),
1192                                     (void *)scsb->scsb_rq);
1193                 }
1194                 scsb->scsb_rq = RD(q);
1195                 scsb->scsb_opens++;
1196         }
1197         scsb->scsb_state |= SCSB_OPEN;
1198         mutex_exit(&scsb->scsb_mutex);
1199         RD(q)->q_ptr = WR(q)->q_ptr = scsb;
1200         qprocson(q);
1201         return (0);
1202 }
1203 
1204 /*ARGSUSED*/
1205 static int
1206 sm_close(queue_t *q, int flag, cred_t *credp)
1207 {
1208         scsb_state_t    *scsb;
1209         int             clone;
1210         clone_dev_t     *clptr = NULL;
1211 
1212         scsb = (scsb_state_t *)q->q_ptr;
1213         if (scsb_debug & 0x0009)
1214                 cmn_err(CE_NOTE, "sm_close[%d](0x%p)", scsb->scsb_instance,
1215                     (void *)q);
1216         if (scsb->scsb_clopens) {
1217                 mutex_enter(&scsb->scsb_mutex);
1218                 if ((clone = scsb_queue_ops(scsb, QFIND_QUEUE, 0,
1219                     (void *) RD(q), "scsb_close")) != QOP_FAILED) {
1220                         clptr = &scsb->clone_devs[clone];
1221                         clptr->cl_flags = 0;
1222                         clptr->cl_rq = NULL;
1223                         scsb->scsb_clopens--;
1224                 }
1225                 mutex_exit(&scsb->scsb_mutex);
1226                 if (scsb_debug & 0x0008 && clone < SCSB_CLONES_MAX &&
1227                     clone >= SCSB_CLONES_FIRST)
1228                         cmn_err(CE_NOTE, "sm_close(%d): SCSB_CLONE 0x%x",
1229                             scsb->scsb_instance, clptr->cl_minor);
1230         }
1231         if (clptr == NULL && scsb->scsb_opens) {
1232                 if (scsb_debug & 0x0008)
1233                         cmn_err(CE_NOTE, "sm_close(%d): DEVOPEN, opens=%d",
1234                             scsb->scsb_instance, scsb->scsb_opens);
1235                 if (RD(q) != scsb->scsb_rq) {
1236                         if (scsb_debug & 0x0008)
1237                                 cmn_err(CE_WARN,
1238                                     "sm_close(%d): DEVOPEN, q != scsb_rq",
1239                                     scsb->scsb_instance);
1240                 }
1241                 mutex_enter(&scsb->scsb_mutex);
1242                 scsb->scsb_opens = 0;
1243                 if (scsb->scsb_state & SCSB_EXCL) {
1244                         scsb->scsb_state &= ~SCSB_EXCL;
1245                 }
1246                 scsb->scsb_rq = (queue_t *)NULL;
1247                 mutex_exit(&scsb->scsb_mutex);
1248         }
1249         if (scsb->scsb_opens == 0 && scsb->scsb_clopens == 0) {
1250                 scsb->scsb_state &= ~SCSB_OPEN;
1251         }
1252         RD(q)->q_ptr = WR(q)->q_ptr = NULL;
1253         qprocsoff(q);
1254         return (0);
1255 }
1256 
1257 /*ARGSUSED*/
1258 static int
1259 sm_rput(queue_t *q, mblk_t *mp)
1260 {
1261         if (scsb_debug & 0x0010)
1262                 cmn_err(CE_NOTE, "sm_rput");
1263         return (0);
1264 }
1265 
1266 static int
1267 sm_wput(queue_t *q, mblk_t *mp)
1268 {
1269         scsb_state_t    *scsb = (scsb_state_t *)WR(q)->q_ptr;
1270 
1271         if (scsb_debug & 0x0010)
1272                 cmn_err(CE_NOTE, "sm_wput(%d): mp %p", scsb->scsb_instance,
1273                     (void *)mp);
1274 
1275         switch (mp->b_datap->db_type) {
1276         default:
1277                 freemsg(mp);
1278                 break;
1279 
1280         case M_FLUSH:   /* canonical flush handling */
1281                 if (*mp->b_rptr & FLUSHW) {
1282                         flushq(q, FLUSHDATA);
1283                         /* free any messages tied to scsb */
1284                 }
1285 
1286                 if (*mp->b_rptr & FLUSHR) {
1287                         *mp->b_rptr &= ~FLUSHW;
1288                         qreply(q, mp);
1289                 } else
1290                         freemsg(mp);
1291                 break;
1292 
1293         case M_IOCTL:
1294                 if (scsb_debug & 0x0010)
1295                         cmn_err(CE_NOTE, "sm_wput(%d): M_IOCTL",
1296                             scsb->scsb_instance);
1297                 /* do ioctl */
1298                 smf_ioctl(q, mp);
1299                 break;
1300 
1301         case M_DATA:
1302                 if (scsb_debug & 0x0010)
1303                         cmn_err(CE_NOTE, "sm_wput(%d): M_DATA",
1304                             scsb->scsb_instance);
1305                 if (!(scsb->scsb_state & SCSB_UP)) {
1306                         freemsg(mp);
1307                         return (0);
1308                 }
1309                 freemsg(mp);
1310                 break;
1311 
1312         case M_CTL:
1313                 if (scsb_debug & 0x0010)
1314                         cmn_err(CE_NOTE, "sm_wput(%d): M_CTL",
1315                             scsb->scsb_instance);
1316                 freemsg(mp);
1317                 break;
1318         }
1319 
1320         return (0);
1321 }
1322 
1323 
1324 /*
1325  * These are the system monitor upper ioctl functions.
1326  */
1327 static void
1328 smf_ioctl(queue_t *q, mblk_t *mp)
1329 {
1330         scsb_state_t    *scsb = (scsb_state_t *)q->q_ptr;
1331         struct iocblk   *iocp = (struct iocblk *)mp->b_rptr;
1332 
1333         if (scsb_debug & 0x0020)
1334                 cmn_err(CE_NOTE, "smf_ioctl(%d): (%p)->cmd=%x",
1335                     scsb->scsb_instance, (void *)mp, iocp->ioc_cmd);
1336 
1337         if (!(scsb->scsb_state & SCSB_UP)) {
1338                 miocnak(q, mp, 0, ENXIO);
1339                 return;
1340         }
1341         /*
1342          * Don't fail ALL commands if the SCB removed, since we still want to
1343          * satisfy some requests from the shadow registers, the last known
1344          * register contents.
1345          *
1346          * if (scsb->scsb_state & SCSB_FROZEN) {
1347          *      iocp->ioc_error = EAGAIN;
1348          *      mp->b_datap->db_type = M_IOCNAK;
1349          *      qreply(q, mp);
1350          *      return;
1351          * }
1352          */
1353 
1354         iocp->ioc_error = 0;
1355         switch (iocp->ioc_cmd) {
1356         default:
1357                 /* if we don't understand the ioctl */
1358                 if (scsb_debug & 0x0022)
1359                         cmn_err(CE_NOTE, "smf_ioctl(%d):unkown ioctl %x",
1360                             scsb->scsb_instance, iocp->ioc_cmd);
1361                 iocp->ioc_error = EINVAL;
1362                 break;
1363 
1364         case ENVC_IOC_GETMODE:
1365         {
1366                 uint8_t *curr_mode;
1367 
1368                 iocp->ioc_error = miocpullup(mp, sizeof (uint8_t));
1369                 if (iocp->ioc_error != 0)
1370                         break;
1371 
1372                 curr_mode = (uint8_t *)mp->b_cont->b_rptr;
1373                 if (scsb->scsb_state & SCSB_DEBUG_MODE)
1374                         *curr_mode = (uint8_t)ENVC_DEBUG_MODE;
1375                 else if (scsb->scsb_state & SCSB_DIAGS_MODE)
1376                         *curr_mode = (uint8_t)ENVCTRL_DIAG_MODE;
1377                 else
1378                         *curr_mode = (uint8_t)ENVCTRL_NORMAL_MODE;
1379 
1380                 if (scsb_debug & 0x20) {
1381                         cmn_err(CE_NOTE, "IOC_GETMODE: returning mode 0x%x",
1382                             *curr_mode);
1383                 }
1384                 break;
1385         }
1386 
1387         case ENVC_IOC_SETMODE:
1388         {
1389                 uint8_t *curr_mode;
1390 
1391                 iocp->ioc_error = miocpullup(mp, sizeof (uint8_t));
1392                 if (iocp->ioc_error != 0)
1393                         break;
1394 
1395                 curr_mode = (uint8_t *)mp->b_cont->b_rptr;
1396                 switch (*curr_mode) {
1397                 case ENVCTRL_NORMAL_MODE:
1398                         scsb->scsb_state &=
1399                             ~(SCSB_DEBUG_MODE | SCSB_DIAGS_MODE);
1400                         break;
1401                 case ENVCTRL_DIAG_MODE:
1402                         scsb->scsb_state |=  SCSB_DIAGS_MODE;
1403                         scsb->scsb_state &= ~SCSB_DEBUG_MODE;
1404                         break;
1405                 case ENVC_DEBUG_MODE:
1406                         if (scsb->scsb_state &
1407                             (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)) {
1408                                 scsb->scsb_state &= ~SCSB_DIAGS_MODE;
1409                                 scsb->scsb_state |=  SCSB_DEBUG_MODE;
1410                         } else {
1411                                 iocp->ioc_error = EACCES;
1412                         }
1413                         break;
1414                 default:
1415                         if (scsb_debug & 0x22) {
1416                                 cmn_err(CE_WARN,
1417                                     "IOC_SETMODE: Invalid mode 0x%x",
1418                                     *curr_mode);
1419                         }
1420                         iocp->ioc_error = EINVAL;
1421                         break;
1422                 }
1423                 break;
1424         }
1425 
1426         case ENVC_IOC_ACQUIRE_SLOT_LED_CTRL:
1427                 if (scsb->scsb_state & SCSB_APP_SLOTLED_CTRL)
1428                         iocp->ioc_error = EAGAIN;
1429                 else {
1430                         scsb->scsb_state |= SCSB_APP_SLOTLED_CTRL;
1431                         iocp->ioc_error = 0;
1432                 }
1433                 break;
1434 
1435         case ENVC_IOC_RELEASE_SLOT_LED_CTRL:
1436                 scsb->scsb_state &= ~SCSB_APP_SLOTLED_CTRL;
1437                 iocp->ioc_error = 0;
1438                 break;
1439 
1440         /*
1441          * Not an exposed interface, only used by development utilities.
1442          */
1443         case SCSBIOC_GET_VERSIONS:
1444         {
1445                 uint8_t *ppromid, promid;
1446                 scsb_ids_t *sids;
1447 
1448                 if (iocp->ioc_count == sizeof (uint8_t)) {
1449                         iocp->ioc_error = miocpullup(mp, sizeof (uint8_t));
1450                         if (iocp->ioc_error != 0)
1451                                 break;
1452 
1453                         ppromid = (uint8_t *)mp->b_cont->b_rptr;
1454                         *ppromid = (uint8_t)(mct_system_info.
1455                             fru_info_list[SCB])->fru_version;
1456                         promid = *ppromid;
1457                 } else {
1458                         iocp->ioc_error = miocpullup(mp, sizeof (scsb_ids_t));
1459                         if (iocp->ioc_error != 0)
1460                                 break;
1461 
1462                         sids = (scsb_ids_t *)mp->b_cont->b_rptr;
1463                         bcopy(modldrv.drv_linkinfo, sids->modldrv_string,
1464                             SCSB_MODSTR_LEN);
1465                         bcopy(scsb_build_version, sids->scsb_version,
1466                             SCSB_VERSTR_LEN);
1467                         sids->promid = (uint8_t)(mct_system_info.
1468                             fru_info_list[SCB])->fru_version;
1469 
1470                         promid = sids->promid;
1471                         if (scsb_debug & 0x20) {
1472                                 cmn_err(CE_NOTE,
1473                                     "IOC_GET_VERSIONS: sizeof(scsb_ids_t) "
1474                                     "= %lu", sizeof (scsb_ids_t));
1475                         }
1476                 }
1477                 if (scsb_debug & 0x20) {
1478                         cmn_err(CE_NOTE,
1479                             "IOC_GET_VERSIONS: SCB PROMID = 0x%x", promid);
1480                 }
1481                 break;
1482         }
1483 
1484 #ifdef  DEBUG
1485         case ENVC_IOC_REGISTER_PID:
1486                 iocp->ioc_error = miocpullup(mp, sizeof (pid_t));
1487                 if (iocp->ioc_error == 0) {
1488                         if (add_event_proc(scsb, *(pid_t *)mp->b_cont->b_rptr))
1489                                 iocp->ioc_error = ENOMEM;
1490                 }
1491                 break;
1492 
1493         case ENVC_IOC_UNREGISTER_PID:
1494                 iocp->ioc_error = miocpullup(mp, sizeof (pid_t));
1495                 if (iocp->ioc_error == 0) {
1496                         if (del_event_proc(scsb, *(pid_t *)mp->b_cont->b_rptr))
1497                                 iocp->ioc_error = EINVAL;
1498                 }
1499                 break;
1500 
1501         case SCSBIOC_VALUE_MODE:
1502         {
1503                 uint32_t *mode_vals;
1504                 int     three_vals = 0;
1505 
1506                 if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
1507                         iocp->ioc_error = EINVAL;
1508                         break;
1509                 }
1510 
1511                 if (iocp->ioc_count == sizeof (uint32_t) * 3)
1512                         three_vals = 1;
1513                 else if (iocp->ioc_count != sizeof (uint32_t) * 2) {
1514                         iocp->ioc_error = EINVAL;
1515                         break;
1516                 }
1517 
1518                 iocp->ioc_error = miocpullup(mp, iocp->ioc_count);
1519                 if (iocp->ioc_error != 0)
1520                         break;
1521 
1522                 /*
1523                  * check mode_vals[0] for get/set option.  setting
1524                  * scsb_state is not valid for now.  0 == GET, 1 == SET
1525                  */
1526                 mode_vals = (uint32_t *)mp->b_cont->b_rptr;
1527                 if (mode_vals[0]) {
1528                         scsb_debug = mode_vals[1];
1529                 } else {
1530                         mode_vals[0] = scsb->scsb_state;
1531                         if (three_vals) {
1532                                 mode_vals[1] = scsb->scsb_hsc_state;
1533                                 mode_vals[2] = scsb_debug;
1534                         } else
1535                                 mode_vals[1] = scsb_debug;
1536                 }
1537                 if ((scsb_debug & 0x20) && three_vals) {
1538                         cmn_err(CE_NOTE, "IOC_VALUE_MODE: mode_vals: "
1539                             "0x%x/0x%x/0x%x; ioc_count = 0x%lx",
1540                             mode_vals[0], mode_vals[1], mode_vals[2],
1541                             iocp->ioc_count);
1542                 }
1543                 break;
1544         }
1545 
1546 #ifdef DEBUG
1547         case SCSBIOC_GET_SLOT_INFO:
1548         {
1549                 hsc_slot_t      *slot_info = NULL;
1550                 uint32_t        *slot_vals;
1551                 int             pslotnum;
1552 
1553                 if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
1554                         iocp->ioc_error = EINVAL;
1555                         break;
1556                 }
1557 
1558                 iocp->ioc_error = miocpullup(mp, sizeof (uint32_t) * 2);
1559                 if (iocp->ioc_error != 0)
1560                         break;
1561 
1562                 slot_vals = (uint32_t *)mp->b_cont->b_rptr;
1563                 pslotnum = (int)*slot_vals;
1564                 hsc_ac_op((int)scsb->scsb_instance, pslotnum,
1565                     SCSB_HSC_AC_GET_SLOT_INFO, &slot_info);
1566                 if (slot_info == NULL) {
1567                         iocp->ioc_error = ENODEV;
1568                         break;
1569                 }
1570                 *slot_vals = (uint32_t)slot_info->hs_flags;
1571                 *(++slot_vals) = (uint32_t)slot_info->hs_slot_state;
1572                 if (scsb_debug & 0x20) {
1573                         cmn_err(CE_NOTE, "IOC_GET_SLOT_STATE: slot_vals: "
1574                             "0x%x/0x%x; ioc_count = 0x%lx",
1575                             slot_vals[0], slot_vals[1], iocp->ioc_count);
1576                 }
1577                 break;
1578         }
1579 #endif /* DEBUG */
1580 
1581         case SCSBIOC_GET_FAN_STATUS:
1582         case SCSBIOC_GET_INTR_ARRAY:
1583                 /* for now we don't understand these ioctls */
1584                 if (scsb_debug & 0x0022)
1585                         cmn_err(CE_NOTE, "smf_ioctl(%d):unknown ioctl %x",
1586                             scsb->scsb_instance, iocp->ioc_cmd);
1587                 iocp->ioc_error = EINVAL;
1588                 break;
1589 #endif  /* DEBUG */
1590 
1591         case SCSBIOC_LED_OK_GET:
1592         case SCSBIOC_LED_NOK_GET:
1593         case SCSBIOC_LED_OK_SET:
1594         case SCSBIOC_LED_NOK_SET:
1595         case SCSBIOC_BHEALTHY_GET:
1596         case SCSBIOC_SLOT_OCCUPANCY:
1597         case SCSBIOC_RESET_UNIT:
1598                 if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
1599                         iocp->ioc_error = EACCES;
1600                         break;
1601                 }
1602                 /*FALLTHROUGH*/
1603 
1604         case ENVC_IOC_GETDSKLED:
1605         case ENVC_IOC_SETDSKLED:
1606         case ENVC_IOC_SETFSP:
1607         {
1608                 scsb_uinfo_t *suip;
1609 
1610                 iocp->ioc_error = miocpullup(mp, sizeof (scsb_uinfo_t));
1611                 if (iocp->ioc_error != 0)
1612                         break;
1613 
1614                 suip = (scsb_uinfo_t *)mp->b_cont->b_rptr;
1615                 switch (iocp->ioc_cmd) {
1616                 case SCSBIOC_LED_OK_GET:
1617                         iocp->ioc_error = scsb_led_get(scsb, suip, OK);
1618                         break;
1619                 case SCSBIOC_LED_NOK_GET:
1620                         iocp->ioc_error = scsb_led_get(scsb, suip, NOK);
1621                         break;
1622                 case SCSBIOC_LED_OK_SET:
1623                         iocp->ioc_error = scsb_led_set(scsb, suip, OK);
1624                         break;
1625                 case SCSBIOC_LED_NOK_SET:
1626                         iocp->ioc_error = scsb_led_set(scsb, suip, NOK);
1627                         break;
1628                 case SCSBIOC_BHEALTHY_GET:
1629                         iocp->ioc_error = scsb_bhealthy_slot(scsb, suip);
1630                         break;
1631                 case SCSBIOC_SLOT_OCCUPANCY:
1632                         iocp->ioc_error = scsb_slot_occupancy(scsb, suip);
1633                         break;
1634                 case SCSBIOC_RESET_UNIT:
1635                         iocp->ioc_error = scsb_reset_unit(scsb, suip);
1636                         break;
1637                 case ENVC_IOC_GETDSKLED:
1638                         if (suip->unit_type != DISK) {
1639                                 iocp->ioc_error = EINVAL;
1640                                 break;
1641                         }
1642                         iocp->ioc_error = scsb_led_get(scsb, suip, NOUSE);
1643                         break;
1644                 case ENVC_IOC_SETDSKLED:
1645                         if (suip->unit_type != DISK) {
1646                                 iocp->ioc_error = EINVAL;
1647                                 break;
1648                         }
1649                         iocp->ioc_error = scsb_led_set(scsb, suip, NOUSE);
1650                         break;
1651                 case ENVC_IOC_SETFSP:
1652                         if (scsb->scsb_state & SCSB_FROZEN) {
1653                                 iocp->ioc_error = EAGAIN;
1654                                 break;
1655                         }
1656                         iocp->ioc_error = scsb_led_set(scsb, suip, NOUSE);
1657                         break;
1658                 }
1659                 break;
1660         }
1661 
1662         case SCSBIOC_FAKE_INTR: {
1663                 uint32_t        ui;
1664 
1665                 if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
1666                         iocp->ioc_error = EINVAL;
1667                         break;
1668                 }
1669                 if (mp->b_cont == NULL)
1670                         ui = 0;
1671                 else {
1672                         iocp->ioc_error = miocpullup(mp, sizeof (uint32_t));
1673                         if (iocp->ioc_error != 0)
1674                                 break;
1675                         ui = *(uint32_t *)mp->b_cont->b_rptr;
1676                 }
1677                 iocp->ioc_error = scsb_fake_intr(scsb, ui);
1678                 break;
1679         }
1680 
1681         case SCSBIOC_GET_STATUS :
1682                 if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
1683                         iocp->ioc_error = EINVAL;
1684                         break;
1685                 }
1686                 iocp->ioc_error = miocpullup(mp, sizeof (scsb_status_t));
1687                 if (iocp->ioc_error == 0)
1688                         iocp->ioc_error = scsb_get_status(scsb,
1689                             (scsb_status_t *)mp->b_cont->b_rptr);
1690                 break;
1691 
1692         case SCSBIOC_ALL_LEDS_ON :
1693                 if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
1694                         iocp->ioc_error = EACCES;
1695                 else
1696                         iocp->ioc_error = scsb_leds_switch(scsb, ON);
1697                 break;
1698 
1699         case SCSBIOC_ALL_LEDS_OFF :
1700                 if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
1701                         iocp->ioc_error = EACCES;
1702                 else
1703                         iocp->ioc_error = scsb_leds_switch(scsb, OFF);
1704                 break;
1705 
1706         case SCSBIOC_REG_READ:
1707         case SCSBIOC_REG_WRITE:
1708                 if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
1709                         iocp->ioc_error = EACCES;
1710                 } else {
1711                         scsb_ioc_rdwr_t *iocrdwrp;
1712 
1713                         if (scsb->scsb_state & SCSB_FROZEN &&
1714                             !(scsb->scsb_state & SCSB_DEBUG_MODE)) {
1715                                 iocp->ioc_error = EAGAIN;
1716                                 break;
1717                         }
1718 
1719                         iocp->ioc_error = miocpullup(mp, sizeof (*iocrdwrp));
1720                         if (iocp->ioc_error == 0) {
1721                                 iocrdwrp =
1722                                     (scsb_ioc_rdwr_t *)mp->b_cont->b_rptr;
1723 
1724                                 if (iocp->ioc_cmd == SCSBIOC_REG_READ) {
1725                                         if (iocrdwrp->ioc_rlen > 0) {
1726                                                 sm_ioc_rdwr(q, mp, I2C_WR_RD);
1727                                                 return;
1728                                         }
1729                                 } else {
1730                                         if (iocrdwrp->ioc_wlen > 0) {
1731                                                 sm_ioc_rdwr(q, mp, I2C_WR);
1732                                                 return;
1733                                         }
1734                                 }
1735                                 iocp->ioc_error = EINVAL;
1736                                 break;
1737                         }
1738                 }
1739                 break;
1740 
1741         case SCSBIOC_SHUTDOWN_POLL:
1742         case SCSBIOC_INTEVENT_POLL:
1743                 if (!(scsb->scsb_state & SCSB_DEBUG_MODE)) {
1744                         iocp->ioc_error = EINVAL;
1745                         break;
1746                 }
1747                 iocp->ioc_error = miocpullup(mp, sizeof (uint32_t));
1748                 if (iocp->ioc_error == 0)
1749                         iocp->ioc_error = scsb_polled_int(scsb, iocp->ioc_cmd,
1750                             (uint32_t *)mp->b_cont->b_rptr);
1751                 break;
1752 
1753         case SCSBIOC_RESTORE :
1754                 if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
1755                         iocp->ioc_error = EACCES;
1756                 else {
1757                         scsb_restore(scsb);
1758                         (void) scsb_toggle_psmint(scsb, 1);
1759                         iocp->ioc_error = 0;
1760                 }
1761                 break;
1762 
1763         case SCSBIOC_FREEZE :
1764                 if (!(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
1765                         iocp->ioc_error = EACCES;
1766                 else {
1767                         scsb_freeze_check(scsb);
1768                         scsb_freeze(scsb);
1769                         iocp->ioc_error = 0;
1770                 }
1771                 break;
1772 
1773         /*
1774          * envmond:alarmcard.so response to SCTRL_EVENT_ALARM_INSERTION
1775          */
1776         case ENVC_IOC_ACCONF_RESTORED:
1777                 (void) scsb_hsc_ac_op(scsb, scsb->ac_slotnum,
1778                     SCSB_HSC_AC_SET_BUSY);
1779                 break;
1780 
1781         /*
1782          * envmond:alarmcard.so response to SCTRL_EVENT_ALARM_REMOVAL
1783          */
1784         case ENVC_IOC_ACCONF_STORED:
1785                 if (scsb->scsb_state & SCSB_FROZEN) {
1786                         iocp->ioc_error = EAGAIN;
1787                         break;
1788                 }
1789                 (void) scsb_hsc_ac_op(scsb, scsb->ac_slotnum,
1790                     SCSB_HSC_AC_UNCONFIGURE);
1791                 break;
1792 
1793 #ifdef  DEBUG
1794         case SCSBIOC_TOPOLOGY_DUMP:
1795                 if (!(scsb->scsb_state & SCSB_DEBUG_MODE))
1796                         iocp->ioc_error = EINVAL;
1797                 else {
1798                         mct_topology_dump(scsb, 1);
1799                         iocp->ioc_error = 0;
1800                 }
1801                 break;
1802 #endif
1803         }
1804         if (iocp->ioc_error)
1805                 mp->b_datap->db_type = M_IOCNAK;
1806         else
1807                 mp->b_datap->db_type = M_IOCACK;
1808         qreply(q, mp);
1809 }
1810 
1811 static fru_info_t *
1812 find_fru_info(fru_id_t fru_id)
1813 {
1814         int             i;
1815         fru_info_t      *fru_ptr;
1816 
1817         if (scsb_debug & 0x00100001)
1818                 cmn_err(CE_NOTE, "find_fru_info(0x%x)", fru_id);
1819         if (fru_id == (fru_id_t)0)
1820                 return ((fru_info_t *)NULL);
1821         for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
1822                 fru_ptr = mct_system_info.fru_info_list[i];
1823                 while (fru_ptr != NULL) {
1824                         if (fru_ptr->fru_id == fru_id)
1825                                 return (fru_ptr);
1826                         fru_ptr = fru_ptr->next;
1827                 }
1828         }
1829         return ((fru_info_t *)NULL);
1830 }
1831 
1832 
1833 struct scsb_cb_entry {
1834         void                    *cb_softstate_ptr;
1835         fru_id_t                cb_fru_id;
1836         scsb_fru_event_t        cb_event;
1837         void                    (*cb_func)
1838                                 (void *, scsb_fru_event_t, scsb_fru_status_t);
1839         fru_info_t              *cb_fru_ptr;
1840         struct scsb_cb_entry    *cb_next;
1841 };
1842 
1843 #ifdef DEBUG
1844 int     scsb_cb_count = 0;
1845 #else
1846 static
1847 #endif
1848 struct scsb_cb_entry    *scsb_cb_table;
1849 
1850 /*
1851  * global function for interested FRU drivers to register a callback function,
1852  * to be called when FRU presence status changes.
1853  */
1854 scsb_fru_status_t
1855 scsb_fru_register(void (*cb_func)(void *, scsb_fru_event_t, scsb_fru_status_t),
1856                         void *soft_ptr, fru_id_t fru_id)
1857 {
1858         struct scsb_cb_entry    *cbe_ptr;
1859 
1860         if (scsb_debug & 0x00800001) {
1861                 cmn_err(CE_NOTE,
1862                     "scsb_fru_register: FRU_ID 0x%x", (int)fru_id);
1863         }
1864         if (!(scsb_global_state & SCSB_UP)) {
1865                 return (FRU_NOT_AVAILABLE);
1866         }
1867         if (cb_func == NULL || fru_id == (fru_id_t)0)
1868                 return (FRU_NOT_AVAILABLE);
1869         if (scsb_cb_table == NULL)
1870                 scsb_cb_table = (struct scsb_cb_entry *)
1871                     kmem_zalloc(sizeof (struct scsb_cb_entry), KM_SLEEP);
1872         cbe_ptr = scsb_cb_table;
1873         while (cbe_ptr->cb_softstate_ptr != NULL) {
1874                 if (cbe_ptr->cb_next == (struct scsb_cb_entry *)NULL) {
1875                         cbe_ptr->cb_next = (struct scsb_cb_entry *)
1876                             kmem_zalloc(sizeof (struct scsb_cb_entry),
1877                             KM_SLEEP);
1878                         cbe_ptr = cbe_ptr->cb_next;
1879                         break;
1880                 }
1881                 cbe_ptr = cbe_ptr->cb_next;
1882         }
1883         cbe_ptr->cb_softstate_ptr = soft_ptr;
1884         cbe_ptr->cb_fru_id = fru_id;
1885         cbe_ptr->cb_func = cb_func;
1886         cbe_ptr->cb_next = (struct scsb_cb_entry *)NULL;
1887         cbe_ptr->cb_fru_ptr = find_fru_info(fru_id);
1888 #ifdef DEBUG
1889         scsb_cb_count++;
1890 #endif
1891         if (scsb_debug & 0x00800000) {
1892                 cmn_err(CE_NOTE,
1893                     "scsb_fru_register: FRU_ID 0x%x, status=%d",
1894                     (int)fru_id,
1895                     (cbe_ptr->cb_fru_ptr == (fru_info_t *)NULL) ?
1896                     0xff : cbe_ptr->cb_fru_ptr->fru_status);
1897         }
1898         if (cbe_ptr->cb_fru_ptr == (fru_info_t *)NULL)
1899                 return (FRU_NOT_AVAILABLE);
1900         if (cbe_ptr->cb_fru_ptr->fru_status & FRU_PRESENT)
1901                 return (FRU_PRESENT);
1902         return (FRU_NOT_PRESENT);
1903 }
1904 
1905 void
1906 scsb_fru_unregister(void *soft_ptr, fru_id_t fru_id)
1907 {
1908         struct scsb_cb_entry    *prev_ptr, *cbe_ptr;
1909 
1910         if (scsb_debug & 0x00800001) {
1911                 cmn_err(CE_NOTE, "scsb_fru_unregister(0x%p, 0x%x)",
1912                     soft_ptr, (int)fru_id);
1913         }
1914         if ((cbe_ptr = scsb_cb_table) == NULL || fru_id == (fru_id_t)0)
1915                 return;
1916         prev_ptr = cbe_ptr;
1917         do {
1918                 if (cbe_ptr->cb_softstate_ptr == soft_ptr &&
1919                     cbe_ptr->cb_fru_id == fru_id) {
1920                         if (cbe_ptr == scsb_cb_table)
1921                                 scsb_cb_table = cbe_ptr->cb_next;
1922                         else
1923                                 prev_ptr->cb_next = cbe_ptr->cb_next;
1924                         kmem_free(cbe_ptr, sizeof (struct scsb_cb_entry));
1925 #ifdef DEBUG
1926                         scsb_cb_count--;
1927 #endif
1928                         return;
1929                 }
1930                 prev_ptr = cbe_ptr;
1931         } while ((cbe_ptr = cbe_ptr->cb_next) != NULL);
1932 }
1933 
1934 /*
1935  * global function for interested FRU drivers to call to check
1936  * FRU presence status.
1937  */
1938 scsb_fru_status_t
1939 scsb_fru_status(uchar_t fru_id)
1940 {
1941         fru_info_t              *fru_ptr;
1942 
1943         fru_ptr = find_fru_info(fru_id);
1944         if (scsb_debug & 0x00800001) {
1945                 cmn_err(CE_NOTE, "scsb_fru_status(0x%x): status=0x%x",
1946                     fru_id, (fru_ptr == (fru_info_t *)NULL) ? 0xff :
1947                     (int)fru_ptr->fru_status);
1948         }
1949         if (fru_ptr == (fru_info_t *)NULL)
1950                 return (FRU_NOT_AVAILABLE);
1951         return (fru_ptr->fru_status);
1952 }
1953 
1954 /*
1955  * Global function for the other interruptible FRU device sharing the
1956  * same interrupt line to register the interrupt handler with scsb.
1957  * This enables all the handlers to be called whenever the interrupt
1958  * line is asserted by anyone shaing the interrupt line.
1959  */
1960 
1961 /*
1962  * The interrupt handler table is currently a linked list. probably a
1963  * hash table will be more efficient. Usage of these facilities can
1964  * happen even before scsb is attached, so do not depend on scsb
1965  * structure being present.
1966  */
1967 struct fru_intr_entry {
1968         void    *softstate_ptr;
1969         int     (*fru_intr_handler)(void *);
1970         fru_id_t        fru_id;
1971         struct fru_intr_entry   *fru_intr_next;
1972 } *fru_intr_table = NULL;
1973 
1974 int
1975 scsb_intr_register(int (*intr_handler)(void *), void * soft_ptr,
1976                 fru_id_t fru_id)
1977 {
1978         struct fru_intr_entry *intr_table_entry;
1979         intr_table_entry = (struct fru_intr_entry *)
1980             kmem_zalloc(sizeof (struct fru_intr_entry), KM_SLEEP);
1981 
1982         if (intr_table_entry == NULL) {
1983                 return (DDI_FAILURE);
1984         }
1985 
1986         if (intr_handler == NULL || soft_ptr == NULL || fru_id == 0) {
1987                 kmem_free(intr_table_entry, sizeof (struct fru_intr_entry));
1988                 return (DDI_FAILURE);
1989         }
1990 
1991         intr_table_entry->softstate_ptr = soft_ptr;
1992         intr_table_entry->fru_intr_handler = intr_handler;
1993         intr_table_entry->fru_id = fru_id;
1994         intr_table_entry->fru_intr_next = fru_intr_table;
1995         fru_intr_table = intr_table_entry;
1996 
1997         return (DDI_SUCCESS);
1998 }
1999 
2000 /*
2001  * Removed interrupt_handler of fru from interrupt call chain
2002  */
2003 void
2004 scsb_intr_unregister(fru_id_t fru_id)
2005 {
2006         struct fru_intr_entry *intr_entry = fru_intr_table,
2007             *prev_entry = intr_entry;
2008 
2009         if (fru_id == 0) {
2010                 return;
2011         }
2012 
2013         do {
2014                 if (intr_entry->fru_id == fru_id) {
2015                         /* found a match, remove entry */
2016                         if (intr_entry == fru_intr_table)
2017                                 fru_intr_table = intr_entry->fru_intr_next;
2018                         else
2019                                 prev_entry->fru_intr_next =
2020                                     intr_entry->fru_intr_next;
2021 
2022                         kmem_free(intr_entry,
2023                             sizeof (struct fru_intr_entry));
2024                         return;
2025                 }
2026                 prev_entry = intr_entry;
2027 
2028         } while ((intr_entry = intr_entry->fru_intr_next) != NULL);
2029 }
2030 
2031 /*
2032  * Invoke all the registered interrupt handlers, whenever scsb_intr
2033  * is called. This function will go through the list of entries
2034  * in the fru interrupt table and invoke each function. Returns
2035  * whether interrupt is claimed or unclaimed.
2036  */
2037 static int
2038 scsb_invoke_intr_chain()
2039 {
2040         int retval = DDI_INTR_UNCLAIMED;
2041         struct fru_intr_entry *intr_entry = fru_intr_table;
2042 
2043         while (intr_entry != NULL) {
2044                 retval = (*intr_entry->
2045                     fru_intr_handler)(intr_entry->softstate_ptr);
2046                 if (retval == DDI_INTR_CLAIMED) {
2047                         return (retval);
2048                 }
2049 
2050                 intr_entry = intr_entry->fru_intr_next;
2051         }
2052 
2053         return (retval);
2054 }
2055 
2056 
2057 /*
2058  * The scsb_ioc_rdwr_t is similar enough to an i2c_transfer_t that we can
2059  * translate the structures and use the i2c_transfer() service.
2060  */
2061 static void
2062 sm_ioc_rdwr(queue_t *q, mblk_t *mp, int op)
2063 {
2064         scsb_state_t    *scsb = (scsb_state_t *)q->q_ptr;
2065         struct iocblk   *iocp = (struct iocblk *)mp->b_rptr;
2066         scsb_ioc_rdwr_t *iocrdwrp;
2067         int             len, error;
2068         uchar_t         *uc, reg;
2069 
2070         if (scsb_debug & 0x0040)
2071                 cmn_err(CE_CONT, "sm_ioc_rdwr[%d]:", scsb->scsb_instance);
2072         iocrdwrp  = (scsb_ioc_rdwr_t *)mp->b_cont->b_rptr;
2073         if (op == I2C_WR) {
2074                 len = iocrdwrp->ioc_wlen;
2075                 uc = iocrdwrp->ioc_wbuf;
2076         } else {
2077                 len = iocrdwrp->ioc_rlen;
2078                 uc = iocrdwrp->ioc_rbuf;
2079         }
2080         /*
2081          * Check SCB register index boundries and requested len of read/write
2082          */
2083         reg = iocrdwrp->ioc_regindex;
2084         if (reg < SCSB_REG_ADDR_START || (reg + len) >
2085             (SCSB_REG_ADDR_START + SCTRL_TOTAL_NUMREGS))
2086                 error = EINVAL;
2087         else
2088                 error = scsb_rdwr_register(scsb, op, reg, len, uc, 1);
2089         if (error) {
2090                 if (scsb_debug & 0x0042)
2091                         cmn_err(CE_WARN,
2092                             "sm_ioc_rdwr: rdwr_register failure: %d", error);
2093                 mp->b_datap->db_type = M_IOCNAK;
2094         } else
2095                 mp->b_datap->db_type = M_IOCACK;
2096         iocp->ioc_error = error;
2097         qreply(q, mp);
2098 }
2099 
2100 /*
2101  * names for (scsb_utype_t) FRU types
2102  */
2103 static char *led_name[SCSB_LED_TYPES] = { "NOK", "OK" };
2104 static char *unit_type_name[SCSB_UNIT_TYPES] = {
2105         "SLOT", "PDU", "POWER SUPPLY", "DISK", "FAN", "ALARM",
2106         "SCB",  "SSB", "CFTM", "CRTM", "PRTM"
2107 };
2108 
2109 /*
2110  * Discover the register and bit-offset for LEDs and Reset registers,
2111  * according to unit_type, unit_number, and led_type.
2112  */
2113 static int
2114 scsb_get_led_regnum(scsb_state_t        *scsb,
2115                     scsb_uinfo_t        *suip,
2116                     uchar_t             *regptr,
2117                     int                 *unitptr,
2118                     scsb_led_t          led_type)
2119 {
2120         int             code, base, error;
2121 
2122         /* OK here means presence (OK) LEDs */
2123         if (led_type == OK)
2124                 base = (SCTRL_LED_OK_BASE);
2125         else
2126                 base = (SCTRL_LED_NOK_BASE);
2127         error = 0;
2128         if (scsb_debug & 0x0100) {
2129                 cmn_err(CE_NOTE, "get_led_regnum: suip <%x, %x, %x, %x>\n",
2130                     suip->unit_type, suip->unit_number,
2131                     led_type, suip->unit_state);
2132         }
2133         /*
2134          * It was requested that the scsb driver allow accesses to SCB device
2135          * registers for FRUs that cannot be present.
2136          * So except for SLOTs, if the unit_number check fails, we now
2137          * just log a message, but ONLY if scsb_debug error messages are
2138          * enabled.
2139          */
2140         switch (suip->unit_type) {
2141         case SLOT:
2142                 if (suip->unit_number < 1 || suip->unit_number >
2143                     ((scsb->scsb_state & SCSB_IS_TONGA) ?
2144                     TG_MAX_SLOTS : MC_MAX_SLOTS)) {
2145                         error = EINVAL;
2146                         break;
2147                 }
2148                 code = FRU_UNIT_TO_EVCODE(SLOT, suip->unit_number);
2149                 break;
2150 
2151         case PDU:
2152                 if (suip->unit_number < 1 || suip->unit_number >
2153                     ((scsb->scsb_state & SCSB_IS_TONGA) ?
2154                     TG_MAX_PDU : MC_MAX_PDU)) {
2155                         if (scsb_debug & 0x0002) {
2156                                 cmn_err(CE_WARN,
2157                                     "get_led_regnum: unit number %d "
2158                                     "is out of range", suip->unit_number);
2159                         }
2160                         error = EINVAL;
2161                         break;
2162                 }
2163                 code = FRU_UNIT_TO_EVCODE(PDU, suip->unit_number);
2164                 break;
2165 
2166         case PS:
2167                 if ((suip->unit_number < 1 || suip->unit_number >
2168                     ((scsb->scsb_state & SCSB_IS_TONGA) ?
2169                     TG_MAX_PS : MC_MAX_PS))) {
2170                         if (scsb_debug & 0x0002) {
2171                                 cmn_err(CE_WARN,
2172                                     "get_led_regnum: unit number %d "
2173                                     "is out of range", suip->unit_number);
2174                         }
2175                         error = EINVAL;
2176                         break;
2177                 }
2178                 code = FRU_UNIT_TO_EVCODE(PS, suip->unit_number);
2179                 break;
2180 
2181         case DISK:
2182                 if ((suip->unit_number < 1 || suip->unit_number >
2183                     ((scsb->scsb_state & SCSB_IS_TONGA) ?
2184                     TG_MAX_DISK : MC_MAX_DISK))) {
2185                         if (scsb_debug & 0x0002) {
2186                                 cmn_err(CE_WARN,
2187                                     "get_led_regnum: unit number %d "
2188                                     "is out of range", suip->unit_number);
2189                         }
2190                         if (!(scsb_debug & 0x20000000)) {
2191                                 error = EINVAL;
2192                                 break;
2193                         }
2194                 }
2195                 code = FRU_UNIT_TO_EVCODE(DISK, suip->unit_number);
2196                 break;
2197 
2198         case FAN:
2199                 if (suip->unit_number < 1 || suip->unit_number >
2200                     ((scsb->scsb_state & SCSB_IS_TONGA) ?
2201                     TG_MAX_FAN : MC_MAX_FAN)) {
2202                         if (scsb_debug & 0x0002) {
2203                                 cmn_err(CE_WARN,
2204                                     "get_led_regnum: unit number %d "
2205                                     "is out of range", suip->unit_number);
2206                         }
2207                         error = EINVAL;
2208                         break;
2209                 }
2210                 code = FRU_UNIT_TO_EVCODE(FAN, suip->unit_number);
2211                 break;
2212 
2213         case CFTM:
2214                 if (suip->unit_number < 1 || suip->unit_number >
2215                     ((scsb->scsb_state & SCSB_IS_TONGA) ?
2216                     TG_MAX_CFTM : MC_MAX_CFTM)) {
2217                         if (scsb_debug & 0x0002) {
2218                                 cmn_err(CE_WARN,
2219                                     "get_led_regnum: unit number %d "
2220                                     "is out of range", suip->unit_number);
2221                         }
2222                         error = EINVAL;
2223                         break;
2224                 }
2225                 code = FRU_UNIT_TO_EVCODE(CFTM, suip->unit_number);
2226                 break;
2227 
2228         case SCB:
2229                 if (suip->unit_number < 1 || suip->unit_number >
2230                     ((scsb->scsb_state & SCSB_IS_TONGA) ?
2231                     TG_MAX_SCB : MC_MAX_SCB)) {
2232                         if (scsb_debug & 0x0002) {
2233                                 cmn_err(CE_WARN,
2234                                     "get_led_regnum: unit number %d "
2235                                     "is out of range", suip->unit_number);
2236                         }
2237                         error = EINVAL;
2238                         break;
2239                 }
2240                 code = FRU_UNIT_TO_EVCODE(SCB, suip->unit_number);
2241                 break;
2242 
2243         case ALARM:
2244                 error = EINVAL;
2245                 break;
2246 
2247         default:
2248                 if (scsb_debug & 0x0102) {
2249                         cmn_err(CE_WARN,
2250                             "scsb_get_led_regnum(): unknown unit type %d",
2251                             suip->unit_type);
2252                 }
2253                 error = EINVAL;
2254                 break;
2255         }
2256         if (!error) {
2257                 *unitptr = FRU_OFFSET(code, base);
2258                 *regptr = FRU_REG_ADDR(code, base);
2259                 if (scsb_debug & 0x0100) {
2260                         cmn_err(CE_NOTE, "get_led_regnum: unitptr=%x, "
2261                             "regptr=%x, code = %x\n",
2262                             *unitptr, *regptr, code);
2263                 }
2264         }
2265         return (error);
2266 }
2267 
2268 /*
2269  * P1.0 and P1.5
2270  * Map 1.0 Tonga Slot Numbers: SCB to user interface and back.
2271  * User interface means positional slot numbers, as on P1.0 SSB,
2272  * which are used by hpcsvc/hsc and kstat/ioctl interfaces.
2273  */
2274 
2275 /* HSC slotnum (Positional SLotnum) to SCB CFG bit-offset */
2276 static  int     psl2sco[TG_MAX_SLOTS + 1] = { -1 };
2277 
2278 /*
2279  * MAP Positional (HSC) slot number to SCB CFG register bit-offset
2280  */
2281 static int
2282 tonga_pslotnum_to_cfgbit(scsb_state_t *scsb, int sln)
2283 {
2284         int     base = SCTRL_SYSCFG_BASE;
2285         if (!(scsb->scsb_state & SCSB_IS_TONGA)) {
2286                 return (sln);
2287         }
2288         if (sln < 1 || sln > TG_MAX_SLOTS) {
2289                 return (sln);
2290         }
2291         /*
2292          * Should move this to _init(), but for now,
2293          * check for initialized table
2294          */
2295         if (psl2sco[0]) {
2296                 psl2sco[0] = 0;
2297                 psl2sco[1] = FRU_OFFSET(SCTRL_EVENT_SLOT5, base);
2298                 psl2sco[2] = FRU_OFFSET(SCTRL_EVENT_SLOT2, base);
2299                 psl2sco[3] = FRU_OFFSET(SCTRL_EVENT_SLOT1, base);
2300                 psl2sco[4] = FRU_OFFSET(SCTRL_EVENT_SLOT3, base);
2301                 psl2sco[5] = FRU_OFFSET(SCTRL_EVENT_SLOT4, base);
2302         }
2303 #ifdef DEBUG
2304         if (scsb_debug & 0x10000000) {
2305                 cmn_err(CE_NOTE, "tonga_pslotnum_to_cfgbit: old/new: %d/%d",
2306                     sln, psl2sco[sln]);
2307         }
2308 #endif
2309         return (psl2sco[sln]);
2310 }
2311 
2312 /* positional slotnum to SCB slotnum */
2313 static  int     psl2ssl[6] = {
2314         0, 5, 2, 1, 3, 4
2315 };
2316 
2317 /* SCB slotnum to positional slotnum */
2318 static  int     ssl2psl[6] = {
2319         0, 3, 2, 4, 5, 1
2320 };
2321 
2322 /*
2323  * P1.0 and P1.5
2324  * HSC Slot numbers (physical positions or positional slotnum)
2325  *  to
2326  * SCB slot numbers (reset,present,healthy)
2327  *
2328  * These requests come mainly from application interface and
2329  * HSC using the scsb_uinfo_t structure.
2330  */
2331 static void
2332 tonga_slotnum_check(scsb_state_t *scsb, scsb_uinfo_t *suip)
2333 {
2334         if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state &
2335             (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) {
2336                 return;
2337         }
2338         if (suip->unit_number < 1 || suip->unit_number > TG_MAX_SLOTS) {
2339                 return;
2340         }
2341 #ifdef DEBUG
2342         if (scsb_debug & 0x10000000) {
2343                 cmn_err(CE_NOTE, "tonga_slotnum_check: old/new: %d/%d",
2344                     suip->unit_number, psl2ssl[suip->unit_number]);
2345         }
2346 #endif
2347         suip->unit_number = psl2ssl[suip->unit_number];
2348 }
2349 
2350 /*
2351  * P1.0 and P1.5
2352  */
2353 static int
2354 tonga_psl_to_ssl(scsb_state_t *scsb, int slotnum)
2355 {
2356         if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state &
2357             (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) {
2358                 return (slotnum);
2359         }
2360         if (slotnum < 1 || slotnum > TG_MAX_SLOTS) {
2361                 return (slotnum);
2362         }
2363 #ifdef DEBUG
2364         if (scsb_debug & 0x10000000) {
2365                 cmn_err(CE_NOTE, "tonga_psl_to_ssl: old/new: %d/%d",
2366                     slotnum, psl2ssl[slotnum]);
2367         }
2368 #endif
2369         return (psl2ssl[slotnum]);
2370 }
2371 
2372 /*
2373  * P1.0 and P1.5
2374  */
2375 static int
2376 tonga_ssl_to_psl(scsb_state_t *scsb, int slotnum)
2377 {
2378         if (!(scsb->scsb_state & SCSB_IS_TONGA && scsb->scsb_state &
2379             (SCSB_P10_PROM | SCSB_P15_PROM | SCSB_P20_PROM))) {
2380                 return (slotnum);
2381         }
2382         if (slotnum < 1 || slotnum > TG_MAX_SLOTS) {
2383                 return (slotnum);
2384         }
2385 #ifdef DEBUG
2386         if (scsb_debug & 0x10000000) {
2387                 cmn_err(CE_NOTE, "tonga_ssl_to_psl: old/new: %d/%d",
2388                     slotnum, ssl2psl[slotnum]);
2389         }
2390 #endif
2391         return (ssl2psl[slotnum]);
2392 }
2393 /*
2394  * tonga_slotnum_led_shift: this function remaps slot bits ONLY for Slots 1-5
2395  * and ONLY for the register sets in bit-offset groups 1,2:
2396  * LEDs, Confg/Status, Reset, BrdHlthy
2397  *
2398  * IN  bits: SCB slot numbers (led,reset,present,healthy)
2399  *  to
2400  * OUT bits: HSC Slot numbers (positional slot numbers as marked on the SSB)
2401  */
2402 static uchar_t
2403 tonga_slotnum_led_shift(scsb_state_t *scsb, uchar_t data)
2404 {
2405         int     i;
2406         uchar_t mask, new_data = 0;
2407 #ifdef DEBUG
2408         uchar_t old_data = data;
2409 #endif
2410         if (!(scsb->scsb_state & SCSB_IS_TONGA)) {
2411                 return (data);
2412         }
2413         /*
2414          * P1.0 and P1.5 slot 1-5 offsets are the same
2415          */
2416         for (i = 1; i <= TG_MAX_SLOTS; ++i) {
2417                 mask = 1 << (i - 1);
2418                 switch (i) {
2419                 case 1:         /* map to slot 3 */
2420                         new_data |= (data & mask) << 2;
2421                         data &= ~(mask);
2422                         break;
2423                 case 2:         /* map to slot 2 */
2424                         new_data |= (data & mask);
2425                         data &= ~(mask);
2426                         break;
2427                 case 3:         /* map to slot 4 */
2428                 case 4:         /* map to slot 5 */
2429                         new_data |= (data & mask) << 1;
2430                         data &= ~(mask);
2431                         break;
2432                 case 5:         /* map to slot 1 */
2433                         new_data |= (data & mask) >> 4;
2434                         data &= ~(mask);
2435                         break;
2436                 }
2437         }
2438         new_data |= data;       /* set any remaining bits */
2439 #ifdef DEBUG
2440         if (scsb_debug & 0x10000000) {
2441                 cmn_err(CE_NOTE, "tonga_slotnum_led_shift: old/new: 0x%x/0x%x",
2442                     old_data, new_data);
2443         }
2444 #endif
2445         return (new_data);
2446 }
2447 
2448 /*
2449  * P1.0 and P1.5
2450  */
2451 int
2452 scsb_led_get(scsb_state_t *scsb, scsb_uinfo_t *suip, scsb_led_t led_type)
2453 {
2454         int             error;
2455         int             unit_number;
2456         uchar_t         reg;
2457         int             index;
2458 
2459         /*
2460          * Allow access to shadow registers even though SCB is removed
2461          *
2462          * if (scsb->scsb_state & SCSB_FROZEN) {
2463          *      return (EAGAIN);
2464          * }
2465          */
2466         if (suip == NULL) {
2467                 return (EFAULT);
2468         }
2469         if (led_type == NOUSE) {
2470                 led_type = suip->led_type;
2471         }
2472         if (led_type != OK && led_type != NOK) {
2473                 cmn_err(CE_NOTE, "scsb_led_get(%d): unknown led type %x",
2474                     scsb->scsb_instance, led_type);
2475                 return (EINVAL);
2476         }
2477         error = 0;
2478         if (scsb_debug & 0x0100) {
2479                 cmn_err(CE_NOTE, "scsb_led_get: %s %s %d",
2480                     led_name[led_type], unit_type_name[suip->unit_type],
2481                     suip->unit_number);
2482         }
2483         /*
2484          * Map to Tonga Slot Number, if NOT P1.0 SCB
2485          * P1.0 SSB workaround
2486          */
2487         if (suip->unit_type == SLOT && !(scsb->scsb_state & SCSB_P10_PROM)) {
2488                 tonga_slotnum_check(scsb, suip);
2489         }
2490         /* discover the register and index we need to operate on */
2491         if ((error = scsb_get_led_regnum(scsb, suip, &reg, &unit_number,
2492             led_type)) == 0) {
2493                 index = SCSB_REG_INDEX(reg);
2494                 mutex_enter(&scsb->scsb_mutex);
2495                 if (scsb->scsb_data_reg[index] & (1 << unit_number)) {
2496                         suip->unit_state = ON;
2497                         if (led_type == OK) {
2498                                 int code = FRU_UNIT_TO_EVCODE(suip->unit_type,
2499                                     suip->unit_number);
2500                                 reg = FRU_REG_ADDR(code, SCTRL_BLINK_OK_BASE);
2501                                 index = SCSB_REG_INDEX(reg);
2502                                 if (scsb->scsb_data_reg[index] &
2503                                     (1 << unit_number))
2504                                         suip->unit_state = BLINK;
2505                         }
2506                 } else {
2507                         suip->unit_state = OFF;
2508                 }
2509                 mutex_exit(&scsb->scsb_mutex);
2510         }
2511         return (error);
2512 }
2513 
2514 int
2515 scsb_led_set(scsb_state_t *scsb, scsb_uinfo_t *suip, scsb_led_t led_type)
2516 {
2517         int             error;
2518         int             unit_number;
2519         uchar_t         reg;
2520         int             code, index;
2521 
2522         /* we should really allow led state changes while frozen... */
2523         if (scsb->scsb_state & SCSB_FROZEN)
2524                 return (EAGAIN);
2525 
2526         if (suip == NULL) {
2527                 return (EFAULT);
2528         }
2529 
2530         /*
2531          * Sanity check, make sure we got plausible values for set command.
2532          * Also check for application only control of slot leds using NOUSE
2533          * interface
2534          */
2535         if (led_type == NOUSE) {
2536                 led_type = suip->led_type;
2537         } else if (suip->unit_type == SLOT &&
2538             scsb->scsb_state & SCSB_APP_SLOTLED_CTRL &&
2539             !(scsb->scsb_state &
2540             (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
2541                 /*
2542                  * kernel modules using this interface need to think they are
2543                  * succeeding, so we won't return an error for this
2544                  * application configuration
2545                  */
2546                 return (0);
2547         }
2548         if (led_type != OK && led_type != NOK) {
2549                 return (EINVAL);
2550         }
2551         if (suip->unit_state != OFF && suip->unit_state != ON &&
2552             suip->unit_state != BLINK) {
2553                 return (EINVAL);
2554         }
2555         if (suip->unit_state == BLINK) {
2556                 if (led_type != OK)
2557                         return (EINVAL);
2558                 if (suip->unit_type != SLOT && scsb->scsb_state &
2559                     (SCSB_P06_PROM | SCSB_P10_PROM))
2560                         return (EINVAL);
2561         }
2562         if (scsb_debug & 0x0100) {
2563                 cmn_err(CE_NOTE,
2564                     "scsb_led_set: led %s, type %s, unit %d, state %s",
2565                     led_name[led_type],
2566                     unit_type_name[suip->unit_type], suip->unit_number,
2567                     suip->unit_state == ON ? "ON":
2568                     suip->unit_state == OFF ? "OFF": "BLINK");
2569         }
2570         /*
2571          * Map to Tonga Slot Number, if NOT P1.0 SCB
2572          * P1.0 SSB workaround
2573          */
2574         if (suip->unit_type == SLOT && !(scsb->scsb_state & SCSB_P10_PROM)) {
2575                 tonga_slotnum_check(scsb, suip);
2576         }
2577         /*
2578          * discover the register and index we need to access
2579          */
2580         if ((error = scsb_get_led_regnum(scsb, suip, &reg, &unit_number,
2581             led_type)) == 0) {
2582                 index = SCSB_REG_INDEX(reg);
2583                 mutex_enter(&scsb->scsb_mutex);
2584                 if (suip->unit_state == ON || suip->unit_state == BLINK)
2585                         scsb->scsb_data_reg[index] |=  (1 << unit_number);
2586                 else
2587                         scsb->scsb_data_reg[index] &= ~(1 << unit_number);
2588 
2589                 if (scsb_debug & 0x0100) {
2590                         cmn_err(CE_NOTE, "Writing %x to Reg %x",
2591                             scsb->scsb_data_reg[index], reg);
2592                 }
2593                 error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
2594                     &scsb->scsb_data_reg[index], 1);
2595                 if (error) {
2596                         cmn_err(CE_WARN, "%s#%d: Could not Update %s LEDs.",
2597                             ddi_driver_name(scsb->scsb_dev),
2598                             ddi_get_instance(scsb->scsb_dev),
2599                             led_name[led_type]);
2600                         goto ledset_done;
2601                 }
2602                 if (led_type != OK ||
2603                     (IS_SCB_P10 && suip->unit_type != SLOT) ||
2604                     suip->unit_type == ALARM ||
2605                     suip->unit_type == SSB ||
2606                     suip->unit_type == CRTM ||
2607                     suip->unit_type == PRTM) {
2608                         goto ledset_done;
2609                 }
2610                 code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
2611                 reg = FRU_REG_ADDR(code, SCTRL_BLINK_OK_BASE);
2612                 index = SCSB_REG_INDEX(reg);
2613                 if (suip->unit_state == BLINK)
2614                         scsb->scsb_data_reg[index] |=  (1 << unit_number);
2615                 else
2616                         scsb->scsb_data_reg[index] &= ~(1 << unit_number);
2617                 if (scsb_debug & 0x0100) {
2618                         cmn_err(CE_NOTE, "Writing %x to Reg %x",
2619                             scsb->scsb_data_reg[index], reg);
2620                 }
2621                 error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
2622                     &scsb->scsb_data_reg[index], 1);
2623                 if (error) {
2624                         cmn_err(CE_WARN, "%s#%d: Could not Blink %s LEDs.",
2625                             ddi_driver_name(scsb->scsb_dev),
2626                             ddi_get_instance(scsb->scsb_dev),
2627                             led_name[led_type]);
2628                 }
2629 ledset_done:
2630                 mutex_exit(&scsb->scsb_mutex);
2631         }
2632         return (error);
2633 }
2634 
2635 struct ps_auto_on {
2636         scsb_state_t    *scsb;
2637         scsb_utype_t    utype;
2638         scsb_unum_t     unit;
2639 };
2640 
2641 static struct ps_auto_on pao;
2642 
2643 static void
2644 scsb_ps_auto_on(void *arg)
2645 {
2646         struct ps_auto_on       *ppao = (struct ps_auto_on *)arg;
2647         uchar_t                 rmask = 0;
2648         uchar_t                 ondata, sysreg;
2649         int                     tmp, bit_index;
2650         /*
2651          * Turn on the PSU.
2652          * Notice: not checking Power Supply unit number
2653          */
2654         bit_index = SCTRL_SYS_PS_ON_BASE + (ppao->unit - 1);
2655         ondata = 1 << SYS_OFFSET(bit_index);
2656         tmp = SYS_REG_INDEX(bit_index, SCTRL_SYS_CMD_BASE);
2657         sysreg = SCSB_REG_ADDR(tmp);
2658         if (scsb_write_mask(ppao->scsb, sysreg, rmask, ondata, (uchar_t)0)) {
2659                 cmn_err(CE_WARN, "scsb%d: " "I2C TRANSFER Failed",
2660                     ppao->scsb->scsb_instance);
2661         }
2662         ppao->scsb->scsb_btid = 0;
2663 }
2664 
2665 /*
2666  * called with mutex held from
2667  * scsb_attach()        with int_fru_ptr == NULL
2668  * scsb_intr()          with int_fru_ptr == info for FRU that caused interrupt
2669  */
2670 static int
2671 scsb_set_scfg_pres_leds(scsb_state_t *scsb, fru_info_t *int_fru_ptr)
2672 {
2673         int             i, error = 0;
2674         int             cfg_idx, led_idx, blink_idx, lid, bid;
2675         int             cfg_bit, led_bit;
2676         uchar_t         *puc, reg, led_reg, led_data[SCSB_LEDDATA_REGISTERS];
2677         uchar_t         blink_bit, blink_reg, blink[SCSB_LEDDATA_REGISTERS];
2678         uchar_t         update_reg = 0;
2679         scsb_utype_t    fru_type;
2680         fru_info_t      *fru_ptr;
2681 
2682         if (scsb->scsb_state & SCSB_FROZEN &&
2683             !(scsb->scsb_state & SCSB_IN_INTR)) {
2684                 return (EAGAIN);
2685         }
2686         for (i = 0; i < SCTRL_LED_OK_NUMREGS; ++i) {
2687                 led_data[i] = 0;
2688                 blink[i] = 0;
2689         }
2690         led_reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
2691         reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
2692         lid = SCSB_REG_INDEX(led_reg);          /* the LED Index Delta */
2693         bid = SCSB_REG_INDEX(reg);              /* the Blink Index Delta */
2694         blink_reg = 0;
2695         if (int_fru_ptr != NULL) {
2696                 update_reg = int_fru_ptr->i2c_info->ledata_reg;
2697         }
2698         for (fru_type = 0; fru_type < SCSB_UNIT_TYPES; ++fru_type) {
2699                 int     is_present;
2700                 fru_ptr = mct_system_info.fru_info_list[fru_type];
2701                 for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
2702                         is_present = 0;
2703                         if (fru_type == SLOT && (scsb->scsb_state &
2704                             SCSB_APP_SLOTLED_CTRL))
2705                                 break;
2706                         if (fru_ptr->i2c_info == NULL)
2707                                 continue;
2708                         if ((led_reg = fru_ptr->i2c_info->ledata_reg) == 0) {
2709                                 /*
2710                                  * No LED exceptions: SSB,CRTM,PRTM
2711                                  */
2712                                 continue;
2713                         }
2714                         if (update_reg && update_reg != led_reg)
2715                                 continue;
2716                         led_idx = SCSB_REG_INDEX(led_reg) - lid;
2717                         led_bit = fru_ptr->i2c_info->ledata_bit;
2718                         if ((reg = fru_ptr->i2c_info->syscfg_reg) == 0) {
2719                                 if (fru_type != SCB)
2720                                         continue;
2721                                 /*
2722                                  * exception: SCB
2723                                  */
2724                                 if (scsb->scsb_state & SCSB_SCB_PRESENT) {
2725                                         led_data[led_idx] |= 1 << led_bit;
2726                                         is_present = 1;
2727                                 } else {
2728                                         led_data[led_idx] &= ~(1 << led_bit);
2729                                 }
2730                                 if (IS_SCB_P10)
2731                                         continue;
2732                         } else {
2733                                 cfg_idx = SCSB_REG_INDEX(reg);
2734                                 cfg_bit = fru_ptr->i2c_info->syscfg_bit;
2735                                 if (scsb->scsb_data_reg[cfg_idx] &
2736                                     (1 << cfg_bit)) {
2737                                         is_present = 1;
2738                                 }
2739                         }
2740                         if (is_present) {
2741                                 /*
2742                                  * If the FRU is a Power Supply, AND
2743                                  * the call is from scsb_attach() OR
2744                                  * from scsb_intr() and FRUs match,
2745                                  * turn it on.
2746                                  */
2747                                 if (fru_type == PS && (int_fru_ptr == NULL ||
2748                                     (int_fru_ptr == fru_ptr))) {
2749                                         pao.scsb = scsb;
2750                                         pao.utype = fru_type;
2751                                         pao.unit = fru_ptr->fru_unit;
2752 #ifdef  PS_ON_DELAY
2753                                         /*
2754                                          * HW recommended not implementing
2755                                          * this delay for now.
2756                                          * The code is tested on PSUs:
2757                                          *      -06
2758                                          *      -07 rev 2
2759                                          *      -08 plus
2760                                          */
2761                                         if (int_fru_ptr) {
2762                                                 /*
2763                                                  * Hot insertion, so give it
2764                                                  * the 3 seconds it needs to
2765                                                  * become stable
2766                                                  */
2767                                                 if (!scsb->scsb_btid)
2768                                                         scsb->scsb_btid =
2769                                                             timeout(
2770                                                             scsb_ps_auto_on,
2771                                                             &pao, (4 *
2772                                                             drv_usectohz(
2773                                                             1000000)));
2774                                         } else
2775 #endif  /* PS_ON_DELAY */
2776                                                 scsb_ps_auto_on((void *)&pao);
2777                                 }
2778                                 /*
2779                                  * Special SLOT handling.
2780                                  * Make sure the OK LED is on for the CPU Slot
2781                                  * and for the FTC (CFTM) Slot for MonteCarlo.
2782                                  * Both will report as FRU_PRESENT.
2783                                  */
2784                                 if (fru_type != SLOT || (fru_type == SLOT &&
2785                                     (fru_ptr->fru_type ==
2786                                     (scsb_utype_t)OC_CPU ||
2787                                     fru_ptr->fru_type ==
2788                                     (scsb_utype_t)OC_CTC))) {
2789                                         /*
2790                                          * Set OK (green) LED register bit
2791                                          */
2792                                         led_data[led_idx] |= 1 << led_bit;
2793                                 }
2794                                 if (IS_SCB_P10)
2795                                         continue;
2796                                 /*
2797                                  * Turn off BLINK register bit.
2798                                  * If single register update, then save the
2799                                  * corresponding blink register in blink_reg.
2800                                  */
2801                                 reg = fru_ptr->i2c_info->blink_reg;
2802                                 if (!reg)
2803                                         continue;
2804                                 blink_bit = fru_ptr->i2c_info->blink_bit;
2805                                 blink_idx = SCSB_REG_INDEX(reg) - bid;
2806                                 blink[blink_idx] |= 1 << blink_bit;
2807                                 if (update_reg && update_reg == led_reg)
2808                                         blink_reg = reg;
2809                         }
2810                 }
2811         }
2812         if (update_reg) {
2813                 reg = update_reg;
2814                 i = SCSB_REG_INDEX(reg);
2815                 puc = &led_data[i - lid];
2816                 i = 1;
2817         } else {
2818                 reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
2819                 puc = led_data;
2820                 i = SCTRL_LED_OK_NUMREGS;
2821         }
2822         if (scsb_debug & 0x0100) {
2823                 cmn_err(CE_NOTE, "scsb_set_scfg_pres(): writing %d bytes "
2824                     "to 0x%x", i, reg);
2825         }
2826         if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, i, puc, 1)) != 0) {
2827                 if (scsb_debug & 0x0102)
2828                         cmn_err(CE_NOTE, "scsb_set_scfg_pres(): "
2829                             "I2C write to 0x%x failed", reg);
2830                 error = EIO;
2831         } else {
2832                 /*
2833                  * Now see which BLINK bits need to be turned off for the
2834                  * corresponding OK LED bits.
2835                  */
2836                 reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
2837                 for (i = 0; i < SCTRL_BLINK_NUMREGS; ++i, ++reg) {
2838                         if (blink_reg && blink_reg != reg)
2839                                 continue;
2840                         if (!blink[i]) {
2841                                 continue;
2842                         }
2843                         if (scsb_debug & 0x0100) {
2844                                 cmn_err(CE_NOTE, "scsb_set_scfg_pres(): turn "
2845                                     "OFF Blink bits 0x%x in 0x%x",
2846                                     blink[i], reg);
2847                         }
2848                         if (scsb_write_mask(scsb, reg, 0, 0, blink[i])) {
2849                                 if (scsb_debug & 0x0102)
2850                                         cmn_err(CE_NOTE,
2851                                             "scsb_set_scfg_pres(): "
2852                                             "Write to 0x%x failed", reg);
2853                                 error = EIO;
2854                                 break;
2855                         }
2856                 }
2857         }
2858         return (error);
2859 }
2860 
2861 static int
2862 scsb_check_config_status(scsb_state_t *scsb)
2863 {
2864         int             error;
2865         uchar_t         reg;
2866         int             index, p06;
2867 
2868         if (scsb_debug & 0x0201) {
2869                 cmn_err(CE_NOTE, "scsb_check_config_status:");
2870         }
2871         /*
2872          * Base of register set
2873          */
2874         reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE);
2875         index = SCSB_REG_INDEX(reg);
2876         /*
2877          * SCB P0.6 workaround: read registers twice, use 2nd value set
2878          */
2879         mutex_enter(&scsb->scsb_mutex);
2880         p06 = 2;
2881         do {
2882                 if (error = scsb_rdwr_register(scsb, I2C_WR_RD, reg,
2883                     SCTRL_CFG_NUMREGS, &scsb->scsb_data_reg[index], 1)) {
2884                         break;
2885                 }
2886                 if (p06 == 1) {
2887                         if (scsb_debug & 0x0200)
2888                                 cmn_err(CE_NOTE,
2889                                 "scsb_check_config_status: P0.6 workaround");
2890                 }
2891                 /*
2892                  * If not P0.6 PROM, just break here
2893                  */
2894                 if (!(scsb->scsb_state & SCSB_P06_PROM))
2895                         break;
2896         } while (--p06);
2897         mutex_exit(&scsb->scsb_mutex);
2898 
2899         if (error == 0) {
2900                 if (!(scsb->scsb_state & SCSB_SCB_PRESENT))
2901                         scsb->scsb_state |= SCSB_SCB_PRESENT;
2902                 if (scsb_fru_op(scsb, SSB, 1, SCTRL_SYSCFG_BASE,
2903                     SCSB_FRU_OP_GET_BITVAL))
2904                         scsb->scsb_state |= SCSB_SSB_PRESENT;
2905                 else
2906                         scsb->scsb_state &= ~SCSB_SSB_PRESENT;
2907         }
2908         return (error);
2909 }
2910 
2911 static void
2912 scsb_set_topology(scsb_state_t *scsb)
2913 {
2914         int             i, t, index, unit, is_tonga = 0;
2915         int             alarm_slot_num, cpu_slot_num, ctc_slot_num;
2916         fru_info_t      *fru_ptr, *last_ptr, *acslot_ptr, *ctcslot_ptr;
2917         uchar_t         syscfg, led_reg, blink_reg, t_uchar;
2918         uchar_t         bit_num, led_bit, blink_bit;
2919         int             pad = 0;
2920 
2921         /*
2922          * Get the presence status from the SysConfigStatus shadow registers
2923          * in scsb->scsb_data_reg[]
2924          */
2925         /* Mid Plane */
2926         i = SYS_REG_INDEX(SCTRL_CFG_MPID0, SCTRL_SYSCFG_BASE);
2927         t_uchar = SCSB_REG_ADDR(i);
2928         index = SCSB_REG_INDEX(t_uchar);
2929         mct_system_info.mid_plane.fru_type = MIDPLANE;
2930         mct_system_info.mid_plane.fru_version = (fru_version_t)0;
2931         t = SYS_OFFSET(SCTRL_CFG_MPID0);
2932         mct_system_info.mid_plane.fru_id = (int)((scsb->scsb_data_reg[index] &
2933             (SCTRL_MPID_MASK << t)) >> t);
2934         switch (mct_system_info.mid_plane.fru_id) {
2935         case SCTRL_MPID_HALF:           /* Monte Carlo          */
2936                 if (scsb_debug & 0x00100005)
2937                         cmn_err(CE_NOTE, "scsb_set_topology: Monte Carlo");
2938                 cpu_slot_num = SC_MC_CPU_SLOT;
2939                 ctc_slot_num = SC_MC_CTC_SLOT;
2940                 alarm_slot_num = scsb->ac_slotnum = SC_MC_AC_SLOT;
2941                 mct_system_info.max_units[SLOT] = MC_MAX_SLOTS;
2942                 mct_system_info.max_units[ALARM] = MC_MAX_AC;
2943                 mct_system_info.max_units[DISK] = MC_MAX_DISK;
2944                 mct_system_info.max_units[FAN] = MC_MAX_FAN;
2945                 mct_system_info.max_units[PS] = MC_MAX_PS;
2946                 mct_system_info.max_units[PDU] = MC_MAX_PDU;
2947                 mct_system_info.max_units[SCB] = MC_MAX_SCB;
2948                 mct_system_info.max_units[SSB] = MC_MAX_SCB;
2949                 mct_system_info.max_units[CFTM] = MC_MAX_CFTM;
2950                 mct_system_info.max_units[CRTM] = MC_MAX_CRTM;
2951                 mct_system_info.max_units[PRTM] = MC_MAX_PRTM;
2952                 break;
2953         case SCTRL_MPID_QUARTER_NODSK:  /* Tonga w/o disk       */
2954         case SCTRL_MPID_QUARTER:        /* Tonga w/  disk       */
2955                 scsb->scsb_state |= SCSB_IS_TONGA;
2956                 is_tonga = 1;
2957                 ctc_slot_num = -1;
2958                 ctcslot_ptr = NULL;
2959                 if (scsb_debug & 0x00100005)
2960                         cmn_err(CE_NOTE, "scsb_set_topology: Tonga%s",
2961                             mct_system_info.mid_plane.fru_id ==
2962                             SCTRL_MPID_QUARTER_NODSK ?
2963                             ", no disk" : " with disk");
2964                 cpu_slot_num = SC_TG_CPU_SLOT;
2965                 alarm_slot_num = scsb->ac_slotnum = SC_TG_AC_SLOT;
2966                 mct_system_info.max_units[SLOT] = TG_MAX_SLOTS;
2967                 mct_system_info.max_units[ALARM] = TG_MAX_AC;
2968                 mct_system_info.max_units[DISK] = TG_MAX_DISK;
2969                 mct_system_info.max_units[FAN] = TG_MAX_FAN;
2970                 mct_system_info.max_units[PS] = TG_MAX_PS;
2971                 mct_system_info.max_units[PDU] = TG_MAX_PDU;
2972                 mct_system_info.max_units[SCB] = TG_MAX_SCB;
2973                 mct_system_info.max_units[SSB] = TG_MAX_SCB;
2974                 mct_system_info.max_units[CFTM] = TG_MAX_CFTM;
2975                 mct_system_info.max_units[CRTM] = TG_MAX_CRTM;
2976                 mct_system_info.max_units[PRTM] = TG_MAX_PRTM;
2977                 break;
2978         default:
2979                 cmn_err(CE_WARN, "%s#%d: Unknown MidPlane Id %x",
2980                     ddi_driver_name(scsb->scsb_dev),
2981                     ddi_get_instance(scsb->scsb_dev),
2982                     mct_system_info.mid_plane.fru_id);
2983                 if (scsb_debug & 0x00100005)
2984                         cmn_err(CE_NOTE, "scsb_set_topology: 0x%x: unknown!",
2985                             mct_system_info.mid_plane.fru_id);
2986                 return;
2987         }
2988         /*
2989          * cPCI Slots
2990          *
2991          * NOTE: The Tonga slot fru_unit needs to get mapped to the logical
2992          * slot number in slot_table[].  The field is not in the slot_table
2993          * at least until we know the format of the OBP slot table for the FCS
2994          * release.
2995          */
2996         mct_system_info.fru_info_list[SLOT] = (fru_info_t *)
2997             kmem_zalloc(sizeof (fru_info_t) *
2998             (mct_system_info.max_units[SLOT] + pad), KM_SLEEP);
2999         fru_ptr = mct_system_info.fru_info_list[SLOT];
3000         for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) {
3001                 int     iunit;
3002                 if (unit == cpu_slot_num) {
3003                         fru_ptr->fru_type = (scsb_utype_t)OC_CPU;
3004                 } else if (unit == ctc_slot_num) {
3005                         /* fru_ptr saved for Transition Card Presence check */
3006                         ctcslot_ptr = fru_ptr;
3007                         fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
3008                 } else if (unit == alarm_slot_num) {
3009                         /* fru_ptr saved for Alarm Card Presence check below */
3010                         acslot_ptr = fru_ptr;
3011                         fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
3012                 } else {
3013                         fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
3014                 }
3015                 /*
3016                  * Get the slot event code (t), then use it to get the
3017                  * slot bit-offsets for LED, BLINK, and SYSCFG registers.
3018                  * On a P1.5 Tonga, the internal slot number must be used to
3019                  * find the event code.
3020                  * The P1.0 Tonga does not get mapped due to a SSB difference.
3021                  */
3022                 if (IS_SCB_P15) {
3023                         iunit = tonga_psl_to_ssl(scsb, unit);
3024                         t = FRU_UNIT_TO_EVCODE(SLOT, iunit);
3025                 } else {
3026                         t = FRU_UNIT_TO_EVCODE(SLOT, unit);
3027                 }
3028                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3029                 blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3030                 blink_reg = FRU_REG_ADDR(t, SCTRL_BLINK_OK_BASE);
3031                 if (is_tonga && unit <= TG_MAX_SLOTS) {
3032                         bit_num = tonga_pslotnum_to_cfgbit(scsb, unit);
3033                 } else {
3034                         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3035                 }
3036                 /*
3037                  * get the registers addresses and shadow register index for
3038                  * the SYSCFG register
3039                  */
3040                 syscfg = FRU_REG_ADDR(t, SCTRL_SYSCFG_BASE);
3041                 index = SCSB_REG_INDEX(syscfg);
3042                 led_reg = FRU_REG_ADDR(t, SCTRL_LED_OK_BASE);
3043                 /*
3044                  * check and set presence status
3045                  */
3046                 if (scsb->scsb_state & SCSB_P06_PROM) {
3047                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3048                 } else if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3049                         fru_ptr->fru_status = FRU_PRESENT;
3050                 } else {
3051                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3052                 }
3053                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3054                 fru_ptr->fru_id = fru_id_table[event_to_index(
3055                     FRU_UNIT_TO_EVCODE(SLOT, unit))];
3056                 fru_ptr->fru_version = (fru_version_t)0;
3057                 fru_ptr->type_list = (fru_options_t *)NULL;
3058                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3059                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3060                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3061                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3062                 fru_ptr->i2c_info->ledata_reg = led_reg;
3063                 fru_ptr->i2c_info->ledata_bit = led_bit;
3064                 fru_ptr->i2c_info->blink_reg = blink_reg;
3065                 fru_ptr->i2c_info->blink_bit = blink_bit;
3066                 last_ptr = fru_ptr;
3067                 fru_ptr++;
3068                 last_ptr->next = fru_ptr;
3069         }
3070         last_ptr->next = (fru_info_t *)NULL;
3071         /*
3072          * PDU
3073          */
3074         mct_system_info.fru_info_list[PDU] = (fru_info_t *)
3075             kmem_zalloc(sizeof (fru_info_t) *
3076             (mct_system_info.max_units[PDU] + pad), KM_SLEEP);
3077         fru_ptr = mct_system_info.fru_info_list[PDU];
3078         for (unit = 1; unit <= mct_system_info.max_units[PDU]; ++unit) {
3079                 fru_ptr->fru_type = PDU;
3080                 /* SCB15 */
3081                 /*
3082                  * get the FRU event code (t), then use it to get the
3083                  * FRU bit-offsets for LED and SYSCFG registers
3084                  */
3085                 t = FRU_UNIT_TO_EVCODE(PDU, unit);
3086                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3087                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3088                 if (IS_SCB_P15) {
3089                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3090                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3091                         blink_reg = SCSB_REG_ADDR(i);
3092                 } else {
3093                         blink_bit = 0;
3094                         blink_reg = 0;
3095                 }
3096                 /*
3097                  * get the registers addresses and shadow register index for
3098                  * the SYSCFG register
3099                  */
3100                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3101                 syscfg = SCSB_REG_ADDR(i);
3102                 index = SCSB_REG_INDEX(syscfg);
3103                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3104                 led_reg = SCSB_REG_ADDR(i);
3105                 /*
3106                  * check and set presence status
3107                  */
3108                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3109                         fru_ptr->fru_status = FRU_PRESENT;
3110                         fru_ptr->fru_version = (fru_version_t)0;
3111                 } else {
3112                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3113                         fru_ptr->fru_version = (fru_version_t)0;
3114                 }
3115                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3116                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3117                 fru_ptr->type_list = (fru_options_t *)NULL;
3118                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3119                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3120                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3121                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3122                 fru_ptr->i2c_info->ledata_reg = led_reg;
3123                 fru_ptr->i2c_info->ledata_bit = led_bit;
3124                 fru_ptr->i2c_info->blink_reg = blink_reg;
3125                 fru_ptr->i2c_info->blink_bit = blink_bit;
3126                 last_ptr = fru_ptr;
3127                 fru_ptr++;
3128                 last_ptr->next = fru_ptr;
3129         }
3130         last_ptr->next = (fru_info_t *)NULL;
3131         /*
3132          * Power Supplies
3133          */
3134         mct_system_info.fru_info_list[PS] = (fru_info_t *)
3135             kmem_zalloc(sizeof (fru_info_t) *
3136             (mct_system_info.max_units[PS] + pad), KM_SLEEP);
3137         fru_ptr = mct_system_info.fru_info_list[PS];
3138         for (unit = 1; unit <= mct_system_info.max_units[PS]; ++unit) {
3139                 /*
3140                  * get the FRU event code (t), then use it to get the
3141                  * FRU bit-offsets for LED and SYSCFG registers
3142                  */
3143                 t = FRU_UNIT_TO_EVCODE(PS, unit);
3144                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3145                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3146                 if (IS_SCB_P15) {
3147                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3148                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3149                         blink_reg = SCSB_REG_ADDR(i);
3150                 } else {
3151                         blink_bit = 0;
3152                         blink_reg = 0;
3153                 }
3154                 /*
3155                  * get the registers addresses and shadow register index for
3156                  * the SYSCFG register
3157                  */
3158                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3159                 syscfg = SCSB_REG_ADDR(i);
3160                 index = SCSB_REG_INDEX(syscfg);
3161                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3162                 led_reg = SCSB_REG_ADDR(i);
3163                 /*
3164                  * check and set presence status
3165                  */
3166                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3167                         fru_ptr->fru_status = FRU_PRESENT;
3168                 } else {
3169                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3170                 }
3171                 fru_ptr->fru_type = PS;
3172                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3173                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3174                 fru_ptr->fru_version = (fru_version_t)0;
3175                 fru_ptr->type_list = (fru_options_t *)NULL;
3176                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3177                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3178                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3179                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3180                 fru_ptr->i2c_info->ledata_reg = led_reg;
3181                 fru_ptr->i2c_info->ledata_bit = led_bit;
3182                 fru_ptr->i2c_info->blink_reg = blink_reg;
3183                 fru_ptr->i2c_info->blink_bit = blink_bit;
3184                 last_ptr = fru_ptr;
3185                 fru_ptr++;
3186                 last_ptr->next = fru_ptr;
3187         }
3188         last_ptr->next = (fru_info_t *)NULL;
3189         /*
3190          * SCSI Disks and removable media
3191          */
3192         mct_system_info.fru_info_list[DISK] = (fru_info_t *)
3193             kmem_zalloc(sizeof (fru_info_t) *
3194             (mct_system_info.max_units[DISK] + pad), KM_SLEEP);
3195         fru_ptr = mct_system_info.fru_info_list[DISK];
3196         for (unit = 1; unit <= mct_system_info.max_units[DISK]; ++unit) {
3197                 /* SCB15 */
3198                 /*
3199                  * get the FRU event code (t), then use it to get the
3200                  * FRU bit-offsets for LED and SYSCFG registers
3201                  */
3202                 t = FRU_UNIT_TO_EVCODE(DISK, unit);
3203                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3204                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3205                 if (IS_SCB_P15) {
3206                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3207                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3208                         blink_reg = SCSB_REG_ADDR(i);
3209                 } else {
3210                         blink_bit = 0;
3211                         blink_reg = 0;
3212                 }
3213                 /*
3214                  * get the registers addresses and shadow register index for
3215                  * the SYSCFG register
3216                  */
3217                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3218                 syscfg = SCSB_REG_ADDR(i);
3219                 index = SCSB_REG_INDEX(syscfg);
3220                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3221                 led_reg = SCSB_REG_ADDR(i);
3222                 /*
3223                  * check and set presence status
3224                  */
3225                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3226                         fru_ptr->fru_status = FRU_PRESENT;
3227                         fru_ptr->fru_version = (fru_version_t)0;
3228                 } else
3229                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3230                 fru_ptr->fru_type = DISK;
3231                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3232                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3233                 fru_ptr->type_list = (fru_options_t *)NULL;
3234                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3235                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3236                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3237                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3238                 fru_ptr->i2c_info->ledata_reg = led_reg;
3239                 fru_ptr->i2c_info->ledata_bit = led_bit;
3240                 fru_ptr->i2c_info->blink_reg = blink_reg;
3241                 fru_ptr->i2c_info->blink_bit = blink_bit;
3242                 last_ptr = fru_ptr;
3243                 fru_ptr++;
3244                 last_ptr->next = fru_ptr;
3245         }
3246         last_ptr->next = (fru_info_t *)NULL;
3247         /*
3248          * Fan Trays
3249          */
3250         mct_system_info.fru_info_list[FAN] = (fru_info_t *)
3251             kmem_zalloc(sizeof (fru_info_t) *
3252             (mct_system_info.max_units[FAN] + pad), KM_SLEEP);
3253         fru_ptr = mct_system_info.fru_info_list[FAN];
3254         for (unit = 1; unit <= mct_system_info.max_units[FAN]; ++unit) {
3255                 int             bit_num;
3256                 /* SCB15 */
3257                 /*
3258                  * get the FRU event code (t), then use it to get the
3259                  * FRU bit-offsets for LED and SYSCFG registers
3260                  */
3261                 t = FRU_UNIT_TO_EVCODE(FAN, unit);
3262                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3263                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3264                 if (IS_SCB_P15) {
3265                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3266                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3267                         blink_reg = SCSB_REG_ADDR(i);
3268                 } else {
3269                         blink_bit = 0;
3270                         blink_reg = 0;
3271                 }
3272                 /*
3273                  * get the registers addresses and shadow register index for
3274                  * the SYSCFG register
3275                  */
3276                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3277                 syscfg = SCSB_REG_ADDR(i);
3278                 index = SCSB_REG_INDEX(syscfg);
3279                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3280                 led_reg = SCSB_REG_ADDR(i);
3281                 /*
3282                  * check and set presence status
3283                  */
3284                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3285                         fru_ptr->fru_status = FRU_PRESENT;
3286                 } else {
3287                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3288                 }
3289                 fru_ptr->fru_type = FAN;
3290                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3291                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3292                 fru_ptr->fru_version = (fru_version_t)0;
3293                 fru_ptr->type_list = (fru_options_t *)NULL;
3294                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3295                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3296                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3297                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3298                 fru_ptr->i2c_info->ledata_reg = led_reg;
3299                 fru_ptr->i2c_info->ledata_bit = led_bit;
3300                 fru_ptr->i2c_info->blink_reg = blink_reg;
3301                 fru_ptr->i2c_info->blink_bit = blink_bit;
3302                 last_ptr = fru_ptr;
3303                 fru_ptr++;
3304                 last_ptr->next = fru_ptr;
3305         }
3306         last_ptr->next = (fru_info_t *)NULL;
3307         /*
3308          * Alarm Cards
3309          */
3310         mct_system_info.fru_info_list[ALARM] = (fru_info_t *)
3311             kmem_zalloc(sizeof (fru_info_t) *
3312             (mct_system_info.max_units[ALARM] + pad), KM_SLEEP);
3313         fru_ptr = mct_system_info.fru_info_list[ALARM];
3314         for (unit = 1; unit <= mct_system_info.max_units[ALARM]; ++unit) {
3315                 int             bit_num;
3316 
3317                 /*
3318                  * get the FRU event code (t), then use it to get the
3319                  * FRU bit-offsets for SYSCFG register
3320                  */
3321                 t = FRU_UNIT_TO_EVCODE(ALARM, unit);
3322                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3323                 /*
3324                  * get the registers addresses and shadow register index for
3325                  * the SYSCFG register
3326                  */
3327                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3328                 syscfg = SCSB_REG_ADDR(i);
3329                 index = SCSB_REG_INDEX(syscfg);
3330                 /*
3331                  * check and set presence status
3332                  */
3333                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3334                         fru_ptr->fru_status = FRU_PRESENT;
3335                         if (acslot_ptr != NULL && acslot_ptr->fru_status ==
3336                             FRU_PRESENT) {
3337                                 acslot_ptr->fru_type = (scsb_utype_t)OC_AC;
3338                                 /*
3339                                  * acslot_ptr->fru_id =
3340                                  *      fru_id_table[event_to_index(t)];
3341                                  */
3342                         }
3343                 } else {
3344                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3345                 }
3346 
3347                 fru_ptr->fru_type = ALARM;
3348                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3349                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3350                 fru_ptr->fru_version = (fru_version_t)0;
3351                 fru_ptr->type_list = (fru_options_t *)NULL;
3352                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3353                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3354                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3355                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3356                 fru_ptr->i2c_info->ledata_reg = 0;
3357                 fru_ptr->i2c_info->ledata_bit = 0;
3358                 fru_ptr->i2c_info->blink_reg = 0;
3359                 fru_ptr->i2c_info->blink_bit = 0;
3360                 last_ptr = fru_ptr;
3361                 fru_ptr++;
3362                 last_ptr->next = fru_ptr;
3363         }
3364         last_ptr->next = (fru_info_t *)NULL;
3365         /*
3366          * SCB
3367          */
3368         mct_system_info.fru_info_list[SCB] = (fru_info_t *)
3369             kmem_zalloc(sizeof (fru_info_t) *
3370             (mct_system_info.max_units[SCB] + pad), KM_SLEEP);
3371         fru_ptr = mct_system_info.fru_info_list[SCB];
3372         unit = 1;
3373         /* SCB15 */
3374         /*
3375          * get the FRU event code (t), then use it to get the
3376          * FRU bit-offset for LED register
3377          */
3378         t = FRU_UNIT_TO_EVCODE(SCB, unit);
3379         led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3380         i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3381         led_reg = SCSB_REG_ADDR(i);
3382         if (IS_SCB_P15) {
3383                 blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3384                 i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3385                 blink_reg = SCSB_REG_ADDR(i);
3386         } else {
3387                 blink_bit = 0;
3388                 blink_reg = 0;
3389         }
3390         i = SYS_REG_INDEX(SCTRL_SCBID0, SCTRL_SCBID_BASE);
3391         index = SCSB_REG_ADDR(i);
3392         /*
3393          * check and set presence status
3394          */
3395         if (scsb->scsb_state & SCSB_SCB_PRESENT) {
3396                 fru_ptr->fru_status = FRU_PRESENT;
3397         } else {
3398                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3399         }
3400         fru_ptr->fru_type = SCB;
3401         fru_ptr->fru_unit = (scsb_unum_t)unit;
3402         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3403         /* get PROM_VERSION from shadow registers */
3404         if (scsb_rdwr_register(scsb, I2C_WR_RD, index, 1, &t_uchar, 1))
3405                 fru_ptr->fru_version = (fru_version_t)0;
3406         else
3407                 fru_ptr->fru_version = (fru_version_t)t_uchar;
3408         fru_ptr->type_list = (fru_options_t *)NULL;
3409         fru_ptr->i2c_info = (fru_i2c_info_t *)
3410             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3411         fru_ptr->i2c_info->syscfg_reg = 0;
3412         fru_ptr->i2c_info->syscfg_bit = 0;
3413         fru_ptr->i2c_info->ledata_reg = led_reg;
3414         fru_ptr->i2c_info->ledata_bit = led_bit;
3415         fru_ptr->i2c_info->blink_reg = blink_reg;
3416         fru_ptr->i2c_info->blink_bit = blink_bit;
3417         fru_ptr->next = (fru_info_t *)NULL;
3418         /*
3419          * SSB
3420          */
3421         mct_system_info.fru_info_list[SSB] = (fru_info_t *)
3422             kmem_zalloc(sizeof (fru_info_t) *
3423             (mct_system_info.max_units[SSB] + pad), KM_SLEEP);
3424         fru_ptr = mct_system_info.fru_info_list[SSB];
3425         unit = 1;
3426         /* SCB15 */
3427         /*
3428          * get the FRU event code (t), then use it to get the
3429          * FRU bit-offset for SYSCFG register
3430          */
3431         t = FRU_UNIT_TO_EVCODE(SSB, unit);
3432         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3433         /*
3434          * get the registers addresses and shadow register index for
3435          * the SYSCFG register
3436          */
3437         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3438         syscfg = SCSB_REG_ADDR(i);
3439         index = SCSB_REG_INDEX(syscfg);
3440         /*
3441          * check and set presence status
3442          */
3443         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3444                 fru_ptr->fru_status = FRU_PRESENT;
3445         } else {
3446                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3447         }
3448         fru_ptr->fru_type = SSB;
3449         fru_ptr->fru_unit = (scsb_unum_t)unit;
3450         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3451         fru_ptr->fru_version = (fru_version_t)0;
3452         fru_ptr->type_list = (fru_options_t *)NULL;
3453         fru_ptr->i2c_info = (fru_i2c_info_t *)
3454             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3455         fru_ptr->i2c_info->syscfg_reg = syscfg;
3456         fru_ptr->i2c_info->syscfg_bit = bit_num;
3457         fru_ptr->i2c_info->ledata_reg = 0;
3458         fru_ptr->i2c_info->ledata_bit = 0;
3459         fru_ptr->i2c_info->blink_reg = 0;
3460         fru_ptr->i2c_info->blink_bit = 0;
3461         fru_ptr->next = (fru_info_t *)NULL;
3462         /*
3463          * CFTM
3464          */
3465         mct_system_info.fru_info_list[CFTM] = (fru_info_t *)
3466             kmem_zalloc(sizeof (fru_info_t) *
3467             (mct_system_info.max_units[CFTM] + pad), KM_SLEEP);
3468         fru_ptr = mct_system_info.fru_info_list[CFTM];
3469         unit = 1;
3470         /* SCB15 */
3471         /*
3472          * get the FRU event code (t), then use it to get the
3473          * FRU bit-offsets for LED and SYSCFG registers
3474          */
3475         t = FRU_UNIT_TO_EVCODE(CFTM, unit);
3476         led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3477         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3478         if (IS_SCB_P15) {
3479                 blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3480                 i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3481                 blink_reg = SCSB_REG_ADDR(i);
3482         } else {
3483                 blink_bit = 0;
3484                 blink_reg = 0;
3485         }
3486         /*
3487          * get the registers addresses and shadow register index for
3488          * the SYSCFG register
3489          */
3490         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3491         syscfg = SCSB_REG_ADDR(i);
3492         index = SCSB_REG_INDEX(syscfg);
3493         i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3494         led_reg = SCSB_REG_ADDR(i);
3495         /*
3496          * check and set presence status
3497          */
3498         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3499                 fru_ptr->fru_status = FRU_PRESENT;
3500                 if (ctcslot_ptr != NULL && ctcslot_ptr->fru_status ==
3501                     FRU_PRESENT) {
3502                         ctcslot_ptr->fru_type = (scsb_utype_t)OC_CTC;
3503                         scsb->scsb_hsc_state |= SCSB_HSC_CTC_PRES;
3504                 }
3505         } else {
3506                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3507         }
3508         fru_ptr->fru_type = CFTM;
3509         fru_ptr->fru_unit = (scsb_unum_t)1;
3510         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3511         fru_ptr->fru_version = (fru_version_t)0;
3512         fru_ptr->type_list = (fru_options_t *)NULL;
3513         fru_ptr->i2c_info = (fru_i2c_info_t *)
3514             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3515         fru_ptr->i2c_info->syscfg_reg = syscfg;
3516         fru_ptr->i2c_info->syscfg_bit = bit_num;
3517         fru_ptr->i2c_info->ledata_reg = led_reg;
3518         fru_ptr->i2c_info->ledata_bit = led_bit;
3519         fru_ptr->i2c_info->blink_reg = blink_reg;
3520         fru_ptr->i2c_info->blink_bit = blink_bit;
3521         fru_ptr->next = (fru_info_t *)NULL;
3522         /*
3523          * CRTM
3524          */
3525         mct_system_info.fru_info_list[CRTM] = (fru_info_t *)
3526             kmem_zalloc(sizeof (fru_info_t) *
3527             (mct_system_info.max_units[CRTM] + pad),
3528             KM_SLEEP);
3529         fru_ptr = mct_system_info.fru_info_list[CRTM];
3530         unit = 1;
3531         /* SCB15 */
3532         /*
3533          * get the FRU event code (t), then use it to get the
3534          * FRU bit-offsets for LED and SYSCFG registers
3535          */
3536         t = FRU_UNIT_TO_EVCODE(CRTM, unit);
3537         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3538         /*
3539          * get the registers addresses and shadow register index for
3540          * the SYSCFG register
3541          */
3542         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3543         syscfg = SCSB_REG_ADDR(i);
3544         index = SCSB_REG_INDEX(syscfg);
3545         /*
3546          * check and set presence status
3547          */
3548         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3549                 fru_ptr->fru_status = FRU_PRESENT;
3550         } else {
3551                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3552         }
3553         fru_ptr->fru_type = CRTM;
3554         fru_ptr->fru_unit = (scsb_unum_t)unit;
3555         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3556         fru_ptr->fru_version = (fru_version_t)0;
3557         fru_ptr->type_list = (fru_options_t *)NULL;
3558         fru_ptr->i2c_info = (fru_i2c_info_t *)
3559             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3560         fru_ptr->i2c_info->syscfg_reg = syscfg;
3561         fru_ptr->i2c_info->syscfg_bit = bit_num;
3562         fru_ptr->i2c_info->ledata_reg = 0;
3563         fru_ptr->i2c_info->ledata_bit = 0;
3564         fru_ptr->i2c_info->blink_reg = 0;
3565         fru_ptr->i2c_info->blink_bit = 0;
3566         fru_ptr->next = (fru_info_t *)NULL;
3567         /*
3568          * PRTM
3569          */
3570         mct_system_info.fru_info_list[PRTM] = (fru_info_t *)
3571             kmem_zalloc(sizeof (fru_info_t) *
3572             (mct_system_info.max_units[PRTM] + pad), KM_SLEEP);
3573         fru_ptr = mct_system_info.fru_info_list[PRTM];
3574         unit = 1;
3575         /*
3576          * SCB15
3577          * get the FRU event code (t), then use it to get the
3578          * FRU bit-offsets for LED and SYSCFG registers
3579          */
3580         t = FRU_UNIT_TO_EVCODE(PRTM, unit);
3581         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3582         /*
3583          * get the registers addresses and shadow register index for
3584          * the SYSCFG register
3585          */
3586         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3587         syscfg = SCSB_REG_ADDR(i);
3588         index = SCSB_REG_INDEX(syscfg);
3589         /*
3590          * check and set presence status
3591          */
3592         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3593                 fru_ptr->fru_status = FRU_PRESENT;
3594         } else {
3595                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3596         }
3597         fru_ptr->fru_type = PRTM;
3598         fru_ptr->fru_unit = (scsb_unum_t)unit;
3599         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3600         fru_ptr->fru_version = (fru_version_t)0;
3601         fru_ptr->type_list = (fru_options_t *)NULL;
3602         fru_ptr->i2c_info = (fru_i2c_info_t *)
3603             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3604         fru_ptr->i2c_info->syscfg_reg = syscfg;
3605         fru_ptr->i2c_info->syscfg_bit = bit_num;
3606         fru_ptr->i2c_info->ledata_reg = 0;
3607         fru_ptr->i2c_info->ledata_bit = 0;
3608         fru_ptr->i2c_info->blink_reg = 0;
3609         fru_ptr->i2c_info->blink_bit = 0;
3610         fru_ptr->next = (fru_info_t *)NULL;
3611 
3612         scsb->scsb_state |= SCSB_TOPOLOGY;
3613 #ifdef DEBUG
3614         mct_topology_dump(scsb, 0);
3615 #endif
3616 }
3617 
3618 /*ARGSUSED*/
3619 static void
3620 scsb_free_topology(scsb_state_t *scsb)
3621 {
3622         int             i;
3623         fru_info_t      *fru_ptr;
3624 
3625         if (scsb_debug & 0x00100005)
3626                 cmn_err(CE_NOTE, "scsb_free_topology:");
3627         for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
3628                 fru_ptr = mct_system_info.fru_info_list[i];
3629                 while (fru_ptr != NULL) {
3630                         if (fru_ptr->i2c_info != (fru_i2c_info_t *)NULL)
3631                                 kmem_free(fru_ptr->i2c_info,
3632                                     sizeof (fru_i2c_info_t));
3633                         fru_ptr = fru_ptr->next;
3634                 }
3635                 if ((fru_ptr = mct_system_info.fru_info_list[i]) !=
3636                     (fru_info_t *)NULL) {
3637                         kmem_free(fru_ptr, sizeof (fru_info_t) *
3638                             mct_system_info.max_units[i]);
3639                         mct_system_info.fru_info_list[i] = (fru_info_t *)NULL;
3640                 }
3641         }
3642 }
3643 
3644 #ifdef DEBUG
3645 static void
3646 mct_topology_dump(scsb_state_t *scsb, int force)
3647 {
3648         int             i;
3649         fru_info_t      *fru_ptr;
3650 
3651         if (!force && !(scsb_debug & 0x00200000))
3652                 return;
3653         if (force && !(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
3654                 return;
3655         if (!(scsb->scsb_state & SCSB_TOPOLOGY)) {
3656                 cmn_err(CE_NOTE, "mct_topology_dump: Topology not set!");
3657                 return;
3658         }
3659         for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
3660                 fru_ptr = mct_system_info.fru_info_list[i];
3661                 switch ((scsb_utype_t)i) {
3662                 case SLOT:
3663                         cmn_err(CE_NOTE, "MCT: Number of Slots: %d",
3664                             mct_system_info.max_units[SLOT]);
3665                         break;
3666                 case ALARM:
3667                         cmn_err(CE_NOTE, "MCT: MAX Number of Alarm Cards: %d",
3668                             mct_system_info.max_units[ALARM]);
3669                         break;
3670                 case DISK:
3671                         cmn_err(CE_NOTE, "MCT: MAX Number of SCSI Devices: %d",
3672                             mct_system_info.max_units[DISK]);
3673                         break;
3674                 case FAN:
3675                         cmn_err(CE_NOTE, "MCT: MAX Number of Fan Trays: %d",
3676                             mct_system_info.max_units[FAN]);
3677                         break;
3678                 case PDU:
3679                         cmn_err(CE_NOTE, "MCT: MAX Number of PDUs: %d",
3680                             mct_system_info.max_units[PDU]);
3681                         break;
3682                 case PS:
3683                         cmn_err(CE_NOTE,
3684                             "MCT: MAX Number of Power Supplies: %d",
3685                             mct_system_info.max_units[PS]);
3686                         break;
3687                 case SCB:
3688                         cmn_err(CE_NOTE, "MCT: MAX Number of SCBs: %d",
3689                             mct_system_info.max_units[SCB]);
3690                         break;
3691                 case SSB:
3692                         cmn_err(CE_NOTE, "MCT: MAX Number of SSBs: %d",
3693                             mct_system_info.max_units[SSB]);
3694                         break;
3695                 }
3696                 while (fru_ptr != NULL) {
3697                         if (fru_ptr->fru_status & FRU_PRESENT) {
3698                                 cmn_err(CE_NOTE,
3699                                     "MCT:   type=%d, unit=%d, id=0x%x, "
3700                                     "version=0x%x",
3701                                     fru_ptr->fru_type,
3702                                     fru_ptr->fru_unit,
3703                                     fru_ptr->fru_id,
3704                                     fru_ptr->fru_version);
3705                         }
3706                         fru_ptr = fru_ptr->next;
3707                 }
3708         }
3709 }
3710 
3711 /*
3712  * Sends an event when the system controller board I2C errors
3713  * exceed the threshold.
3714  */
3715 static void
3716 scsb_failing_event(scsb_state_t *scsb)
3717 {
3718         uint32_t scsb_event_code = SCTRL_EVENT_SCB;
3719 
3720         add_event_code(scsb, scsb_event_code);
3721         (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code,
3722         "scsb_intr");
3723 }
3724 #endif
3725 
3726 int
3727 scsb_read_bhealthy(scsb_state_t *scsb)
3728 {
3729         int             error;
3730         uchar_t         reg;
3731         int             index;
3732 
3733         if (scsb_debug & 0x8001) {
3734                 cmn_err(CE_NOTE, "scsb_read_bhealthy()");
3735         }
3736         reg = SCSB_REG_ADDR(SCTRL_BHLTHY_BASE);
3737         index = SCSB_REG_INDEX(reg);
3738         error = scsb_rdwr_register(scsb, I2C_WR_RD, reg,
3739             SCTRL_BHLTHY_NUMREGS, &scsb->scsb_data_reg[index], 1);
3740         return (error);
3741 }
3742 
3743 /*
3744  * Returns the health status of a slot
3745  */
3746 int
3747 scsb_read_slot_health(scsb_state_t *scsb, int pslotnum)
3748 {
3749         int slotnum = tonga_psl_to_ssl(scsb, pslotnum);
3750         return (scsb_fru_op(scsb, SLOT, slotnum,
3751             SCTRL_BHLTHY_BASE, SCSB_FRU_OP_GET_BITVAL));
3752 }
3753 
3754 /*
3755  * DIAGNOSTIC and DEBUG only.
3756  * Called from ioctl command (SCSBIOC_BHEALTHY_GET)
3757  */
3758 int
3759 scsb_bhealthy_slot(scsb_state_t *scsb, scsb_uinfo_t *suip)
3760 {
3761         int             error = 0;
3762         int             base, code, unit_number;
3763         uchar_t         reg;
3764         int             index;
3765 
3766         if (scsb->scsb_state & SCSB_FROZEN)
3767                 return (EAGAIN);
3768 
3769         /* operation valid for slots only */
3770         if (suip == NULL || suip->unit_type != SLOT) {
3771                 return (EINVAL);
3772         }
3773 
3774         if (scsb_debug & 0x8001)
3775                 cmn_err(CE_NOTE, "scsb_bhealthy_slot: slot %d",
3776                     suip->unit_number);
3777         if (suip->unit_number > mct_system_info.max_units[SLOT]) {
3778                 return (EINVAL);
3779         }
3780         /*
3781          * Map 1.0 Tonga Slot Number, if necessary
3782          */
3783         tonga_slotnum_check(scsb, suip);
3784         base = SCTRL_BHLTHY_BASE;
3785         code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
3786         unit_number = FRU_OFFSET(code, base);
3787         index = FRU_REG_INDEX(code, base);
3788         reg = SCSB_REG_ADDR(index);
3789         index = SCSB_REG_INDEX(reg);            /* shadow index */
3790 
3791         if (scsb->scsb_state & SCSB_P10_PROM) {
3792                 error = scsb_read_bhealthy(scsb);
3793         }
3794         /* else shadow regs are updated by interrupt handler */
3795         if (error == 0) {
3796                 if (scsb->scsb_data_reg[index] & (1 << unit_number))
3797                         suip->unit_state = ON;
3798                 else
3799                         suip->unit_state = OFF;
3800         }
3801         return (error);
3802 }
3803 
3804 /*
3805  * Called from HSC and ioctl command (SCSBIOC_RESET_UNIT)
3806  * to reset one specified slot
3807  */
3808 int
3809 scsb_reset_unit(scsb_state_t *scsb, scsb_uinfo_t *suip)
3810 {
3811         int             error;
3812         int             unit_number;
3813         uchar_t         reg;
3814         int             index, slotnum, reset_state;
3815 
3816         if (scsb->scsb_state & SCSB_FROZEN)
3817                 return (EAGAIN);
3818         if (scsb_debug & 0x8001) {
3819                 cmn_err(CE_NOTE, "scsb_reset_slot(%d): slot %d, state %d\n",
3820                     scsb->scsb_instance, suip->unit_number,
3821                     suip->unit_state);
3822         }
3823         if (suip->unit_type != ALARM && !(scsb->scsb_state &
3824             (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
3825                 return (EINVAL);
3826         }
3827         if (suip->unit_state != ON && suip->unit_state != OFF) {
3828                 return (EINVAL);
3829         }
3830         error = 0;
3831         switch (suip->unit_type) {
3832         case ALARM:
3833         {
3834                 int     i, code;
3835                 if (suip->unit_number != 1)
3836                         return (EINVAL);
3837                 code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
3838                 unit_number = FRU_OFFSET(code, SCTRL_RESET_BASE);
3839                 i = ALARM_RESET_REG_INDEX(code, SCTRL_RESET_BASE);
3840                 reg = SCSB_REG_ADDR(i);
3841                 break;
3842         }
3843         case SLOT:
3844                 slotnum = suip->unit_number;
3845                 reset_state = (suip->unit_state == ON) ? SCSB_RESET_SLOT :
3846                     SCSB_UNRESET_SLOT;
3847                 if (scsb->scsb_state & SCSB_IS_TONGA) {
3848                         if (slotnum > TG_MAX_SLOTS ||
3849                             slotnum == SC_TG_CPU_SLOT) {
3850                                 return (EINVAL);
3851                         }
3852                 } else {
3853                         if (slotnum > MC_MAX_SLOTS ||
3854                             slotnum == SC_MC_CPU_SLOT ||
3855                             (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
3856                             slotnum == SC_MC_CTC_SLOT)) {
3857                                 return (EINVAL);
3858                         }
3859                 }
3860                 return (scsb_reset_slot(scsb, slotnum, reset_state));
3861         default:
3862                 return (EINVAL);
3863         }
3864         index = SCSB_REG_INDEX(reg);
3865         mutex_enter(&scsb->scsb_mutex);
3866         if (suip->unit_state == ON)
3867                 scsb->scsb_data_reg[index] |= (1 << unit_number);
3868         else /* OFF */
3869                 scsb->scsb_data_reg[index] &= ~(1 << unit_number);
3870         if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
3871             &scsb->scsb_data_reg[index], 0)) != 0) {
3872                 if (scsb_debug & 0x8002)
3873                         cmn_err(CE_WARN,
3874                             "scsb_leds: write failure to 0x%x", reg);
3875                 return (error);
3876         }
3877         mutex_exit(&scsb->scsb_mutex);
3878         return (error);
3879 }
3880 
3881 /*
3882  * Diagnostic and DEBUG
3883  * This is a helper function for the helper ioctl to pretend that
3884  * scsb h/w is doing its job!!!
3885  */
3886 int
3887 scsb_slot_occupancy(scsb_state_t *scsb, scsb_uinfo_t *suip)
3888 {
3889         int             error;
3890         int             saved_unit_number;
3891 
3892         if (!(scsb->scsb_state & (SCSB_DEBUG_MODE | SCSB_DIAGS_MODE)))
3893                 return (EACCES);
3894         if (scsb->scsb_state & SCSB_FROZEN) {
3895                 return (EAGAIN);
3896         }
3897         error = 0;
3898         switch (suip->unit_type) {
3899         case ALARM:
3900                 if (suip->unit_number !=
3901                     (mct_system_info.fru_info_list[ALARM])->fru_unit) {
3902                         return (EINVAL);
3903                 }
3904                 break;
3905 
3906         case SLOT:
3907                 /*
3908                  * All slots are acceptable, except slots 11 & 12.
3909                  */
3910                 if (suip->unit_number < 1 || suip->unit_number >
3911                     mct_system_info.max_units[ALARM]) {
3912                         error = EINVAL;
3913                         break;
3914                 }
3915                 /* Map 1.0 Tonga Slot Numbers if necessary */
3916                 saved_unit_number = suip->unit_number;
3917                 tonga_slotnum_check(scsb, suip);
3918                 break;
3919 
3920         default:
3921                 error = EINVAL;
3922                 break;
3923         }
3924 
3925         if (error)
3926                 return (error);
3927         if (suip->unit_state == ON) {
3928                 if (hsc_slot_occupancy(saved_unit_number, B_TRUE, 0, B_TRUE)
3929                     != 0)
3930                         error = EFAULT;
3931         } else {
3932                 if (hsc_slot_occupancy(saved_unit_number, B_FALSE, 0, B_FALSE)
3933                     != 0)
3934                         error = EFAULT;
3935         }
3936 
3937         return (error);
3938 }
3939 
3940 static int
3941 scsb_clear_intptrs(scsb_state_t *scsb)
3942 {
3943         int             i, error;
3944         uchar_t         wbuf[SCTRL_MAX_GROUP_NUMREGS];
3945         error = 0;
3946         for (i = 1; i <= SCTRL_INTR_NUMREGS; ++i) {
3947                 wbuf[i] = 0xff;
3948         }
3949         if (error = scsb_rdwr_register(scsb, I2C_WR,
3950             SCSB_REG_ADDR(SCTRL_INTSRC_BASE),
3951             SCTRL_INTR_NUMREGS, wbuf, 1)) {
3952                 if (scsb_debug & 0x0402)
3953                         cmn_err(CE_NOTE, "scsb_clear_intptrs(): "
3954                             "write to 0x%x failed",
3955                             SCSB_REG_ADDR(SCTRL_INTSRC_BASE));
3956         }
3957         return (error);
3958 }
3959 
3960 static int
3961 scsb_setall_intmasks(scsb_state_t *scsb)
3962 {
3963         int             error;
3964         uchar_t         reg, wdata, rmask;
3965         int             i;
3966 
3967         /*
3968          * write loop for Interrupt Mask registers
3969          */
3970         if (scsb_debug & 0x0401)
3971                 cmn_err(CE_NOTE, "setall_intmasks()");
3972         error = 0;
3973         rmask = 0;
3974         wdata = 0xff;
3975         reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE);
3976         for (i = 0; i < SCTRL_MASK_NUMREGS; ++i, ++reg) {
3977                 if (error = scsb_write_mask(scsb, reg, rmask, wdata, 0)) {
3978                         if (scsb_debug & 0x0402)
3979                                 cmn_err(CE_NOTE, "scsb_setall_intmasks: "
3980                                     "write to 0x%x failed: %d", reg, error);
3981                         error = EIO;
3982                         break;
3983                 }
3984         }
3985         return (error);
3986 }
3987 
3988 
3989 /*
3990  * Clear Interrupt masks based on the FRUs that could be installed
3991  * for this particular topology, determined by the MidPlane ID
3992  * from SCTRL_SYSCFG registers
3993  *      case SCTRL_MPID_HALF:
3994  *              1 CPU, 1 AlarmCard, 1 SCB/SSB, 2 PS, 3 FAN, 3 SCSI, 8 Slots
3995  *      case SCTRL_MPID_QUARTER:
3996  *              1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 1 SCSI, 4 Slots
3997  *      case SCTRL_MPID_QUARTER_NODSK:
3998  *              1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 0 SCSI, 4 Slots
3999  */
4000 static int
4001 scsb_clear_intmasks(scsb_state_t *scsb)
4002 {
4003         int             error;
4004         uchar_t         msk_reg, reg, wdata, rmask;
4005         uchar_t         mask_data[SCTRL_MAX_GROUP_NUMREGS];
4006         int             tmp, idx, code, unit, offset, mbid;
4007         scsb_utype_t    fru_type;
4008         fru_info_t      *fru_ptr;
4009 
4010         if (scsb->scsb_state & SCSB_FROZEN &&
4011             !(scsb->scsb_state & SCSB_IN_INTR)) {
4012                 return (EAGAIN);
4013         }
4014         error = 0;
4015         for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp)
4016                 mask_data[tmp] = 0;
4017         msk_reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE);
4018         mbid    = SCSB_REG_INDEX(msk_reg); /* the Mask Base Index Delta */
4019         if (scsb_debug & 0x0400) {
4020                 cmn_err(CE_NOTE, "clear_intmasks: msk_reg=0x%x; mbid=%d",
4021                     msk_reg, mbid);
4022         }
4023         for (fru_type = 0; fru_type < SCSB_UNIT_TYPES; ++fru_type) {
4024                 if (fru_type == SCB)
4025                         continue;       /* handle below, 2 reg offsets */
4026                 fru_ptr = mct_system_info.fru_info_list[fru_type];
4027                 for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
4028                         unit = fru_ptr->fru_unit;
4029                         code   = FRU_UNIT_TO_EVCODE(fru_type, unit);
4030                         offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4031                         reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
4032                         idx    = SCSB_REG_INDEX(reg);
4033                         tmp = idx - mbid;
4034                         mask_data[tmp] |= (1 << offset);
4035                         if (scsb_debug & 0x0400)
4036                                 cmn_err(CE_NOTE,
4037                                 "clear_intmasks:%d:%d: PRES mask[%d]:0x%x",
4038                                     fru_type, unit, tmp, mask_data[tmp]);
4039                         if ((fru_type == SLOT) && (IS_SCB_P15)) {
4040                                 /*
4041                                  * Unmask the corresponding Slot HLTHY mask
4042                                  * Use Slot bit and register offsets,
4043                                  *  but with SCTRL_INTMASK_HLTHY_BASE
4044                                  */
4045                                 reg = FRU_REG_ADDR(code,
4046                                     SCTRL_INTMASK_HLTHY_BASE);
4047                                 idx = SCSB_REG_INDEX(reg);
4048                                 tmp = idx - mbid;
4049                                 mask_data[tmp] |= (1 << offset);
4050                                 if (scsb_debug & 0x0400) {
4051                                         cmn_err(CE_NOTE,
4052                                 "clear_intmasks:Slot:%d: HLTHY mask[%d]:0x%x"
4053                                 "; reg=0x%x, idx=%d, mbid=%d",
4054                                             unit, tmp, mask_data[tmp],
4055                                             reg, idx, mbid);
4056                                 }
4057                         }
4058                 }
4059         }
4060         /*
4061          * Now unmask these non-fru interrupt events
4062          *      SCTRL_EVENT_PWRDWN      (almost normal)
4063          *      SCTRL_EVENT_REPLACE     (not used)
4064          *      SCTRL_EVENT_ALARM_INT   (not working in P0.6/P1.0)
4065          *      SCTRL_EVENT_SCB         (SCB 1.5 ONLY; plus SCB_INT_OFFSET)
4066          */
4067         code   = SCTRL_EVENT_PWRDWN;
4068         offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4069         reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
4070         idx    = SCSB_REG_INDEX(reg);
4071         tmp = idx - mbid;
4072         mask_data[tmp] |= (1 << offset);
4073         if (IS_SCB_P15) {
4074                 code   = SCTRL_EVENT_SCB;
4075                 offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4076                 reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE) + SCB_INT_OFFSET;
4077                 idx    = SCSB_REG_INDEX(reg);
4078                 tmp = idx - mbid;
4079                 mask_data[tmp] |= (1 << offset);
4080                 code   = SCTRL_EVENT_ALARM_INT;
4081                 offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4082                 reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
4083                 idx    = SCSB_REG_INDEX(reg);
4084                 tmp = idx - mbid;
4085                 mask_data[tmp] |= (1 << offset);
4086         }
4087         for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp) {
4088                 rmask = 0;
4089                 wdata = mask_data[tmp];
4090                 if (scsb_debug & 0x0400)
4091                         cmn_err(CE_NOTE, "clear_intmasks:0x%x: ~(0x%x),0x%x",
4092                             msk_reg, (~wdata) & 0xff, wdata);
4093                 mutex_enter(&scsb->scsb_mutex);
4094                 if (error = scsb_write_mask(scsb, msk_reg, rmask,
4095                     (~wdata) & 0xff, wdata)) {
4096                         mutex_exit(&scsb->scsb_mutex);
4097                         if (scsb_debug & 0x0402)
4098                                 cmn_err(CE_NOTE, "scsb_clear_intmasks: "
4099                                     "write to 0x%x failed: %d",
4100                                     msk_reg, error);
4101                         error = EIO;
4102                         break;
4103                 }
4104                 mutex_exit(&scsb->scsb_mutex);
4105                 ++msk_reg;
4106         }
4107         return (error);
4108 }
4109 
4110 static int
4111 scsb_get_status(scsb_state_t *scsb, scsb_status_t *smp)
4112 {
4113         register int    i;
4114 
4115         if (smp == NULL) {
4116                 return (EFAULT);
4117         }
4118         if (scsb_debug & 0x40000000 &&
4119             (scsb->scsb_state & SCSB_DEBUG_MODE ||
4120             scsb->scsb_state & SCSB_DIAGS_MODE)) {
4121                 if (scsb->scsb_state & SCSB_FROZEN) {
4122                         return (EAGAIN);
4123                 }
4124                 mutex_enter(&scsb->scsb_mutex);
4125                 if (scsb_debug & 0x80000000) {
4126                         if ((i = scsb_readall_regs(scsb)) != 0 &&
4127                             scsb->scsb_state & SCSB_DEBUG_MODE)
4128                                 cmn_err(CE_WARN, "scsb_get_status: "
4129                                     "scsb_readall_regs() FAILED");
4130                 } else {
4131                         if ((i = scsb_check_config_status(scsb)) == 0) {
4132                                 i = scsb_set_scfg_pres_leds(scsb, NULL);
4133                         }
4134                 }
4135                 mutex_exit(&scsb->scsb_mutex);
4136                 if (i) {
4137                         cmn_err(CE_WARN,
4138                             "scsb_get_status: FAILED Presence LEDs update");
4139                         return (EIO);
4140                 }
4141         }
4142         for (i = 0; i < SCSB_DATA_REGISTERS; ++i)
4143                 smp->scsb_reg[i] = scsb->scsb_data_reg[i];
4144         return (0);
4145 }
4146 
4147 /*
4148  * scsb_freeze_check:
4149  *      Turn all the leds off on the system monitor card, without changing
4150  *      the state of what we have for scsb. This routine is called only when
4151  *      replacing system monitor card, so the state of the card leds could be
4152  *      restored, using scsb_restore().
4153  *      Also, set state to SCSB_FROZEN which denies access to scsb while in
4154  *      freeze mode.
4155  */
4156 static char  *BAD_BOARD_MSG =
4157         "SCSB: Should NOT remove SCB(%d) while cPCI Slot %d is "
4158         "in RESET with a possible bad board.";
4159 static int      slots_in_reset[SCTRL_MAX_GROUP_NUMREGS];
4160 
4161 static void
4162 scsb_freeze_check(scsb_state_t *scsb)
4163 {
4164         register int    i;
4165         int             offset;
4166         int             unit, slotnum;
4167         int             index;
4168         fru_info_t      *fru_ptr;
4169         uint32_t        code;
4170         uchar_t         reg;
4171 
4172         if (scsb_debug & 0x20001)
4173                 cmn_err(CE_NOTE, "scsb_freeze_check(%d):", scsb->scsb_instance);
4174 
4175         if (scsb->scsb_state & SCSB_FROZEN) {
4176                 return;
4177         }
4178         mutex_enter(&scsb->scsb_mutex);
4179         for (i = 0; i < SCTRL_MAX_GROUP_NUMREGS; ++i)
4180                 slots_in_reset[i] = 0;
4181         /*
4182          * We allow the SCB to be removed only if none of
4183          * the cPCI resets are asserted for occupied slots.
4184          * There shouldn't be a bad board plugged in the system
4185          * while swapping the SCB.
4186          */
4187         fru_ptr = mct_system_info.fru_info_list[SLOT];
4188         for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) {
4189                 if (IS_SCB_P15) {
4190                         slotnum = tonga_psl_to_ssl(scsb, unit);
4191                 } else {
4192                         slotnum = unit;
4193                 }
4194                 code = FRU_UNIT_TO_EVCODE(SLOT, slotnum);
4195                 offset = FRU_OFFSET(code, SCTRL_RESET_BASE);
4196                 reg = FRU_REG_ADDR(code, SCTRL_RESET_BASE);
4197                 index = SCSB_REG_INDEX(reg);
4198                 if (scsb->scsb_data_reg[index] & (1 << offset)) {
4199                         if (fru_ptr[unit - 1].fru_status == FRU_PRESENT) {
4200                                 slots_in_reset[unit - 1] = unit;
4201                                 cmn_err(CE_NOTE, BAD_BOARD_MSG,
4202                                     scsb->scsb_instance, unit);
4203                         }
4204                 }
4205         }
4206         mutex_exit(&scsb->scsb_mutex);
4207 }
4208 
4209 static void
4210 scsb_freeze(scsb_state_t *scsb)
4211 {
4212         uint32_t        code;
4213         if (scsb_debug & 0x00020002) {
4214                 cmn_err(CE_WARN, "scsb_freeze: SCB%d possibly removed",
4215                     scsb->scsb_instance);
4216         }
4217         if (scsb->scsb_state & SCSB_FROZEN)
4218                 return;
4219         scsb->scsb_state |= SCSB_FROZEN;
4220         scsb->scsb_state &= ~SCSB_SCB_PRESENT;
4221         (void) scsb_hsc_freeze(scsb->scsb_dev);
4222         /*
4223          * Send the EVENT_SCB since there is evidence that the
4224          * System Controller Board has been removed.
4225          */
4226         code = SCTRL_EVENT_SCB;
4227         if (!(scsb->scsb_state & SCSB_IN_INTR))
4228                 scsb_event_code = code;
4229         check_fru_info(scsb, code);
4230         add_event_code(scsb, code);
4231         (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &code, "scsb_freeze");
4232 }
4233 
4234 /*
4235  * scsb_restore will only be called from the interrupt handler context on
4236  * INIT_SCB interrupt for newly inserted SCB.
4237  * Called with mutex held.
4238  */
4239 static void
4240 scsb_restore(scsb_state_t *scsb)
4241 {
4242         if (scsb_debug & 0x20001)
4243                 cmn_err(CE_NOTE, "scsb_restore(%d):", scsb->scsb_instance);
4244 
4245         if (initialize_scb(scsb) != DDI_SUCCESS) {
4246                 if (scsb_debug & 0x00020002) {
4247                         cmn_err(CE_WARN, "scsb_restore: INIT Failed");
4248                 return;
4249                 }
4250         }
4251         /* 9. Clear all Interrupts */
4252         if (scsb_clear_intmasks(scsb)) {
4253                 cmn_err(CE_WARN,
4254                     "scsb%d: I2C TRANSFER Failed", scsb->scsb_instance);
4255                 if (scsb_debug & 0x00020002) {
4256                         cmn_err(CE_WARN, "scsb_restore: clear_intmasks Failed");
4257                 }
4258                 return;
4259         }
4260 
4261         /* 10. */
4262         /* Check if Alarm Card present at boot and set flags */
4263         if (scsb_fru_op(scsb, ALARM, 1, SCTRL_SYSCFG_BASE,
4264             SCSB_FRU_OP_GET_BITVAL))
4265                 scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
4266         else
4267                 scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES;
4268 
4269         scsb->scsb_state &= ~SCSB_FROZEN;
4270         (void) scsb_hsc_restore(scsb->scsb_dev);
4271 }
4272 
4273 /*
4274  * Given an Event Code,
4275  * Return:
4276  *      FRU type    in LSByte
4277  *      unit number in MSByte
4278  */
4279 uint16_t
4280 event_to_type(uint32_t evcode)
4281 {
4282         int             i, li, unit;
4283         uint32_t        ec;
4284         uint16_t        ret;
4285         for (i = li = 0; i < SCSB_UNIT_TYPES; ++i) {
4286                 if (evcode == type_to_code1[i]) {
4287                         ret = (uint16_t)(0x0100 | i);
4288                         return (ret);
4289                 }
4290                 if (evcode < type_to_code1[i]) {
4291                         unit = 1;
4292                         ec = type_to_code1[li];
4293                         while (ec < evcode)
4294                                 ec = ec << 1, ++unit;
4295                         ret = (unit << 8) | li;
4296                         return (ret);
4297                 }
4298                 li = i;
4299         }
4300         return ((uint16_t)0xffff);
4301 }
4302 
4303 /*
4304  * scsb interrupt handler for (MC) PSM_INT vector
4305  * P0.6: HW shipped to beta customers
4306  *      1. did not have Slot Occupant Presense support
4307  *      2. I2C interrupt-map properties not yet tested, using polling daemon
4308  *      3. Polling detects each event reliably twice.
4309  *         clr_bits# are used to keep track of events to be ignored 2nd time
4310  *
4311  * retval flags allow all events to be checked, and still returning the
4312  * correct DDI value.
4313  *
4314  */
4315 #define SCSB_INTR_CLAIMED       1
4316 #define SCSB_INTR_UNCLAIMED     2
4317 #define SCSB_INTR_EVENT         4
4318 
4319 /*
4320  * Does preprocessing of the interrupt. The only thing this
4321  * needs to do is to ask scsb to release the interrupt line.
4322  * and then schedule delayed actual processing using timeout()
4323  */
4324 uint_t
4325 scsb_intr_preprocess(caddr_t arg)
4326 {
4327         scsb_state_t    *scsb = (scsb_state_t *)arg;
4328 
4329         scb_pre_s = gethrtime();
4330 
4331         /*
4332          * If SCSB_IN_INTR is already set in scsb_state,
4333          * it means we are being interrupted by someone else. This can
4334          * happen only if the interrupt does not belong to scsb, and some
4335          * other device, e.g. a FAN or PS is interrupting. So, we
4336          * cancel the previous timeout().
4337          */
4338 
4339         if (scsb->scsb_state & SCSB_IN_INTR) {
4340                 (void) untimeout(scsb_intr_tid);
4341                 (void) scsb_invoke_intr_chain();
4342                 (void) scsb_toggle_psmint(scsb, 1);
4343                 scsb->scsb_state &= ~SCSB_IN_INTR;
4344                 goto intr_end;
4345         }
4346         scsb->scsb_state |= SCSB_IN_INTR;
4347 
4348         /*
4349          * Stop scsb from interrupting first.
4350          */
4351         if (scsb_quiesce_psmint(scsb) != DDI_SUCCESS) {
4352                 goto intr_end;
4353         }
4354 
4355         /*
4356          * Schedule a timeout to actually process the
4357          * interrupt.
4358          */
4359         scsb_intr_tid = timeout((void (*)(void *))scsb_intr, arg,
4360             drv_usectohz(1000));
4361 
4362 intr_end:
4363 
4364         scb_pre_e = gethrtime();
4365         return (DDI_INTR_CLAIMED);
4366 }
4367 
4368 static void scsb_healthy_intr(scsb_state_t *scsb, int pslotnum);
4369 void
4370 scsb_intr(caddr_t arg)
4371 {
4372         scsb_state_t    *scsb = (scsb_state_t *)arg;
4373         int             i, idx, offset, unit, numregs, error;
4374         int             intr_idx, index, offset_base, retval, slotnum, val;
4375         uint32_t        code;
4376         uchar_t         intr_reg, tmp_reg, intr_addr, clr_bits = 0;
4377         uchar_t         ac_slot = B_FALSE;
4378         uchar_t         *int_masks;
4379         uchar_t         cstatus_regs[SCTRL_MAX_GROUP_NUMREGS];
4380         scsb_utype_t    fru_type;
4381         fru_info_t      *fru_ptr;
4382         int             ac_present;
4383 
4384         /*
4385          * Avoid mayhem, make sure we have only one timeout thread running.
4386          */
4387         mutex_enter(&scsb->scsb_mutex);
4388         while (scsb_in_postintr)
4389                 cv_wait(&scsb->scsb_cv, &scsb->scsb_mutex);
4390         scsb_in_postintr = 1;
4391         mutex_exit(&scsb->scsb_mutex);
4392 
4393         scb_post_s = gethrtime();
4394         if (scsb_debug & 0x00002000)
4395                 cmn_err(CE_NOTE, "scsb_intr(%d)", scsb->scsb_instance);
4396         retval = 0;
4397         tmp_reg = 0;
4398         /*
4399          * XXX: Problem, when we want to support swapping between SCB
4400          * versions, then we need to check the SCB PROM ID (CF) register here
4401          * before assuming the same SCB version was re-inserted.
4402          * We will have to duplicate some of the scb_initialization()
4403          * code to set the scsb_state PROM ID bits and to set up the
4404          * register table pointers.
4405          *
4406          * Only if NOT SSB_PRESENT, check the SCB PROM ID
4407          */
4408         if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
4409                 if (scb_check_version(scsb) != DDI_SUCCESS) {
4410 #ifdef DEBUG
4411                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4412                             scsb->scsb_i2c_errcnt > scsb_err_threshold)
4413                                 scsb_failing_event(scsb);
4414 #endif
4415                         goto intr_error;
4416                 }
4417         }
4418         if (IS_SCB_P15) {
4419                 int_masks = scb_15_int_masks;
4420         } else {
4421                 int_masks = scb_10_int_masks;
4422         }
4423         /*
4424          * Now check the INTSRC registers for set bits.
4425          * Do a quick check by OR'ing INTSRC registers together as we copy
4426          * them from the transfer buffer. For P1.0 or earlier we had already
4427          * read the interrupt source registers and wrote them back to stop
4428          * interrupt. So we need to do this step only for P1.5 or later.
4429          * We already read INTSRC6 to take care of SCB insertion case, so
4430          * do not read INTSRC6 again.
4431          */
4432 
4433         if (IS_SCB_P15) {
4434                 intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
4435                 /* read the interrupt register from scsb */
4436                 if (scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr,
4437                     SCTRL_INTR_NUMREGS - 1, scb_intr_regs, 1)) {
4438                         cmn_err(CE_WARN, "scsb_intr: "
4439                             " Failed read of interrupt registers.");
4440 #ifdef DEBUG
4441                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4442                             scsb->scsb_i2c_errcnt > scsb_err_threshold)
4443                                 scsb_failing_event(scsb);
4444 #endif
4445                         goto intr_error;
4446                 }
4447         }
4448 
4449         /*
4450          * We have seen that an interrupt source bit can be set
4451          * even though the corresponding interrupt mask bit
4452          * has been set to mask the interrupt. So we must
4453          * clear all bits set in the interrupt source register.
4454          */
4455         for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) {
4456                 retval |= scb_intr_regs[i];             /* Quick INTSRC check */
4457 #ifdef DEBUG
4458                 if (scsb_debug & 0x08000000) {
4459                         if (tmp_reg || scb_intr_regs[i]) {
4460                                 cmn_err(CE_NOTE, "scsb_intr: INTSRC%d=0x%x",
4461                                     i + 1, scb_intr_regs[i]);
4462                                 ++tmp_reg;
4463                         }
4464                 }
4465 #endif
4466         }
4467         /*
4468          * Any bits from quick check? If this is not our interrupt,
4469          * something is wrong. FAN/PS interrupts are supposed to be
4470          * blocked, but we can not be sure. So, go ahead and call the
4471          * emergency interrupt handlers for FAN/PS devices and mask
4472          * their interrupts, if they aren't already masked.
4473          */
4474         if (retval == 0) {
4475                 goto intr_error;
4476         }
4477 
4478         retval = 0;
4479 
4480         /*
4481          * If SCB 1.5 or 2.0, check for the INIT_SCB Interrupt
4482          * to support Hot SCB Insertion.
4483          * The check was moved here during debugging of the SCB hot insertion.
4484          * Theoretically, this code could be moved back to the check for
4485          * SCTRL_EVENT_SCB in the processing loop below.
4486          */
4487         if (IS_SCB_P15) {
4488                 int     iid;
4489                 iid = SCSB_REG_INDEX(intr_addr);
4490                 offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE);
4491                 tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15);
4492                 intr_idx = SCSB_REG_INDEX(tmp_reg) - iid;
4493                 clr_bits = 1 << offset;
4494                 if (scb_intr_regs[intr_idx] & clr_bits) {
4495                         /*
4496                          * Must be newly inserted SCB
4497                          * Time to re-initialize.
4498                          */
4499                         if (scsb_debug & 0x00023000) {
4500                                 cmn_err(CE_NOTE,
4501                                     "scsb_intr(%d): INIT_SCB INT",
4502                                     scsb->scsb_instance);
4503                         }
4504                         scsb_restore(scsb);
4505                         retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4506                         /*
4507                          * The INTSRC bit will be cleared by the
4508                          * scsb_restore() function.
4509                          * Also, leave the bit set in scb_intr_regs[] so we can
4510                          * report the event code as we check for other
4511                          * interrupt source bits.
4512                          *
4513                          * scsb_write_mask(scsb, tmp_reg, 0, clr_bits, 0);
4514                          * scb_intr_regs[intr_idx] &= ~clr_bits;
4515                          */
4516                 }
4517                 /*
4518                  * In case this is a power down interrupt, check the validity
4519                  * of the request to make sure it's not an I2C noise
4520                  */
4521                 offset = FRU_OFFSET(SCTRL_EVENT_PWRDWN,
4522                     SCTRL_INTPTR_BASE);
4523                 clr_bits = 1 << offset;
4524                 intr_reg = scb_intr_regs[intr_idx];
4525                 if (intr_reg & clr_bits) {
4526                         /*
4527                          * A shutdown request has been detected. Poll
4528                          * the corresponding register ? more times to
4529                          * make sure it's a genuine shutdown request.
4530                          */
4531                         for (i = 0; i < scsb_shutdown_count; i++) {
4532                                 drv_usecwait(1000);
4533                                 if (scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg,
4534                                     1, &intr_reg, 1)) {
4535                                         cmn_err(CE_WARN, "Failed to read "
4536                                             " interrupt register");
4537                                         goto intr_error;
4538                                 }
4539                                 if (scsb_debug & 0x08000000) {
4540                                         cmn_err(CE_NOTE, "scsb_intr: "
4541                                             " INTSRC6[%d]=0x%x", i,
4542                                             intr_reg);
4543                                 }
4544                                 if (!(intr_reg & clr_bits)) {
4545                                         scb_intr_regs[intr_idx] &= ~clr_bits;
4546                                         break;
4547                                 }
4548                         }
4549                 }
4550         }
4551         /*
4552          * if retval == 0, then we didn't call scsb_restore,
4553          * so we update the shadow copy of SYSCFG registers
4554          * We *MUST* read the syscfg registers before any attempt
4555          * to clear the interrupt source registers is made.
4556          */
4557         if (retval == 0 && scsb_check_config_status(scsb)) {
4558                 cmn_err(CE_WARN,
4559                     "scsb_intr: Failed read of config/status registers");
4560                 if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) {
4561                         if (!scsb_debug) {
4562                                 goto intr_error;
4563                         }
4564                 }
4565 #ifdef DEBUG
4566                 if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4567                     scsb->scsb_i2c_errcnt > scsb_err_threshold) {
4568                         scsb_failing_event(scsb);
4569                 }
4570 #endif
4571                 /*
4572                  * Allow to go on so we clear the INTSRC bits
4573                  */
4574         }
4575 
4576         /*
4577          * Read the board healthy registers here, if any of the healthy
4578          * interrupts are set.
4579          */
4580         if (IS_SCB_P15) {
4581                 intr_idx = intr_reg = 0;
4582                 intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
4583                 index = SCSB_REG_INDEX(intr_addr);
4584                 for (i = 0; i < SCTRL_BHLTHY_NUMREGS; ++i, ++intr_idx) {
4585                         scsb->scsb_data_reg[index++] =
4586                             scb_intr_regs[intr_idx] & int_masks[intr_idx];
4587                         intr_reg |= scb_intr_regs[i];
4588                 }
4589 
4590                 if (intr_reg && scsb_read_bhealthy(scsb) != 0) {
4591                         cmn_err(CE_WARN, "%s#%d: Error Reading Healthy# "
4592                             " Registers", ddi_driver_name(scsb->scsb_dev),
4593                             ddi_get_instance(scsb->scsb_dev));
4594 #ifdef DEBUG
4595                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4596                             scsb->scsb_i2c_errcnt > scsb_err_threshold) {
4597                                 scsb_failing_event(scsb);
4598                         }
4599 #endif
4600                         goto intr_error;
4601                 }
4602         }
4603 
4604         /*
4605          * We clear the interrupt source registers now itself so that
4606          * future interrupts can be latched quickly, instead of after
4607          * finishing processing of all interrupt conditions. The global
4608          * interrupt mask however remain disabled.
4609          */
4610         if (IS_SCB_P15) {
4611                 if (scsb_rdwr_register(scsb, I2C_WR, intr_addr,
4612                     SCTRL_INTR_NUMREGS, scb_intr_regs, 1)) {
4613                         cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt"
4614                             " registers.");
4615 #ifdef DEBUG
4616                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4617                             scsb->scsb_i2c_errcnt > scsb_err_threshold) {
4618                                 scsb_failing_event(scsb);
4619                         }
4620 #endif
4621                         goto intr_error;
4622                 }
4623         }
4624 
4625         /*
4626          * At this point, all interrupt source registers are read.
4627          * We only handle interrups which are not masked
4628          */
4629         for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) {
4630                 scb_intr_regs[i] &= int_masks[i];
4631         }
4632 
4633         /*
4634          * We are here means that there was some bit set in the interrupt
4635          * source register. So we must claim the interrupt no matter
4636          * whatever error we may encounter in the course of processing.
4637          */
4638         retval |= SCSB_INTR_CLAIMED;
4639 
4640         /* store config status data */
4641         tmp_reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE);
4642         index = SCSB_REG_INDEX(tmp_reg);
4643         for (i = 0; i < SCTRL_CFG_NUMREGS; ++i)
4644                 cstatus_regs[i] = scsb->scsb_data_reg[index + i];
4645         /*
4646          * Clear the event code,
4647          * then check to see what kind(s) of events we were interrupted for.
4648          * Check all SCTRL_INTSRC registers
4649          */
4650         scsb_event_code = 0;
4651         clr_bits = 0;
4652         intr_idx = 0;
4653         numregs = SCTRL_INTR_NUMREGS;
4654         index = SCSB_REG_INDEX(intr_addr);
4655         /*
4656          * If SCB 1.5, adjust some variables to skip the SCTRL_BHLTHY_REGS
4657          * which will be handled last in this function.
4658          */
4659         if (IS_SCB_P15) {
4660                 i = SCTRL_BHLTHY_NUMREGS;
4661                 intr_idx += i;
4662                 intr_addr += i;
4663                 index += i;
4664         }
4665         /*
4666          * For the rest of the INTSRC registers, we walk through the
4667          * scb_fru_offset[] table, matching register offsets with our offset
4668          * counter.  Then we check for the scb_fru_offset[] bit in intr_reg.
4669          * The scb_fru_offset[] index is now the SCTRL_EVENT code.
4670          * The code is then compared to type_to_code1[] entries to find the
4671          * fru_type.  The fru_type will help us recognize when to do
4672          * SLOT Hot Swap processing.
4673          *
4674          * offset_base:         the appropriate scb_fru_offset[] base index
4675          *                      for the INTPTR_BASE register group
4676          * offset:              bit offset found in INTSRC register
4677          * intr_idx:            index to temporary INTSRC register copies
4678          * intr:                modified copy of current INTR register
4679          * intr_addr:           SCB register address of current INTR register
4680          * index:               index to current INTR shadow register
4681          * idx:                 bit-number of current INTR event bit
4682          * uc:                  uchar_t from scb_fru_offset[] table,
4683          *                      containing register and FRU offsets.
4684          * j:                   used to walk fru_offset[] table, which is also
4685          *                      the bit-number of the current event code
4686          * code:                manufactured event code for current INT event
4687          */
4688         offset_base = FRU_OFFSET_BASE(SCTRL_INTPTR_BASE);
4689         for (offset = 0; intr_idx < numregs;
4690             ++offset, ++intr_idx, ++intr_addr, ++index) {
4691                 scsb->scsb_data_reg[index] = scb_intr_regs[intr_idx];
4692                 intr_reg = scb_intr_regs[intr_idx];
4693                 while (intr_reg) {      /* for each INTSRC bit that's set */
4694                         int             j;
4695                         uint16_t        ui;
4696                         uchar_t         uc;
4697                         idx = event_to_index((uint32_t)intr_reg); /* offset */
4698                         code = (1 << idx);                /* back to bit mask */
4699                         clr_bits |= code;
4700                         intr_reg = intr_reg & ~code;        /* clear this one   */
4701                         for (j = 0; j < MCT_MAX_FRUS; ++j) {
4702                                 /*
4703                                  * Get register offset from table and check
4704                                  * for a match with our loop offset counter.
4705                                  * Then check for intr_reg bit-offset match
4706                                  * with bit-offset from table entry.
4707                                  */
4708                                 uc = scb_fru_offset[offset_base + j];
4709                                 if (offset != ((uc >> 4) & 0xf)) {
4710                                         if (IS_SCB_P10)
4711                                                 continue;
4712                                         if (j != FRU_INDEX(SCTRL_EVENT_SCB))
4713                                                 continue;
4714                                         if (offset != ((uc >> 4) & 0xf)
4715                                             + SCB_INT_OFFSET)
4716                                                 continue;
4717                                 }
4718                                 if (idx == (uc & 0xf))
4719                                         break;
4720                         }
4721                         if (uc == 0xff) {
4722                                 /*
4723                                  * bit idx not recognized, check another.
4724                                  */
4725                                 continue;
4726                         }
4727                         /*
4728                          * We found the fru_offset[] entry, now use the index
4729                          * to get the event code.
4730                          */
4731                         code = (uint32_t)(1 << j);
4732                         if (scsb_debug & 0x00002000) {
4733                                 cmn_err(CE_NOTE, "scsb_intr: code=0x%x", code);
4734                         }
4735                         /*
4736                          * Now check for the NON-FRU type events.
4737                          */
4738                         if (code ==  SCTRL_EVENT_PWRDWN) {
4739                                 if (scsb_debug & 0x1002) {
4740                                         cmn_err(CE_NOTE,
4741                                             "scsb_intr(%d): power down req."
4742                                             " INT.", scsb->scsb_instance);
4743                                 }
4744                                 scsb_event_code |= code;
4745                                 if (scsb->scsb_state & SCSB_OPEN &&
4746                                     scsb->scsb_rq != (queue_t *)NULL) {
4747                                         /*
4748                                          * inform applications using poll(2)
4749                                          * about this event, and provide the
4750                                          * event code to EnvMon scsb policy
4751                                          */
4752                                         if (!(scsb_debug & 0x00040000))
4753                                         (void) scsb_queue_put(scsb->scsb_rq, 1,
4754                                             &scsb_event_code, "scsb_intr");
4755                                         goto intr_error;
4756                                 }
4757                                 continue;
4758                         } else if (code == SCTRL_EVENT_REPLACE) {
4759                                 if (scsb_debug & 0x1002) {
4760                                         cmn_err(CE_NOTE,
4761                                             "scsb_intr(%d): replacement "
4762                                             "req. INT.",
4763                                             scsb->scsb_instance);
4764                                 }
4765                                 scsb_freeze_check(scsb);
4766                                 scsb_freeze(scsb);
4767                                 scsb_event_code |= code;
4768                                 retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4769                                 continue;
4770                         } else if (code == SCTRL_EVENT_SCB) {
4771                                 int     tmp;
4772                                 /*
4773                                  * Must be newly inserted SCB
4774                                  * Time to re-initialize.
4775                                  */
4776                                 if (scsb_debug & 0x1002) {
4777                                         cmn_err(CE_NOTE,
4778                                             "scsb_intr(%d): INIT SCB INTR",
4779                                             scsb->scsb_instance);
4780                                 }
4781                                 /*
4782                                  * SCB initialization already handled, but we
4783                                  * set the event code bit here in order to
4784                                  * report the event to interested utilities.
4785                                  *
4786                                  * scsb_restore(scsb);
4787                                  * The INTSRC bit is already cleared,
4788                                  * so we won't do it again.
4789                                  */
4790                                 tmp = FRU_OFFSET(SCTRL_EVENT_SCB,
4791                                     SCTRL_INTPTR_BASE);
4792                                 clr_bits &= ~(1 << tmp);
4793                                 scsb_event_code |= code;
4794                                 retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4795                                 continue;
4796                         } else if (code == SCTRL_EVENT_ALARM_INT) {
4797                                 /*
4798                                  * P0.6/P1.0: SCTRL_INTR_ALARM_INT is always
4799                                  * set and cannot be cleared, so ignore it.
4800                                  */
4801                                 if (!IS_SCB_P15) {
4802                                         continue;
4803                                 }
4804                                 if (scsb_debug & 0x1002) {
4805                                         cmn_err(CE_NOTE,
4806                                             "scsb_intr(%d): Alarm INT.",
4807                                             scsb->scsb_instance);
4808                                 }
4809                                 scsb_event_code |= code;
4810                                 retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4811                                 /*
4812                                  * XXX:
4813                                  * Must service the Alarm INT by clearing INT
4814                                  * condition on Alarm Card,
4815                                  * then clear the SCTRL_INTR_ALARM_INT bit here.
4816                                  * Waiting for specs and test environment.
4817                                  */
4818                                 continue;
4819                         } else if ((ui = event_to_type(code)) == 0xffff) {
4820                                 /*
4821                                  * FRU type not found
4822                                  */
4823                                 break;
4824                         }
4825                         /*
4826                          * Check for special processing
4827                          * now that we found the FRU type.
4828                          */
4829                         fru_type = (scsb_utype_t)(ui & 0xff);
4830                         unit = (ui >> 8) & 0xff;
4831                         if (scsb_debug & 0x00002000) {
4832                                 cmn_err(CE_NOTE, "scsb_intr: "
4833                                     "FRU type/unit/code %d/%d/0x%x",
4834                                     fru_type, unit, code);
4835                         }
4836                         switch (fru_type) {
4837                         case PDU:
4838                                 break;
4839                         case PS:
4840                                 break;
4841                         case DISK:
4842                                 break;
4843                         case FAN:
4844                                 break;
4845                         case SSB:
4846                                 /*
4847                                  * in check_fru_info() below, we see if the
4848                                  * SSB has been removed, then check for
4849                                  * occupied slots in reset to see if we should
4850                                  * WARN agains SCB removal
4851                                  */
4852                                 break;
4853                         case CFTM:
4854                                 break;
4855                         case CRTM:
4856                                 break;
4857                         case PRTM:
4858                                 break;
4859                         case SLOT:
4860                                 slotnum = tonga_ssl_to_psl(scsb, unit);
4861                                 if (scsb_debug & 0x00002000) {
4862                                         cmn_err(CE_NOTE, "scsb_intr: "
4863                                             "unit/slot %d/%d",
4864                                             unit, slotnum);
4865                                 }
4866 
4867                                 /*
4868                                  * If the slot number is not valid, continue.
4869                                  */
4870                                 if (scsb->scsb_state & SCSB_IS_TONGA) {
4871                                         if (slotnum > TG_MAX_SLOTS ||
4872                                             slotnum == SC_TG_CPU_SLOT) {
4873                                                 continue;
4874                                         }
4875                                         /*
4876                                          * For a tonga, we need to return
4877                                          * the code corresponding to the
4878                                          * actual physical slot
4879                                          */
4880                                         code = FRU_UNIT_TO_EVCODE(SLOT,
4881                                             slotnum);
4882                                 } else {
4883                                         if (slotnum > MC_MAX_SLOTS ||
4884                                             slotnum == SC_MC_CPU_SLOT ||
4885                                             (scsb->scsb_hsc_state &
4886                                             SCSB_HSC_CTC_PRES &&
4887                                             slotnum == SC_MC_CTC_SLOT)) {
4888                                                 continue;
4889                                         }
4890                                 }
4891                         /* FALLTHROUGH */
4892                         case ALARM:
4893                 /*
4894                  * INDENT CHEATING, 2 indentations
4895                  */
4896                 ac_present = 0;
4897                 /*
4898                  * If it is an Alarm Card Interrupt, we just do some sanity
4899                  * checks and then wait for the slot interrupt to take
4900                  * connect or disconnect action.
4901                  * XXX - Is there a gaurantee that ALARM int will occur first ?
4902                  */
4903                 if (fru_type == ALARM) {
4904                         DEBUG2("AC Intr %d(%d)\n", scsb->ac_slotnum, idx+1);
4905                         val = scsb_fru_op(scsb, SLOT,
4906                             tonga_ssl_to_psl(scsb, scsb->ac_slotnum),
4907                             SCTRL_SYSCFG_BASE, SCSB_FRU_OP_GET_BITVAL);
4908                         ac_present = scsb_fru_op(scsb, ALARM, 1,
4909                             SCTRL_SYSCFG_BASE,
4910                             SCSB_FRU_OP_GET_BITVAL);
4911                         /*
4912                          * It is observed that slot presence and Alarm
4913                          * presence bits do not go ON at the same time.
4914                          * Hence we wait till both events happen.
4915                          */
4916 #ifdef DEBUG
4917                         if ((((val) && (!ac_present)) ||
4918                             ((!val) && (ac_present))) &&
4919                             (scsb->scsb_hsc_state &
4920                             SCSB_AC_SLOT_INTR_DONE))
4921 
4922                                 cmn_err(CE_WARN, "?Alarm and Slot presence "
4923                                     "state bits do not match! (%x,%x)",
4924                                     val, ac_present);
4925 #endif
4926                         if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE)
4927                                 scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE;
4928                         else
4929                                 scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE;
4930                         break;  /* we break and wait for slot interrupt. */
4931                 }
4932 
4933                 /*
4934                  * cPCI slot interrupt event
4935                  */
4936                 if (scsb->scsb_state & SCSB_IS_TONGA) {
4937                         if (slotnum > TG_MAX_SLOTS ||
4938                             slotnum == SC_TG_CPU_SLOT) {
4939                                 continue;
4940                         }
4941                 } else {
4942                         if (slotnum > MC_MAX_SLOTS ||
4943                             slotnum == SC_MC_CPU_SLOT ||
4944                             (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
4945                             slotnum == SC_MC_CTC_SLOT)) {
4946                                 continue;
4947                         }
4948                 }
4949                 if (scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) {
4950                         DEBUG2("AC slot Intr %d(%d)\n", slotnum, idx+1);
4951                         ac_slot = B_TRUE;
4952                 }
4953                 val = scsb_fru_op(scsb, SLOT, unit, SCTRL_SYSCFG_BASE,
4954                     SCSB_FRU_OP_GET_BITVAL);
4955                 if (ac_slot == B_TRUE) {
4956                         ac_present = scsb_fru_op(scsb, ALARM, 1,
4957                             SCTRL_SYSCFG_BASE,
4958                             SCSB_FRU_OP_GET_BITVAL);
4959 #ifdef DEBUG
4960                         if ((((val) && (!ac_present)) ||
4961                             ((!val) && (ac_present))) &&
4962                             (scsb->scsb_hsc_state &
4963                             SCSB_AC_SLOT_INTR_DONE)) {
4964 
4965                                 cmn_err(CE_WARN, "?Alarm and Slot presence "
4966                                     "state bits do not match! (%x,%x)",
4967                                     val, ac_present);
4968                         }
4969 #endif
4970                         if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE)
4971                                 scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE;
4972                         else
4973                                 scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE;
4974                 }
4975                 if (val) {
4976                         if (ac_present) {
4977                                 DEBUG1("AC insertion on slot %d!\n", slotnum);
4978                                 if (scsb_debug & 0x00010000) {
4979                                         cmn_err(CE_NOTE, "scsb_intr: "
4980                                         "AC_PRES slot %d", slotnum);
4981                                 }
4982                                 scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
4983                         }
4984 #ifndef lint
4985                         else
4986                                 DEBUG1("IO Insertion on slot %d!\n", slotnum);
4987 #endif
4988                         /*
4989                          * Special case : check MPID type.
4990                          * If MC midplane type,
4991                          * check to make sure the Alarm Card present
4992                          * bit is ON. If not, this is a regular IO card.
4993                          */
4994                         (void) scsb_connect_slot(scsb, slotnum, B_FALSE);
4995                 } else {
4996                         if ((ac_slot == B_TRUE) &&
4997                             (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) {
4998 
4999                                 DEBUG1("AC Removal on slot %d!\n", slotnum);
5000 #ifdef DEBUG
5001                                 if (scsb_debug & 0x00010000) {
5002                                         cmn_err(CE_NOTE, "scsb_intr: "
5003                                             "!AC_PRES slot %d",
5004                                             slotnum);
5005                                 }
5006 #endif /* DEBUG */
5007                                 scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES;
5008                         }
5009 #ifndef lint
5010                         else
5011                                 DEBUG1("IO Removal on slot %d!\n", slotnum);
5012 #endif
5013                         (void) scsb_disconnect_slot(scsb, B_FALSE, slotnum);
5014                 }
5015                 /*
5016                  * END INDENT CHEATING, 2 indentations
5017                  */
5018 
5019                                 break;
5020                         default:
5021                                 /*
5022                                  * ERROR: Did not find cause of INTSRC bit
5023                                  */
5024                                 if (scsb_debug & 0x00000002) {
5025                                         cmn_err(CE_WARN,
5026                                             "scsb_intr: FRU type %d"
5027                                             " not recognized", fru_type);
5028                                 }
5029                                 continue;
5030                         }
5031                         scsb_event_code |= code;
5032                         retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
5033                         if (fru_type == SLOT)
5034                                 continue;
5035                         error = 0;
5036                         fru_ptr = mct_system_info.fru_info_list[fru_type];
5037                         for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
5038                                 if (unit != fru_ptr->fru_unit)
5039                                         continue;
5040                                 if (fru_ptr->i2c_info == NULL ||
5041                                     (tmp_reg = fru_ptr->i2c_info->
5042                                     ledata_reg) == 0)
5043                                         continue;
5044                                 error = scsb_set_scfg_pres_leds(scsb, fru_ptr);
5045                                 if (error) {
5046                                         cmn_err(CE_WARN, "scsb_intr(): "
5047                                             "I2C write error to 0x%x",
5048                                             tmp_reg);
5049                                         if (!(scsb->scsb_state &
5050                                             SCSB_DEBUG_MODE)) {
5051                                                 goto intr_error;
5052                                         }
5053                                 }
5054                                 break;
5055                         }
5056                 }
5057                 if (clr_bits) {
5058                         clr_bits = 0;
5059                 }
5060         }
5061         /*
5062          * Check for SCB 1.5 interrupt for SLOT HEALTHY changes
5063          */
5064         clr_bits = 0;
5065         intr_idx = 0;
5066         numregs = SCTRL_INTR_NUMREGS;
5067         intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
5068         index = SCSB_REG_INDEX(intr_addr);
5069         if (IS_SCB_P15) {
5070                 for (i = 0; i < SCTRL_BHLTHY_NUMREGS;
5071                     ++i, ++intr_idx, ++intr_addr) {
5072                         scsb->scsb_data_reg[index++] = scb_intr_regs[intr_idx];
5073                         intr_reg = scb_intr_regs[i];
5074                         while (intr_reg) {
5075                                 idx = event_to_index((uint32_t)intr_reg);
5076                                 code = (1 << idx);
5077                                 clr_bits |= code;
5078                                 intr_reg = intr_reg & ~code;
5079                                 /* idx + 1 because bit 0 is for Slot 1 */
5080                                 slotnum = tonga_ssl_to_psl(scsb, idx + 1);
5081                                 if (scsb->scsb_state & SCSB_IS_TONGA) {
5082                                         if (slotnum > TG_MAX_SLOTS ||
5083                                             slotnum == SC_TG_CPU_SLOT) {
5084                                                 continue;
5085                                         }
5086                                 } else {
5087                                         if (slotnum > MC_MAX_SLOTS ||
5088                                             slotnum == SC_MC_CPU_SLOT ||
5089                                             (scsb->scsb_hsc_state &
5090                                             SCSB_HSC_CTC_PRES &&
5091                                             slotnum == SC_MC_CTC_SLOT)) {
5092                                                 continue;
5093                                         }
5094                                 }
5095                                 scsb_healthy_intr(scsb, slotnum);
5096                         }
5097                         if (clr_bits) {
5098                                 clr_bits = 0;
5099                         }
5100                 }
5101         }
5102         code = scsb_event_code;
5103         if (retval & SCSB_INTR_EVENT &&
5104             !(scsb->scsb_state & SCSB_P06_NOINT_KLUGE)) {
5105                 check_fru_info(scsb, code);
5106                 add_event_code(scsb, code);
5107                 (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code,
5108                 "scsb_intr");
5109         }
5110 intr_error:
5111         scb_post_e = gethrtime();
5112 
5113         if (scsb_debug & 0x8000000)
5114                 cmn_err(CE_NOTE, "Summary of times in nsec: pre_time %llu, \
5115                         post_time %llu", scb_pre_e - scb_pre_s,
5116                     scb_post_e - scb_post_s);
5117 
5118 
5119         mutex_enter(&scsb->scsb_mutex);
5120         scsb_in_postintr = 0;
5121         cv_broadcast(&scsb->scsb_cv);
5122         mutex_exit(&scsb->scsb_mutex);
5123 
5124         /*
5125          * Re-enable interrupt now.
5126          */
5127         (void) scsb_toggle_psmint(scsb, 1);
5128         scsb->scsb_state &= ~SCSB_IN_INTR;
5129 }
5130 
5131 static int
5132 scsb_polled_int(scsb_state_t *scsb, int cmd, uint32_t *set)
5133 {
5134         if (scsb_debug & 0x4000)
5135                 cmn_err(CE_NOTE, "scsb_polled_int(scsb,0x%x)", cmd);
5136         *set = 0;
5137         if (cmd == SCSBIOC_SHUTDOWN_POLL) {
5138                 return (EINVAL);
5139         }
5140         if (cmd != SCSBIOC_INTEVENT_POLL) {
5141                 return (EINVAL);
5142         }
5143         if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) {
5144                 /*
5145                  * scsb_intr() may modify scsb_event_code
5146                  */
5147                 scsb_event_code = SCTRL_EVENT_NONE;
5148                 (void) scsb_intr((caddr_t)scsb);
5149                 *set = scsb_event_code;
5150                 scsb_event_code = 0;
5151         } else {
5152                 /*
5153                  * SCSB_P06_INTR_ON, we know there was an event
5154                  * and we're retrieving the event code from the event FIFO.
5155                  */
5156                 *set = get_event_code();
5157         }
5158         if (scsb_debug & 0x01004000) {
5159                 cmn_err(CE_NOTE, "scsb_polled_int: event_code = 0x%x", *set);
5160         }
5161         return (0);
5162 }
5163 
5164 static int
5165 scsb_leds_switch(scsb_state_t *scsb, scsb_ustate_t op)
5166 {
5167         register int    i;
5168         int             index;
5169         uchar_t         reg, idata, rwbuf[SCTRL_MAX_GROUP_NUMREGS];
5170 
5171         if (scsb->scsb_state & SCSB_FROZEN &&
5172             !(scsb->scsb_state & SCSB_IN_INTR)) {
5173                 return (EAGAIN);
5174         }
5175         if (scsb_debug & 0x0101) {
5176                 cmn_err(CE_NOTE, "scsb_leds_switch(%s):",
5177                     op == ON ? "ON" : "OFF");
5178         }
5179         /* Step 1: turn ON/OFF all NOK LEDs. */
5180         if (scsb_debug & 0x0100) {
5181                 cmn_err(CE_NOTE, "scsb%d: turning all NOK LEDs %s",
5182                     scsb->scsb_instance,
5183                     op == ON ? "ON" : "OFF");
5184         }
5185         if (op == ON)
5186                 idata = 0xff;
5187         else    /* off */
5188                 idata = 0x00;
5189         reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE);
5190         index = SCSB_REG_INDEX(reg);
5191         for (i = 0; i < SCTRL_LED_NOK_NUMREGS;  ++i) {
5192                 rwbuf[i] = idata;
5193                 scsb->scsb_data_reg[index + i] = idata;
5194         }
5195         mutex_enter(&scsb->scsb_mutex);
5196         i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_NOK_NUMREGS,
5197             rwbuf, 1);
5198         mutex_exit(&scsb->scsb_mutex);
5199         if (i) {
5200                 if (scsb_debug & 0x0102)
5201                         cmn_err(CE_WARN, "scsb_leds_switch(): "
5202                             "Failed to turn %s NOK LEDs",
5203                             op == ON ? "ON" : "OFF");
5204         }
5205         /* Step 2: turn ON/OFF all OK LEDs. */
5206         if (scsb_debug & 0x0100) {
5207                 cmn_err(CE_NOTE, "scsb%d: turning all OK LEDs %s",
5208                     scsb->scsb_instance,
5209                     op == ON ? "ON" : "OFF");
5210         }
5211         reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
5212         index = SCSB_REG_INDEX(reg);
5213         for (i = 0; i < SCTRL_LED_OK_NUMREGS;  ++i) {
5214                 rwbuf[i] = idata;
5215                 scsb->scsb_data_reg[index + i] = idata;
5216         }
5217         mutex_enter(&scsb->scsb_mutex);
5218         i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_OK_NUMREGS,
5219             rwbuf, 1);
5220         mutex_exit(&scsb->scsb_mutex);
5221         if (i) {
5222                 if (scsb_debug & 0x0102)
5223                         cmn_err(CE_WARN, "scsb_leds_switch(): "
5224                             "Failed to turn %s NOK LEDs",
5225                             op == ON ? "ON" : "OFF");
5226         }
5227         /* Step 3: turn OFF all BLINK LEDs. */
5228         if (op == OFF) {
5229                 reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
5230                 index = SCSB_REG_INDEX(reg);
5231                 for (i = 0; i < SCTRL_BLINK_NUMREGS;  ++i) {
5232                         rwbuf[i] = idata;
5233                         scsb->scsb_data_reg[index + i] = idata;
5234                 }
5235                 mutex_enter(&scsb->scsb_mutex);
5236                 i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_BLINK_NUMREGS,
5237                     rwbuf, 1);
5238                 mutex_exit(&scsb->scsb_mutex);
5239                 if (i) {
5240                         if (scsb_debug & 0x0102)
5241                                 cmn_err(CE_WARN, "scsb_leds_switch(): "
5242                                     "Failed to turn %s BLINK BITs",
5243                                     op == ON ? "ON" : "OFF");
5244                 }
5245         }
5246         return (0);
5247 }
5248 
5249 static int
5250 scsb_readall_regs(scsb_state_t *scsb)
5251 {
5252         int             error;
5253         int             index;
5254         uchar_t         reg;
5255 
5256         if (!(scsb_debug & 0x40000000))
5257                 return (0);
5258         if (scsb_debug & 0x0005) {
5259                 cmn_err(CE_NOTE, "scsb_readall_regs:");
5260         }
5261         if (scsb->scsb_state & SCSB_FROZEN) {
5262                 return (EAGAIN);
5263         }
5264         reg = SCSB_REG_ADDR_START;      /* 1st register in set */
5265         index = SCSB_REG_INDEX(reg);
5266         error = scsb_rdwr_register(scsb, I2C_WR_RD, reg, SCSB_DATA_REGISTERS,
5267             &scsb->scsb_data_reg[index], 1);
5268         return (error);
5269 }
5270 
5271 
5272 /*
5273  * read 1-byte register, mask with read bits (rmask),
5274  * turn ON bits in on_mask, turn OFF bits in off_mask
5275  * write the byte back to register
5276  * NOTE: MUST be called with mutex held
5277  */
5278 static int
5279 scsb_write_mask(scsb_state_t *scsb,
5280                 uchar_t reg,
5281                 uchar_t rmask,
5282                 uchar_t on_mask,
5283                 uchar_t off_mask)
5284 {
5285         i2c_transfer_t  *i2cxferp;
5286         int             index, error = 0;
5287         uchar_t         reg_data;
5288 
5289         if (scsb_debug & 0x0800) {
5290                 cmn_err(CE_NOTE, "scsb_write_mask(,%x,,%x,%x):",
5291                     reg, on_mask, off_mask);
5292         }
5293         if (scsb->scsb_state & SCSB_FROZEN &&
5294             !(scsb->scsb_state & SCSB_IN_INTR)) {
5295                 return (EAGAIN);
5296         }
5297         /* select the register address and read the register */
5298         i2cxferp = (i2c_transfer_t *)scsb->scsb_i2ctp;
5299         i2cxferp->i2c_flags = I2C_WR_RD;
5300         i2cxferp->i2c_wlen = 1;
5301         i2cxferp->i2c_rlen = 1;
5302         i2cxferp->i2c_wbuf[0] = reg;
5303         i2cxferp->i2c_rbuf[0] = 0;
5304         scsb->scsb_kstat_flag = B_TRUE;      /* we did a i2c transaction */
5305         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
5306                 error = EIO;
5307                 goto wm_error;
5308         }
5309         scsb->scsb_i2c_errcnt = 0;
5310         if (scsb_debug & 0x0800)
5311                 cmn_err(CE_NOTE, "scsb_write_mask() read 0x%x",
5312                     i2cxferp->i2c_rbuf[0]);
5313         reg_data = i2cxferp->i2c_rbuf[0];
5314         if (rmask)
5315                 reg_data &= rmask;
5316         if (off_mask)
5317                 reg_data &= ~off_mask;
5318         if (on_mask)
5319                 reg_data |= on_mask;
5320         i2cxferp->i2c_flags = I2C_WR;
5321         i2cxferp->i2c_wlen = 2;
5322         i2cxferp->i2c_wbuf[0] = reg;
5323         i2cxferp->i2c_wbuf[1] = reg_data;
5324         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
5325                 error = EIO;
5326                 goto wm_error;
5327         }
5328         /* keep shadow registers updated */
5329         index = SCSB_REG_INDEX(reg);
5330         scsb->scsb_data_reg[index] = reg_data;
5331         if (scsb_debug & 0x0800)
5332                 cmn_err(CE_NOTE, "scsb_write_mask() wrote 0x%x", reg_data);
5333         scsb->scsb_i2c_errcnt = 0;
5334         return (error);
5335 wm_error:
5336         scsb->scsb_i2c_errcnt++;
5337         if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
5338                 scsb->scsb_err_flag = B_TRUE; /* latch error */
5339         if (scsb->scsb_state & SCSB_SSB_PRESENT) {
5340                 if (scsb_debug & 0x0802)
5341                         cmn_err(CE_WARN,
5342                             "scsb_write_mask(): reg %x %s error, data=%x",
5343                             reg,
5344                             i2cxferp->i2c_flags & I2C_WR ? "write" : "read",
5345                             i2cxferp->i2c_flags & I2C_WR ?
5346                             i2cxferp->i2c_wbuf[1] : i2cxferp->i2c_rbuf[0]);
5347         } else {
5348                 if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
5349                         scsb_freeze(scsb);
5350                 return (EAGAIN);
5351         }
5352         return (error);
5353 }
5354 
5355 /*
5356  * read/write len consecutive single byte registers to/from rbuf
5357  * NOTE: should be called with mutex held
5358  */
5359 static int
5360 scsb_rdwr_register(scsb_state_t *scsb, int op, uchar_t reg, int len,
5361                                 uchar_t *rwbuf, int i2c_alloc)
5362 {
5363         i2c_transfer_t  *i2cxferp;
5364         int             i, rlen, wlen, index, error = 0;
5365 
5366         if (scsb_debug & 0x0800) {
5367                 cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):",
5368                     (op == I2C_WR) ? "write" : "read",  reg, len);
5369         }
5370         if (scsb->scsb_state & SCSB_FROZEN &&
5371             !(scsb->scsb_state & SCSB_IN_INTR)) {
5372                 return (EAGAIN);
5373         }
5374         if (i2c_alloc) {
5375                 i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP);
5376                 if (i2cxferp == NULL) {
5377                         if (scsb_debug & 0x0042)
5378                                 cmn_err(CE_WARN, "scsb_rdwr_register: "
5379                                     "i2ctx allocation failure");
5380                         return (ENOMEM);
5381                 }
5382         } else {
5383                 i2cxferp = scsb->scsb_i2ctp;
5384         }
5385         index = SCSB_REG_INDEX(reg);
5386         switch (op) {
5387         case I2C_WR:
5388                 wlen = len + 1; /* add the address */
5389                 rlen = 0;
5390                 i2cxferp->i2c_wbuf[0] = reg;
5391                 for (i = 0; i < len; ++i) {
5392                         scsb->scsb_data_reg[index + i] =
5393                             i2cxferp->i2c_wbuf[1 + i] = rwbuf[i];
5394                         if (scsb_debug & 0x0080)
5395                                 cmn_err(CE_NOTE,
5396                                 "scsb_rdwr_register: writing rwbuf[%d]=0x%x",
5397                                     i, rwbuf[i]);
5398                 }
5399                 break;
5400         case I2C_WR_RD:
5401                 wlen = 1;       /* for the address */
5402                 rlen = len;
5403                 i2cxferp->i2c_wbuf[0] = reg;
5404                 break;
5405         default:
5406                 if (i2c_alloc)
5407                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
5408                 return (EINVAL);
5409         }
5410         /* select the register address */
5411         i2cxferp->i2c_flags = op;
5412         i2cxferp->i2c_rlen = rlen;
5413         i2cxferp->i2c_wlen = wlen;
5414         i2cxferp->i2c_wbuf[0] = reg;
5415         scsb->scsb_kstat_flag = B_TRUE;      /* we did a i2c transaction */
5416         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
5417                 error = EIO;
5418         } else if (rlen) {
5419                 /* copy to rwbuf[] and keep shadow registers updated */
5420                 for (i = 0; i < len; ++i) {
5421                         scsb->scsb_data_reg[index + i] = rwbuf[i] =
5422                             i2cxferp->i2c_rbuf[i];
5423                         if (scsb_debug & 0x0080)
5424                                 cmn_err(CE_NOTE,
5425                                 "scsb_rdwr_register: read rwbuf[%d]=0x%x",
5426                                     i, rwbuf[i]);
5427                 }
5428         }
5429         if (i2c_alloc)
5430                 scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
5431         if (error) {
5432                 scsb->scsb_i2c_errcnt++;
5433                 if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
5434                         scsb->scsb_err_flag = B_TRUE; /* latch error */
5435                 if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
5436                         if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
5437                                 scsb_freeze(scsb);
5438                         return (EAGAIN);
5439                 } else {
5440                         cmn_err(CE_WARN,
5441                             "scsb_rdwr_register(): I2C read error from %x",
5442                             reg);
5443                 }
5444         } else {
5445                 scsb->scsb_i2c_errcnt = 0;
5446         }
5447 
5448         return (error);
5449 }
5450 
5451 /*
5452  * Called from scsb_intr()
5453  * First find the fru_info for this fru_id, and set fru_status for callback.
5454  * Then check for a registered call_back entry for this fru_id,
5455  * and if found, call it.
5456  * Recursize call until no EVENTS left in evcode.
5457  */
5458 static  void
5459 check_fru_info(scsb_state_t *scsb, int evcode)
5460 {
5461         struct scsb_cb_entry    *cbe_ptr;
5462         fru_info_t              *fru_ptr;
5463         fru_id_t                fru_id;
5464         scsb_fru_status_t       fru_status;
5465         int                     i, new_evcode;
5466 
5467         if (scsb_debug & 0x00100001)
5468                 cmn_err(CE_NOTE, "check_fru_info(scsb,0x%x)", evcode);
5469         if (evcode == 0)
5470                 return;
5471         i = event_to_index((uint32_t)evcode);
5472         new_evcode = evcode & ~(1 << i);
5473         if (i > MCT_MAX_FRUS) {
5474                 if (scsb_debug & 0x00100000)
5475                         cmn_err(CE_NOTE,
5476                             "check_fru_info: index %d out of range", i);
5477                 check_fru_info(scsb, new_evcode);
5478                 return;
5479         }
5480         fru_id = fru_id_table[i];
5481         fru_ptr = find_fru_info(fru_id);
5482         if (fru_ptr == (fru_info_t *)NULL) {
5483                 check_fru_info(scsb, new_evcode);
5484                 return;
5485         }
5486         update_fru_info(scsb, fru_ptr);
5487         if (fru_ptr->fru_status & FRU_PRESENT) {
5488                 fru_status = FRU_PRESENT;
5489         } else {
5490                 fru_status = FRU_NOT_PRESENT;
5491                 if (fru_ptr->fru_type == SSB) {
5492                         /*
5493                          * WARN against SCB removal if any
5494                          * occupied slots are in reset
5495                          */
5496                         scsb_freeze_check(scsb);
5497                 }
5498         }
5499         /*
5500          * check for an entry in the CallBack table
5501          */
5502         for (cbe_ptr = scsb_cb_table; cbe_ptr != NULL;
5503             cbe_ptr = cbe_ptr->cb_next) {
5504                 if (cbe_ptr->cb_fru_id == fru_id &&
5505                     cbe_ptr->cb_fru_ptr == fru_ptr) {
5506                         if (scsb_debug & 0x00800000)
5507                                 cmn_err(CE_NOTE,
5508                                     "check_fru_info: callback for FRU_ID "
5509                                     "0x%x; device is %spresent",
5510                                     (int)fru_id,
5511                                     fru_status == FRU_PRESENT ?
5512                                     "" : "not ");
5513                         (*cbe_ptr->cb_func)(
5514                             cbe_ptr->cb_softstate_ptr,
5515                             cbe_ptr->cb_event,
5516                             fru_status);
5517                         break;
5518                 }
5519         }
5520         check_fru_info(scsb, new_evcode);
5521 }
5522 
5523 /*
5524  * -----------------------------
5525  * scsb kstat support functions.
5526  * -----------------------------
5527  */
5528 /*
5529  * Create and initialize the kstat data structures
5530  */
5531 static int
5532 scsb_alloc_kstats(scsb_state_t *scsb)
5533 {
5534         kstat_named_t   *kn;
5535         /*
5536          * scsb_ks_leddata_t for "scsb_leddata"
5537          */
5538         if (scsb_debug & 0x00080001)
5539                 cmn_err(CE_NOTE,
5540                     "scsb_alloc_kstats: create scsb_leddata: %lu bytes",
5541                     sizeof (scsb_ks_leddata_t));
5542         if ((scsb->ks_leddata = kstat_create(scsb_name, scsb->scsb_instance,
5543             SCSB_KS_LEDDATA, "misc", KSTAT_TYPE_RAW,
5544             sizeof (scsb_ks_leddata_t), KSTAT_FLAG_PERSISTENT))
5545             == NULL) {
5546                 scsb->scsb_state |= SCSB_KSTATS;
5547                 scsb_free_kstats(scsb);
5548                 return (DDI_FAILURE);
5549         }
5550         scsb->ks_leddata->ks_update = update_ks_leddata;
5551         scsb->ks_leddata->ks_private = (void *)scsb;
5552         if (update_ks_leddata(scsb->ks_leddata, KSTAT_READ) != DDI_SUCCESS) {
5553                 scsb->scsb_state |= SCSB_KSTATS;
5554                 scsb_free_kstats(scsb);
5555                 return (DDI_FAILURE);
5556         }
5557         kstat_install(scsb->ks_leddata);
5558         /*
5559          * scsb_ks_state_t for "scsb_state"
5560          */
5561         if (scsb_debug & 0x00080000)
5562                 cmn_err(CE_NOTE,
5563                     "scsb_alloc_kstats: create scsb_state: %lu bytes",
5564                     sizeof (scsb_ks_state_t));
5565         if ((scsb->ks_state = kstat_create(scsb_name, scsb->scsb_instance,
5566             SCSB_KS_STATE, "misc", KSTAT_TYPE_RAW,
5567             sizeof (scsb_ks_state_t), KSTAT_FLAG_PERSISTENT))
5568             == NULL) {
5569                 scsb->scsb_state |= SCSB_KSTATS;
5570                 scsb_free_kstats(scsb);
5571                 return (DDI_FAILURE);
5572         }
5573         scsb->ks_state->ks_update = update_ks_state;
5574         scsb->ks_state->ks_private = (void *)scsb;
5575         if (update_ks_state(scsb->ks_state, KSTAT_READ) != DDI_SUCCESS) {
5576                 scsb->scsb_state |= SCSB_KSTATS;
5577                 scsb_free_kstats(scsb);
5578                 return (DDI_FAILURE);
5579         }
5580         kstat_install(scsb->ks_state);
5581         /*
5582          * mct_topology_t for "env_topology"
5583          */
5584         if (scsb_debug & 0x00080000)
5585                 cmn_err(CE_NOTE,
5586                     "scsb_alloc_kstats: create env_toploogy: %lu bytes",
5587                     sizeof (mct_topology_t));
5588         if ((scsb->ks_topology = kstat_create(scsb_name, scsb->scsb_instance,
5589             SCSB_KS_TOPOLOGY, "misc", KSTAT_TYPE_RAW,
5590             sizeof (mct_topology_t), KSTAT_FLAG_PERSISTENT))
5591             == NULL) {
5592                 scsb->scsb_state |= SCSB_KSTATS;
5593                 scsb_free_kstats(scsb);
5594                 return (DDI_FAILURE);
5595         }
5596         scsb->ks_topology->ks_update = update_ks_topology;
5597         scsb->ks_topology->ks_private = (void *)scsb;
5598         if (update_ks_topology(scsb->ks_topology, KSTAT_READ) != DDI_SUCCESS) {
5599                 scsb->scsb_state |= SCSB_KSTATS;
5600                 scsb_free_kstats(scsb);
5601                 return (DDI_FAILURE);
5602         }
5603         kstat_install(scsb->ks_topology);
5604         /*
5605          * kstat_named_t * 2 for "scsb_evc_register"
5606          */
5607         if (scsb_debug & 0x00080001)
5608                 cmn_err(CE_NOTE,
5609                     "scsb_alloc_kstats: create scsb_evc_register: %lu bytes",
5610                     sizeof (kstat_named_t) * 2);
5611         if ((scsb->ks_evcreg = kstat_create(scsb_name, scsb->scsb_instance,
5612             SCSB_KS_EVC_REGISTER, "misc", KSTAT_TYPE_NAMED, 2,
5613             KSTAT_FLAG_PERSISTENT|KSTAT_FLAG_WRITABLE)) == NULL) {
5614                 scsb->scsb_state |= SCSB_KSTATS;
5615                 scsb_free_kstats(scsb);
5616                 return (DDI_FAILURE);
5617         }
5618         scsb->ks_evcreg->ks_update = update_ks_evcreg;
5619         scsb->ks_evcreg->ks_private = (void *)scsb;
5620         kn = KSTAT_NAMED_PTR(scsb->ks_evcreg);
5621         kstat_named_init(&kn[0], "pid_register", KSTAT_DATA_INT64);
5622         kstat_named_init(&kn[1], "pid_unregister", KSTAT_DATA_INT64);
5623         kstat_install(scsb->ks_evcreg);
5624         /*
5625          * Done, set the flag for scsb_detach() and other checks
5626          */
5627         scsb->scsb_state |= SCSB_KSTATS;
5628         return (DDI_SUCCESS);
5629 }
5630 
5631 static int
5632 update_ks_leddata(kstat_t *ksp, int rw)
5633 {
5634         scsb_state_t            *scsb;
5635         scsb_ks_leddata_t       *pks_leddata;
5636         int                     i, numregs, index, error = DDI_SUCCESS;
5637         uchar_t                 reg;
5638 
5639         scsb = (scsb_state_t *)ksp->ks_private;
5640         if (scsb_debug & 0x00080001)
5641                 cmn_err(CE_NOTE, "update_ks_leddata: KS_UPDATE%sset",
5642                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5643         /*
5644          * Since this is satisfied from the shadow registers, let it succeed
5645          * even if the SCB is not present.  It would be nice to return the
5646          * shadow values with a warning.
5647          *
5648          * if (scsb->scsb_state & SCSB_FROZEN) {
5649          *      return (DDI_FAILURE);
5650          * }
5651          */
5652         if (rw == KSTAT_WRITE) {
5653                 return (EACCES);
5654         }
5655         mutex_enter(&scsb->scsb_mutex);
5656         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5657                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5658                         mutex_exit(&scsb->scsb_mutex);
5659                         return (EINTR);
5660                 }
5661         }
5662         scsb->scsb_state |= SCSB_KS_UPDATE;
5663         mutex_exit(&scsb->scsb_mutex);
5664         if (scsb_debug & 0x00080001)
5665                 cmn_err(CE_NOTE, "update_ks_leddata: updating data");
5666         pks_leddata = (scsb_ks_leddata_t *)ksp->ks_data;
5667         /*
5668          * Call tonga_slotnum_led_shift() for each register that
5669          * contains Slot 1-5 information, the first register at each base:
5670          * NOK_BASE, OK_BASE, BLINK_OK_BASE
5671          * XXX: breaking register table access rules by not using macros.
5672          */
5673         /* NOK */
5674         reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE);
5675         index = SCSB_REG_INDEX(reg);
5676         numregs = SCTRL_LED_NOK_NUMREGS;
5677         i = 0;
5678         if (IS_SCB_P15)
5679                 reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
5680         else
5681                 reg = scsb->scsb_data_reg[index];
5682         pks_leddata->scb_led_regs[i] = reg;
5683         for (++i, ++index; i < numregs; ++i, ++index)
5684                 pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
5685         /* OK */
5686         reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
5687         index = SCSB_REG_INDEX(reg);
5688         numregs += SCTRL_LED_OK_NUMREGS;
5689         if (IS_SCB_P15)
5690                 reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
5691         else
5692                 reg = scsb->scsb_data_reg[index];
5693         pks_leddata->scb_led_regs[i] = reg;
5694         for (++i, ++index; i < numregs; ++i, ++index)
5695                 pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
5696         /* BLINK */
5697         reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
5698         index = SCSB_REG_INDEX(reg);
5699         numregs += SCTRL_BLINK_NUMREGS;
5700         if (IS_SCB_P15)
5701                 reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
5702         else
5703                 reg = scsb->scsb_data_reg[index];
5704         pks_leddata->scb_led_regs[i] = reg;
5705         for (++i, ++index; i < numregs; ++i, ++index)
5706                 pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
5707         mutex_enter(&scsb->scsb_mutex);
5708         scsb->scsb_state &= ~SCSB_KS_UPDATE;
5709         cv_signal(&scsb->scsb_cv);
5710         mutex_exit(&scsb->scsb_mutex);
5711         if (scsb_debug & 0x00080001)
5712                 cmn_err(CE_NOTE, "update_ks_leddata: returning");
5713         return (error);
5714 }
5715 
5716 static int
5717 update_ks_evcreg(kstat_t *ksp, int rw)
5718 {
5719         scsb_state_t            *scsb;
5720         int                     error = 0;
5721         kstat_named_t           *kn = KSTAT_NAMED_PTR(ksp);
5722         pid_t                   pid;
5723 
5724         scsb = (scsb_state_t *)ksp->ks_private;
5725         if (scsb_debug & 0x00080001)
5726                 cmn_err(CE_NOTE, "update_ks_evcreg: %s(%d), KS_UPDATE%sset",
5727                     rw == KSTAT_READ ? "read" : "write", rw,
5728                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5729         /*
5730          * Let this registration succeed
5731          *
5732          * if (scsb->scsb_state & SCSB_FROZEN) {
5733          *      return (DDI_FAILURE);
5734          * }
5735          */
5736         mutex_enter(&scsb->scsb_mutex);
5737         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5738                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5739                         mutex_exit(&scsb->scsb_mutex);
5740                         return (EINTR);
5741                 }
5742         }
5743         scsb->scsb_state |= SCSB_KS_UPDATE;
5744         mutex_exit(&scsb->scsb_mutex);
5745         if (rw == KSTAT_READ) {
5746                 kn[0].value.i64 = (int64_t)0;
5747                 kn[1].value.i64 = (int64_t)0;
5748         } else if (rw == KSTAT_WRITE) {
5749                 /*
5750                  * kn[0] is "pid_register", kn[1] is "pid_unregister"
5751                  */
5752                 if (kn[0].value.i64 != 0 && kn[1].value.i64 == 0) {
5753                         pid = (pid_t)kn[0].value.i64;
5754                         if (add_event_proc(scsb, pid)) {
5755                                 if (scsb_debug & 0x02000002) {
5756                                         cmn_err(CE_WARN,
5757                                             "update_ks_evcreg: "
5758                                             "process add failed for %d",
5759                                             pid);
5760                                 }
5761                                 error = EOVERFLOW;
5762                         }
5763                 } else if (kn[0].value.i64 == 0 && kn[1].value.i64 != 0) {
5764                         pid = (pid_t)kn[1].value.i64;
5765                         if (del_event_proc(scsb, pid)) {
5766                                 if (scsb_debug & 0x02000000) {
5767                                         cmn_err(CE_NOTE,
5768                                             "update_ks_evcreg: "
5769                                             "process delete failed for %d",
5770                                             pid);
5771                                 }
5772                                 error = EOVERFLOW;
5773                         }
5774                 } else if (kn[0].value.i64 == 0 && kn[1].value.i64 == 0) {
5775                         /*
5776                          * rewind the pointers and counts, zero the table.
5777                          */
5778                         rew_event_proc(scsb);
5779                 } else {
5780                         error = EINVAL;
5781                 }
5782         } else {
5783                 error = EINVAL;
5784         }
5785         mutex_enter(&scsb->scsb_mutex);
5786         scsb->scsb_state &= ~SCSB_KS_UPDATE;
5787         cv_signal(&scsb->scsb_cv);
5788         mutex_exit(&scsb->scsb_mutex);
5789         return (error);
5790 }
5791 
5792 static int
5793 update_ks_state(kstat_t *ksp, int rw)
5794 {
5795         scsb_state_t            *scsb;
5796         scsb_ks_state_t         *pks_state;
5797         int                     error = DDI_SUCCESS;
5798         uint32_t                current_evc;
5799 
5800         scsb = (scsb_state_t *)ksp->ks_private;
5801         if (scsb_debug & 0x00080001)
5802                 cmn_err(CE_NOTE, "update_ks_state: KS_UPDATE%sset",
5803                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5804         /*
5805          * Let this succeed based on last known data
5806          *
5807          * if (scsb->scsb_state & SCSB_FROZEN) {
5808          *      return (DDI_FAILURE);
5809          * }
5810          */
5811         if (rw == KSTAT_WRITE) {
5812                 return (EACCES);
5813         }
5814         mutex_enter(&scsb->scsb_mutex);
5815         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5816                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5817                         mutex_exit(&scsb->scsb_mutex);
5818                         return (EINTR);
5819                 }
5820         }
5821         scsb->scsb_state |= SCSB_KS_UPDATE;
5822         /*
5823          * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence
5824          * by initiating an I2C read from the SCB.  If an error occurs,
5825          * scsb_freeze() will be called to update SCB info and scsb state.
5826          */
5827         if (!(scsb->scsb_state & SCSB_SSB_PRESENT) &&
5828             !(scsb->scsb_state & SCSB_FROZEN)) {
5829                 uchar_t         data;
5830                 /* Read the SCB PROM ID */
5831                 if (data = scsb_rdwr_register(scsb, I2C_WR_RD,
5832                     (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1))
5833                         if (scsb_debug & 0x00080002)
5834                                 cmn_err(CE_NOTE, "update_ks_state: SCB/I2C "
5835                                     "failure %d", data);
5836         }
5837         mutex_exit(&scsb->scsb_mutex);
5838         pks_state = (scsb_ks_state_t *)ksp->ks_data;
5839         pks_state->scb_present = (scsb->scsb_state & SCSB_SCB_PRESENT) ? 1 : 0;
5840         pks_state->ssb_present = (scsb->scsb_state & SCSB_SSB_PRESENT) ? 1 : 0;
5841         pks_state->scsb_frozen = (scsb->scsb_state & SCSB_FROZEN) ? 1 : 0;
5842         if (scsb->scsb_state & SCSB_DEBUG_MODE)
5843                 pks_state->scsb_mode = (uint8_t)ENVC_DEBUG_MODE;
5844         else if (scsb->scsb_state & SCSB_DIAGS_MODE)
5845                 pks_state->scsb_mode = (uint8_t)ENVCTRL_DIAG_MODE;
5846         else
5847                 pks_state->scsb_mode = (uint8_t)ENVCTRL_NORMAL_MODE;
5848         /*
5849          * If scsb_attach() has not completed the kstat installs,
5850          * then there are no event processes to check for.
5851          */
5852         if (scsb->scsb_state & SCSB_KSTATS) {
5853                 switch (check_event_procs(&current_evc)) {
5854                 case EVC_NO_EVENT_CODE:
5855                         pks_state->event_code = 0;
5856                         break;
5857                 case EVC_NEW_EVENT_CODE:
5858                 /* FALLTHROUGH */
5859                 case EVC_NO_CURR_PROC:
5860                         pks_state->event_code = current_evc;
5861                         break;
5862                 case EVC_OR_EVENT_CODE:
5863                         pks_state->event_code |= current_evc;
5864                         break;
5865                 case EVC_FAILURE:
5866                         pks_state->event_code = 0;
5867                         error = DDI_FAILURE;
5868                         break;
5869                 }
5870         } else {
5871                 pks_state->event_code = 0;
5872         }
5873         mutex_enter(&scsb->scsb_mutex);
5874         scsb->scsb_state &= ~SCSB_KS_UPDATE;
5875         cv_signal(&scsb->scsb_cv);
5876         mutex_exit(&scsb->scsb_mutex);
5877         return (error);
5878 }
5879 
5880 static int
5881 update_ks_topology(kstat_t *ksp, int rw)
5882 {
5883         scsb_state_t            *scsb;
5884         mct_topology_t          *pks_topo;
5885         fru_info_t              *fru_ptr;
5886         int                     i, val, error = DDI_SUCCESS, slotnum;
5887 
5888         scsb = (scsb_state_t *)ksp->ks_private;
5889         if (scsb_debug & 0x00080001)
5890                 cmn_err(CE_NOTE, "update_ks_topology: KS_UPDATE%sset",
5891                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5892         /*
5893          * Let this succeed based on last known data
5894          *
5895          * if (scsb->scsb_state & SCSB_FROZEN) {
5896          *      return (DDI_FAILURE);
5897          * }
5898          */
5899         if (rw == KSTAT_WRITE) {
5900                 return (EACCES);
5901         }
5902         mutex_enter(&scsb->scsb_mutex);
5903         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5904                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5905                         mutex_exit(&scsb->scsb_mutex);
5906                         return (EINTR);
5907                 }
5908         }
5909         scsb->scsb_state |= SCSB_KS_UPDATE;
5910         /*
5911          * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence
5912          * by initiating an I2C read from the SCB.  If an error occurs,
5913          * scsb_freeze() will be called to update SCB info and scsb state.
5914          */
5915         if (!(scsb->scsb_state & SCSB_SSB_PRESENT) &&
5916             !(scsb->scsb_state & SCSB_FROZEN)) {
5917                 uchar_t         data;
5918                 /* Read the SCB PROM ID */
5919                 if (data = scsb_rdwr_register(scsb, I2C_WR_RD,
5920                     (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1))
5921                         if (scsb_debug & 0x00080002)
5922                                 cmn_err(CE_NOTE, "update_ks_topology: SCB/I2C "
5923                                     "failure %d", data);
5924         }
5925         mutex_exit(&scsb->scsb_mutex);
5926         pks_topo = (mct_topology_t *)ksp->ks_data;
5927         for (i = SLOT; i < SCSB_UNIT_TYPES; ++i) {
5928                 pks_topo->max_units[i] = mct_system_info.max_units[i];
5929         }
5930 
5931         pks_topo->mid_plane.fru_status = FRU_PRESENT;
5932         pks_topo->mid_plane.fru_unit = (scsb_unum_t)1;
5933         pks_topo->mid_plane.fru_type = mct_system_info.mid_plane.fru_type;
5934         pks_topo->mid_plane.fru_id = mct_system_info.mid_plane.fru_id;
5935         pks_topo->mid_plane.fru_version = mct_system_info.mid_plane.fru_version;
5936         pks_topo->mid_plane.fru_health = MCT_HEALTH_OK;
5937         fru_ptr = mct_system_info.fru_info_list[SLOT];
5938         for (i = 0; i < pks_topo->max_units[SLOT]; ++i, ++fru_ptr) {
5939                 pks_topo->mct_slots[i].fru_status = fru_ptr->fru_status;
5940                 pks_topo->mct_slots[i].fru_type = fru_ptr->fru_type;
5941                 pks_topo->mct_slots[i].fru_unit = fru_ptr->fru_unit;
5942                 pks_topo->mct_slots[i].fru_id = fru_ptr->fru_id;
5943                 pks_topo->mct_slots[i].fru_version = fru_ptr->fru_version;
5944                 /*
5945                  * XXX: need to check healthy regs to set fru_health
5946                  */
5947                 slotnum = tonga_psl_to_ssl(scsb, i+1);
5948                 val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
5949                     SCSB_FRU_OP_GET_BITVAL);
5950                 pks_topo->mct_slots[i].fru_health = (val) ?
5951                     MCT_HEALTH_OK : MCT_HEALTH_NOK;
5952         }
5953         fru_ptr = mct_system_info.fru_info_list[PDU];
5954         for (i = 0; i < pks_topo->max_units[PDU]; ++i, ++fru_ptr) {
5955                 pks_topo->mct_pdu[i].fru_status = fru_ptr->fru_status;
5956                 pks_topo->mct_pdu[i].fru_type = fru_ptr->fru_type;
5957                 pks_topo->mct_pdu[i].fru_unit = fru_ptr->fru_unit;
5958                 pks_topo->mct_pdu[i].fru_id = fru_ptr->fru_id;
5959                 pks_topo->mct_pdu[i].fru_version = fru_ptr->fru_version;
5960                 pks_topo->mct_pdu[i].fru_health = MCT_HEALTH_NA;
5961         }
5962         fru_ptr = mct_system_info.fru_info_list[PS];
5963         for (i = 0; i < pks_topo->max_units[PS]; ++i, ++fru_ptr) {
5964                 pks_topo->mct_ps[i].fru_status = fru_ptr->fru_status;
5965                 pks_topo->mct_ps[i].fru_type = fru_ptr->fru_type;
5966                 pks_topo->mct_ps[i].fru_unit = fru_ptr->fru_unit;
5967                 pks_topo->mct_ps[i].fru_id = fru_ptr->fru_id;
5968                 pks_topo->mct_ps[i].fru_version = fru_ptr->fru_version;
5969                 pks_topo->mct_ps[i].fru_health = MCT_HEALTH_NA;
5970         }
5971         fru_ptr = mct_system_info.fru_info_list[DISK];
5972         for (i = 0; i < pks_topo->max_units[DISK]; ++i, ++fru_ptr) {
5973                 pks_topo->mct_disk[i].fru_status = fru_ptr->fru_status;
5974                 pks_topo->mct_disk[i].fru_type = fru_ptr->fru_type;
5975                 pks_topo->mct_disk[i].fru_unit = fru_ptr->fru_unit;
5976                 pks_topo->mct_disk[i].fru_id = fru_ptr->fru_id;
5977                 pks_topo->mct_disk[i].fru_version = fru_ptr->fru_version;
5978                 pks_topo->mct_disk[i].fru_health = MCT_HEALTH_NA;
5979         }
5980         fru_ptr = mct_system_info.fru_info_list[FAN];
5981         for (i = 0; i < pks_topo->max_units[FAN]; ++i, ++fru_ptr) {
5982                 pks_topo->mct_fan[i].fru_status = fru_ptr->fru_status;
5983                 pks_topo->mct_fan[i].fru_type = fru_ptr->fru_type;
5984                 pks_topo->mct_fan[i].fru_unit = fru_ptr->fru_unit;
5985                 pks_topo->mct_fan[i].fru_id = fru_ptr->fru_id;
5986                 pks_topo->mct_fan[i].fru_version = fru_ptr->fru_version;
5987                 pks_topo->mct_fan[i].fru_health = MCT_HEALTH_NA;
5988         }
5989         fru_ptr = mct_system_info.fru_info_list[SCB];
5990         for (i = 0; i < pks_topo->max_units[SCB]; ++i, ++fru_ptr) {
5991                 pks_topo->mct_scb[i].fru_status = fru_ptr->fru_status;
5992                 pks_topo->mct_scb[i].fru_type = fru_ptr->fru_type;
5993                 pks_topo->mct_scb[i].fru_unit = fru_ptr->fru_unit;
5994                 pks_topo->mct_scb[i].fru_id = fru_ptr->fru_id;
5995                 pks_topo->mct_scb[i].fru_version = fru_ptr->fru_version;
5996                 /*
5997                  * To get the scsb health, if there was no i2c transaction
5998                  * until this read, generate an i2c transaction.
5999                  */
6000                 if (scsb->scsb_kstat_flag == B_FALSE) {
6001                         uchar_t         data;
6002                         (void) scsb_blind_read(scsb, I2C_WR_RD,
6003                             (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1);
6004                 }
6005                 pks_topo->mct_scb[i].fru_health = ((scsb->scsb_err_flag ==
6006                     B_TRUE || scsb->scsb_i2c_errcnt > scsb_err_threshold)
6007                     ?  MCT_HEALTH_NOK : MCT_HEALTH_OK);
6008 #ifdef DEBUG
6009                 if (pks_topo->mct_scb[i].fru_health == MCT_HEALTH_NOK)
6010                         cmn_err(CE_WARN, "SCSB kstat health:%d", pks_topo->
6011                             mct_scb[i].fru_health);
6012 #endif
6013                 scsb->scsb_err_flag = B_FALSE; /* clear error flag once read */
6014                 scsb->scsb_kstat_flag = B_FALSE; /* false? read from i2c */
6015         }
6016         fru_ptr = mct_system_info.fru_info_list[SSB];
6017         for (i = 0; i < pks_topo->max_units[SSB]; ++i, ++fru_ptr) {
6018                 pks_topo->mct_ssb[i].fru_status = fru_ptr->fru_status;
6019                 pks_topo->mct_ssb[i].fru_type = fru_ptr->fru_type;
6020                 pks_topo->mct_ssb[i].fru_unit = fru_ptr->fru_unit;
6021                 pks_topo->mct_ssb[i].fru_id = fru_ptr->fru_id;
6022                 pks_topo->mct_ssb[i].fru_version = fru_ptr->fru_version;
6023                 pks_topo->mct_ssb[i].fru_health = MCT_HEALTH_NA;
6024         }
6025         fru_ptr = mct_system_info.fru_info_list[ALARM];
6026         for (i = 0; i < pks_topo->max_units[ALARM]; ++i, ++fru_ptr) {
6027                 pks_topo->mct_alarm[i].fru_status = fru_ptr->fru_status;
6028                 pks_topo->mct_alarm[i].fru_type = fru_ptr->fru_type;
6029                 pks_topo->mct_alarm[i].fru_unit = fru_ptr->fru_unit;
6030                 pks_topo->mct_alarm[i].fru_id = fru_ptr->fru_id;
6031                 pks_topo->mct_alarm[i].fru_version = fru_ptr->fru_version;
6032                 pks_topo->mct_alarm[i].fru_health = MCT_HEALTH_NA;
6033         }
6034         fru_ptr = mct_system_info.fru_info_list[CFTM];
6035         for (i = 0; i < pks_topo->max_units[CFTM]; ++i, ++fru_ptr) {
6036                 pks_topo->mct_cftm[i].fru_status = fru_ptr->fru_status;
6037                 pks_topo->mct_cftm[i].fru_type = fru_ptr->fru_type;
6038                 pks_topo->mct_cftm[i].fru_unit = fru_ptr->fru_unit;
6039                 pks_topo->mct_cftm[i].fru_id = fru_ptr->fru_id;
6040                 pks_topo->mct_cftm[i].fru_version = fru_ptr->fru_version;
6041                 pks_topo->mct_cftm[i].fru_health = MCT_HEALTH_NA;
6042         }
6043         fru_ptr = mct_system_info.fru_info_list[CRTM];
6044         for (i = 0; i < pks_topo->max_units[CRTM]; ++i, ++fru_ptr) {
6045                 pks_topo->mct_crtm[i].fru_status = fru_ptr->fru_status;
6046                 pks_topo->mct_crtm[i].fru_type = fru_ptr->fru_type;
6047                 pks_topo->mct_crtm[i].fru_unit = fru_ptr->fru_unit;
6048                 pks_topo->mct_crtm[i].fru_id = fru_ptr->fru_id;
6049                 pks_topo->mct_crtm[i].fru_version = fru_ptr->fru_version;
6050                 pks_topo->mct_crtm[i].fru_health = MCT_HEALTH_NA;
6051         }
6052         fru_ptr = mct_system_info.fru_info_list[PRTM];
6053         for (i = 0; i < pks_topo->max_units[PRTM]; ++i, ++fru_ptr) {
6054                 pks_topo->mct_prtm[i].fru_status = fru_ptr->fru_status;
6055                 pks_topo->mct_prtm[i].fru_type = fru_ptr->fru_type;
6056                 pks_topo->mct_prtm[i].fru_unit = fru_ptr->fru_unit;
6057                 pks_topo->mct_prtm[i].fru_id = fru_ptr->fru_id;
6058                 pks_topo->mct_prtm[i].fru_version = fru_ptr->fru_version;
6059                 pks_topo->mct_prtm[i].fru_health = MCT_HEALTH_NA;
6060         }
6061         mutex_enter(&scsb->scsb_mutex);
6062         scsb->scsb_state &= ~SCSB_KS_UPDATE;
6063         cv_signal(&scsb->scsb_cv);
6064         mutex_exit(&scsb->scsb_mutex);
6065         return (error);
6066 }
6067 
6068 static void
6069 scsb_free_kstats(scsb_state_t *scsb)
6070 {
6071         if (!(scsb->scsb_state & SCSB_KSTATS))
6072                 return;
6073         /*
6074          * free the allocated kstat data
6075          */
6076         if (scsb->ks_evcreg != NULL) {
6077                 kstat_delete(scsb->ks_evcreg);
6078         }
6079         if (scsb->ks_topology != NULL) {
6080                 kstat_delete(scsb->ks_topology);
6081         }
6082         if (scsb->ks_state != NULL) {
6083                 kstat_delete(scsb->ks_state);
6084         }
6085         if (scsb->ks_leddata != NULL) {
6086                 kstat_delete(scsb->ks_leddata);
6087         }
6088         scsb->ks_leddata = NULL;
6089         scsb->ks_state = NULL;
6090         scsb->ks_topology = NULL;
6091         scsb->ks_evcreg = NULL;
6092         scsb->scsb_state &= ~SCSB_KSTATS;
6093 }
6094 
6095 
6096 /*
6097  * --------------------------------------
6098  * Miscellaneous scsb internal functions.
6099  * --------------------------------------
6100  *
6101  * allocate I2C transfer structure
6102  */
6103 static i2c_transfer_t *
6104 scsb_alloc_i2ctx(i2c_client_hdl_t phandle, uint_t sleep)
6105 {
6106         i2c_transfer_t  *tp;
6107 
6108         if (i2c_transfer_alloc(phandle, &tp, SCSB_DATA_REGISTERS + 2,
6109             SCSB_DATA_REGISTERS + 2, sleep) == I2C_FAILURE) {
6110                 return (NULL);
6111         }
6112         return (tp);
6113 }
6114 
6115 /*
6116  * free I2C transfer structure
6117  */
6118 static void
6119 scsb_free_i2ctx(i2c_client_hdl_t phandle, i2c_transfer_t *tp)
6120 {
6121         i2c_transfer_free(phandle, tp);
6122 }
6123 
6124 static  void
6125 update_fru_info(scsb_state_t *scsb, fru_info_t *fru_ptr)
6126 {
6127         int             index;
6128         uchar_t         reg, bit;
6129         fru_info_t      *acslot_ptr = NULL;
6130         fru_id_t        acslot_id = 0;
6131         if (scsb_debug & 0x00100001)
6132                 cmn_err(CE_NOTE, "update_fru_info(scsb,0x%p)", (void *)fru_ptr);
6133         if (fru_ptr == (fru_info_t *)NULL ||
6134             fru_ptr->i2c_info == (fru_i2c_info_t *)NULL)
6135                 return;
6136         /*
6137          * If this is an Alarm Card update, then we also need to get
6138          * Alarm Card Slot fru_ptr to update it's fru_type, and maybe fru_id
6139          */
6140         if (fru_ptr->fru_id == fru_id_table[FRU_INDEX(SCTRL_EVENT_ALARM)]) {
6141                 /*
6142                  * SCTRL_EVENT_SLOT1 == 0x01 so
6143                  * fru_id_table[] index for Slot 1 == 0
6144                  */
6145                 acslot_id = fru_id_table[(scsb->ac_slotnum - 1)];
6146                 acslot_ptr = find_fru_info(acslot_id);
6147         }
6148         reg = fru_ptr->i2c_info->syscfg_reg;
6149         bit = fru_ptr->i2c_info->syscfg_bit;
6150         if (reg == 0 && fru_ptr->fru_type == SCB) {
6151                 if (scsb->scsb_state & SCSB_SCB_PRESENT)
6152                         fru_ptr->fru_status = FRU_PRESENT;
6153                 else
6154                         fru_ptr->fru_status = FRU_NOT_PRESENT;
6155         } else if (reg) {
6156                 index = SCSB_REG_INDEX(reg);
6157                 if (scsb->scsb_data_reg[index] & (1 << bit)) {
6158                         fru_ptr->fru_status = FRU_PRESENT;
6159                         /*
6160                          * XXX: need to add version register, and maybe a
6161                          *       method, to the fru_ptr->i2c_info structure.
6162                          *
6163                          * fru_ptr->fru_version = (fru_version_t)0;
6164                          */
6165                         /*
6166                          * Because scsb_intr() sometimes gets the AC present
6167                          * INT before the ACSLOT present INT,
6168                          * do not check the ACSLOT fru_status
6169                          *
6170                          * if (acslot_ptr != NULL && acslot_ptr->fru_status ==
6171                          *                                      FRU_PRESENT)
6172                          */
6173                         if (acslot_ptr != NULL)
6174                                 acslot_ptr->fru_type = (scsb_utype_t)OC_AC;
6175                 } else {
6176                         fru_ptr->fru_status = FRU_NOT_PRESENT;
6177                         /*
6178                          * fru_ptr->fru_version = (fru_version_t)0;
6179                          */
6180                         if (acslot_ptr != NULL) {
6181                                 /* AC just removed, but AC Slot is occupied? */
6182                                 if (acslot_ptr->fru_status == FRU_PRESENT)
6183                                         /* for now it's unknown */
6184                                         acslot_ptr->fru_type =
6185                                             (scsb_utype_t)OC_UNKN;
6186                                 else
6187                                         acslot_ptr->fru_type =
6188                                             (scsb_utype_t)OC_UNKN;
6189                         }
6190                 }
6191         }
6192         if (scsb_debug & 0x00100000)
6193                 cmn_err(CE_NOTE,
6194                     "update_fru_info: type %d unit %d is %spresent",
6195                     fru_ptr->fru_type, fru_ptr->fru_unit,
6196                     fru_ptr->fru_status == FRU_PRESENT
6197                     ? "" : "not ");
6198 }
6199 
6200 /*
6201  * Convert EVENT code to FRU index
6202  * by finding the highest bit number in 32 bit word
6203  */
6204 static int
6205 event_to_index(uint32_t evcode)
6206 {
6207         int     i = 0;
6208         if (evcode == 0)
6209                 return (MCT_MAX_FRUS - 1);
6210         for (; (evcode >>= 1); i++)
6211                 ;
6212         return (i);
6213 }
6214 
6215 #ifdef DEBUG
6216 void
6217 scsb_debug_prnt(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
6218         uintptr_t a4, uintptr_t a5)
6219 {
6220         if (scsb_debug & 0x8000 ||
6221             (*fmt == 'X' && scsb_debug & 0x00010000)) {
6222                 if (*fmt == 'X')
6223                         ++fmt;
6224                 prom_printf("scsb: ");
6225                 prom_printf(fmt, a1, a2, a3, a4, a5);
6226                 prom_printf("\n");
6227         }
6228 }
6229 #endif
6230 
6231 /*
6232  * event code functions to deliver event codes
6233  * and to manage:
6234  *      the event code fifo
6235  *      the process handle table for registered processes interested in
6236  *        event codes
6237  */
6238 /*
6239  * Send signal to processes registered for event code delivery
6240  */
6241 static void
6242 signal_evc_procs(scsb_state_t *scsb)
6243 {
6244         int     i = 0, c = 0;
6245         if (evc_proc_count == 0)
6246                 return;
6247         for (; i < EVC_PROCS_MAX; ++i) {
6248                 if (evc_procs[i] != NULL) {
6249                         if (proc_signal(evc_procs[i], SIGPOLL)) {
6250                                 if (scsb_debug & 0x02000002)
6251                                         cmn_err(CE_WARN,
6252                                             "scsb:signal_evc_procs: "
6253                                             "signal to %d failed",
6254                                             ((struct pid *)
6255                                             evc_procs[i])->pid_id);
6256                                 (void) del_event_proc(scsb,
6257                                     ((struct pid *)evc_procs[i])->pid_id);
6258                         }
6259                         if (++c >= evc_proc_count) {
6260                                 if (scsb_debug & 0x02000000) {
6261                                         cmn_err(CE_NOTE,
6262                                             "signal_evc_procs: signaled "
6263                                             "%d/%d processes", c,
6264                                             evc_proc_count);
6265                                 }
6266                                 break;
6267                         }
6268                 }
6269         }
6270 }
6271 
6272 /*
6273  * bump FIFO ptr, taking care of wrap around
6274  */
6275 static uint32_t *
6276 inc_fifo_ptr(uint32_t *ptr)
6277 {
6278         if (++ptr >= evc_fifo + EVC_FIFO_SIZE)
6279                 ptr = evc_fifo;
6280         return (ptr);
6281 }
6282 
6283 /* ARGSUSED */
6284 static void
6285 reset_evc_fifo(scsb_state_t *scsb)
6286 {
6287         evc_wptr = evc_fifo;
6288         evc_rptr = evc_fifo;
6289         evc_fifo_count = 0;
6290 }
6291 
6292 /*
6293  * Called from scsb_intr() when a new event occurs, to put new code in FIFO,
6294  * and signal any interested processes in evc_procs[].
6295  * Always succeeds.
6296  */
6297 static void
6298 add_event_code(scsb_state_t *scsb, uint32_t event_code)
6299 {
6300         if (event_proc_count(scsb) == 0) {
6301                 return;
6302         }
6303         *evc_wptr = event_code;
6304         evc_wptr = inc_fifo_ptr(evc_wptr);
6305         if (++evc_fifo_count > EVC_FIFO_SIZE) {
6306                 --evc_fifo_count;               /* lose the oldest event */
6307                 evc_rptr = inc_fifo_ptr(evc_rptr);
6308         }
6309         if (scsb_debug & 0x01000000) {
6310                 cmn_err(CE_NOTE, "add_event_code: 0x%x, FIFO size = %d",
6311                     event_code, evc_fifo_count);
6312         }
6313         signal_evc_procs(scsb);
6314 }
6315 
6316 /*
6317  * called from check_event_procs() when the last registered process
6318  * retrieved the oldest event
6319  */
6320 static uint32_t
6321 del_event_code()
6322 {
6323         uint32_t evc = 0;
6324         if (!evc_fifo_count)
6325                 return (scsb_event_code);
6326         evc = *evc_rptr;
6327         evc_rptr = inc_fifo_ptr(evc_rptr);
6328         --evc_fifo_count;
6329         if (scsb_debug & 0x01000000) {
6330                 cmn_err(CE_NOTE, "del_event_code: 0x%x, FIFO size = %d",
6331                     evc, evc_fifo_count);
6332         }
6333         return (evc);
6334 }
6335 
6336 /*
6337  * called from check_event_procs() to retrieve the current event code
6338  */
6339 static uint32_t
6340 get_event_code()
6341 {
6342         if (!evc_fifo_count)
6343                 return (0);
6344         return (*evc_rptr);
6345 }
6346 
6347 /*
6348  * called from an application interface (ie: an ioctl command)
6349  * to register a process id interested in SCB events.
6350  * NOTE: proc_ref() must be called from USER context, so since this is a
6351  * streams driver, a kstat interface is used for process registration.
6352  * return:
6353  *      0 = event_proc was added
6354  *      1 = out of space
6355  */
6356 /* ARGSUSED */
6357 static int
6358 add_event_proc(scsb_state_t *scsb, pid_t pid)
6359 {
6360         int     i = 0;
6361         void    *curr_proc;
6362         pid_t   curr_pid;
6363         if (evc_proc_count >= EVC_PROCS_MAX)
6364                 return (1);
6365         curr_proc = proc_ref();
6366         curr_pid = (pid_t)(((struct pid *)curr_proc)->pid_id);
6367         if (curr_pid != pid) {
6368                 if (scsb_debug & 0x02000000) {
6369                         cmn_err(CE_WARN,
6370                             "add_event_proc: current %d != requestor %d",
6371                             curr_pid, pid);
6372                 } else {
6373                         proc_unref(curr_proc);
6374                         return (1);
6375                 }
6376         }
6377         for (; i < EVC_PROCS_MAX; ++i) {
6378                 if (evc_procs[i] == NULL) {
6379                         evc_procs[i] = curr_proc;
6380                         evc_proc_count++;
6381                         if (scsb_debug & 0x02000000) {
6382                                 cmn_err(CE_NOTE,
6383                                     "add_event_proc: %d; evc_proc_count=%d",
6384                                     pid, evc_proc_count);
6385                         }
6386                         return (0);
6387                 }
6388         }
6389         proc_unref(curr_proc);
6390         return (1);
6391 }
6392 
6393 /*
6394  * called from an application interface (ie: an ioctl command)
6395  * to unregister a process id interested in SCB events.
6396  * return:
6397  *      0 = event_proc was deleted
6398  *      1 = event_proc was not found, or table was empty
6399  */
6400 /* ARGSUSED */
6401 static int
6402 del_event_proc(scsb_state_t *scsb, pid_t pid)
6403 {
6404         int     i = 0;
6405         int     cnt = 0;
6406         void    *this_proc;
6407         if (evc_proc_count == 0)
6408                 return (1);
6409         for (; i < EVC_PROCS_MAX; ++i) {
6410                 if (evc_procs[i] == NULL)
6411                         continue;
6412                 this_proc = evc_procs[i];
6413                 if (pid == ((struct pid *)this_proc)->pid_id) {
6414                         evc_procs[i] = NULL;
6415                         if (--evc_proc_count == 0) {
6416                                 /*
6417                                  * reset evc fifo cound and pointers
6418                                  */
6419                                 reset_evc_fifo(scsb);
6420                         }
6421                         if (scsb_debug & 0x02000000) {
6422                                 cmn_err(CE_NOTE,
6423                                     "del_event_proc: %d; evc_proc_count=%d",
6424                                     pid, evc_proc_count);
6425                         }
6426                         proc_unref(this_proc);
6427                         return (0);
6428                 }
6429                 if (++cnt >= evc_proc_count)
6430                         break;
6431         }
6432         return (1);
6433 }
6434 
6435 /*
6436  * Can be called from an application interface
6437  * to rewind the pointers and counters, and zero the table
6438  * return:
6439  */
6440 /* ARGSUSED */
6441 static void
6442 rew_event_proc(scsb_state_t *scsb)
6443 {
6444         int     i = 0;
6445         if (scsb_debug & 0x02000001) {
6446                 cmn_err(CE_NOTE, "rew_event_proc: evc_proc_count=%d",
6447                     evc_proc_count);
6448         }
6449         for (; i < EVC_PROCS_MAX; ++i) {
6450                 if (evc_procs[i] != NULL) {
6451                         proc_unref(evc_procs[i]);
6452                         evc_procs[i] = NULL;
6453                 }
6454         }
6455         evc_proc_count = 0;
6456 }
6457 
6458 /* ARGSUSED */
6459 static int
6460 event_proc_count(scsb_state_t *scsb)
6461 {
6462         return (evc_proc_count);
6463 }
6464 
6465 /*
6466  * return:
6467  *      1 = pid was found
6468  *      0 = pid was not found, or table was empty
6469  */
6470 static int
6471 find_evc_proc(pid_t pid)
6472 {
6473         int     i = 0;
6474         int     cnt = 0;
6475         if (evc_proc_count == 0)
6476                 return (0);
6477         for (; i < EVC_PROCS_MAX; ++i) {
6478                 if (evc_procs[i] == NULL)
6479                         continue;
6480                 if (pid == ((struct pid *)evc_procs[i])->pid_id)
6481                         return (1);
6482                 if (++cnt >= evc_proc_count)
6483                         break;
6484         }
6485         return (0);
6486 }
6487 
6488 /*
6489  * called from update_ks_state() to compare evc_proc_count with
6490  * evc_requests, also mainted by this same function
6491  * This function could check the current process id, since this will be a user
6492  * context call, and only bump evc_requests if the calling process is
6493  * registered for event code delivery.
6494  * return:
6495  *      EVC_NO_EVENT_CODE       : no event_code on fifo
6496  *      EVC_NO_CURR_PROC        : current process not in table,
6497  *                                but have an event_code
6498  *      EVC_NEW_EVENT_CODE      : return_evc is new ks_state->event_code
6499  *      EVC_OR_EVENT_CODE       : OR return_evc with ks_state->event_code
6500  *      EVC_FAILURE             : unrecoverable error condition.
6501  */
6502 static int
6503 check_event_procs(uint32_t *return_evc)
6504 {
6505         void            *curr_proc;
6506         pid_t           curr_pid = 0;
6507         int             return_val = 0;
6508         static int      evc_requests = 0;
6509         /*
6510          * get current process handle, and check the event_procs table
6511          */
6512         if (evc_proc_count == 0) {
6513                 *return_evc = del_event_code();
6514                 return_val = EVC_NO_CURR_PROC;
6515         } else {
6516                 curr_proc = proc_ref();
6517                 curr_pid = ((struct pid *)curr_proc)->pid_id;
6518                 proc_unref(curr_proc);
6519                 if (!find_evc_proc(curr_pid)) {
6520                         *return_evc = get_event_code();
6521                         return_val = EVC_NO_CURR_PROC;
6522                 } else if (++evc_requests >= evc_proc_count) {
6523                         evc_requests = 0;
6524                         *return_evc = del_event_code();
6525                         return_val = EVC_NEW_EVENT_CODE;
6526                 } else {
6527                         *return_evc = get_event_code();
6528                 }
6529                 if (!return_val)
6530                         return_val = EVC_OR_EVENT_CODE;
6531         }
6532         if (scsb_debug & 0x02000000) {
6533                 cmn_err(CE_NOTE, "check_event_procs: pid=%d, evc=0x%x, "
6534                     "requests=%d, returning 0x%x", curr_pid,
6535                     *return_evc, evc_requests, return_val);
6536         }
6537         return (return_val);
6538 }
6539 
6540 static int
6541 scsb_queue_put(queue_t *rq, int count, uint32_t *data, char *caller)
6542 {
6543         mblk_t          *mp;
6544         if (scsb_debug & 0x4001) {
6545                 cmn_err(CE_NOTE, "scsb_queue_put(0x%p, %d, 0x%x, %s)",
6546                     (void *)rq, count, *data, caller);
6547         }
6548         mp = allocb(sizeof (uint32_t) * count, BPRI_HI);
6549         if (mp == NULL) {
6550                 cmn_err(CE_WARN, "%s: allocb failed",
6551                     caller);
6552                 return (B_FALSE);
6553         }
6554         while (count--) {
6555                 *((uint32_t *)mp->b_wptr) = *data;
6556                 mp->b_wptr += sizeof (*data);
6557                 ++data;
6558         }
6559         putnext(rq, mp);
6560         return (B_TRUE);
6561 }
6562 
6563 /* CLONE */
6564 static int
6565 scsb_queue_ops(scsb_state_t     *scsb,
6566                 int             op,
6567                 int             oparg,
6568                 void            *opdata,
6569                 char            *caller)
6570 {
6571         clone_dev_t     *clptr;
6572         int             clone, find_open, find_available, retval = QOP_FAILED;
6573 
6574         switch (op) {
6575         case QPUT_INT32:
6576                 if (scsb->scsb_opens && scsb->scsb_rq != NULL &&
6577                     scsb_queue_put(scsb->scsb_rq, oparg,
6578                     (uint32_t *)opdata, caller) == B_FALSE) {
6579                         return (QOP_FAILED);
6580                 }
6581         /*FALLTHROUGH*/ /* to look for opened clones */
6582         case QPROCSOFF:
6583                 retval = QOP_OK;
6584         /*FALLTHROUGH*/
6585         case QFIRST_OPEN:
6586         case QFIND_QUEUE:
6587                 find_open = 1;
6588                 find_available = 0;
6589                 break;
6590         case QFIRST_AVAILABLE:
6591                 find_available = 1;
6592                 find_open = 0;
6593                 break;
6594         }
6595         for (clone = SCSB_CLONES_FIRST; clone < SCSB_CLONES_MAX; clone++) {
6596                 clptr = &scsb->clone_devs[clone];
6597                 if (find_open && clptr->cl_flags & SCSB_OPEN) {
6598                         if (clptr->cl_rq == NULL) {
6599                                 cmn_err(CE_WARN, "%s: Clone %d has no queue",
6600                                     caller, clptr->cl_minor);
6601                                 return (QOP_FAILED);
6602                         }
6603                         switch (op) {
6604                         case QPROCSOFF:
6605                                 qprocsoff(clptr->cl_rq);
6606                                 break;
6607                         case QPUT_INT32:
6608                                 if (scsb_queue_put(clptr->cl_rq, oparg,
6609                                     (uint32_t *)opdata, caller)
6610                                     == B_FALSE) {
6611                                         retval = QOP_FAILED;
6612                                 }
6613                                 break;
6614                         case QFIRST_OPEN:
6615                                 return (clone);
6616                         case QFIND_QUEUE:
6617                                 if (clptr->cl_rq == (queue_t *)opdata) {
6618                                         return (clone);
6619                                 }
6620                                 break;
6621                         }
6622                 } else if (find_available && clptr->cl_flags == 0) {
6623                         switch (op) {
6624                         case QFIRST_AVAILABLE:
6625                                 return (clone);
6626                         }
6627                 }
6628         }
6629         return (retval);
6630 }
6631 
6632 /*
6633  * Find out if a bit is set for the FRU type and unit number in the register
6634  * set defined by the register base table index, base.
6635  * Returns TRUE if bit is set, or FALSE.
6636  */
6637 static int
6638 scsb_fru_op(scsb_state_t *scsb, scsb_utype_t fru_type, int unit, int base,
6639                                                                         int op)
6640 {
6641         int             rc;
6642         uchar_t         reg;
6643         int             tmp, idx, code, offset;
6644 
6645 #if 0
6646                 reg = SCSB_REG_ADDR(i);
6647                 ac_mask = 1 << FRU_OFFSET(SCTRL_EVENT_ALARM, SCTRL_RESET_BASE);
6648                 ac_val = scsb->scsb_data_reg[index+1] & ac_mask;
6649 #endif
6650         /* get the event code based on which we get the reg and bit offsets */
6651         code   = FRU_UNIT_TO_EVCODE(fru_type, unit);
6652         /* get the bit offset in the 8bit register corresponding to the event */
6653         offset = FRU_OFFSET(code, base);
6654         /* register offset from the base register, based on the event code */
6655         if ((fru_type == ALARM) && (base == SCTRL_RESET_BASE))
6656                 tmp = ALARM_RESET_REG_INDEX(code, base);
6657         else
6658                 tmp = FRU_REG_INDEX(code, base);
6659         /* get the global offset of the register in the parent address space */
6660         reg    = SCSB_REG_ADDR(tmp);
6661         /* get the global index of the register in this SCSB's address space */
6662         idx    = SCSB_REG_INDEX(reg);
6663         DEBUG4("scsb_fru_op(start): code=%x, offset=%x, tmp=%x, reg=%x\n",
6664             code, offset, tmp, reg);
6665         switch (op) {
6666                 case SCSB_FRU_OP_GET_REG:
6667                         rc = reg;
6668                         break;
6669                 case SCSB_FRU_OP_GET_BITVAL:
6670                         rc = (scsb->scsb_data_reg[idx] & (1 << offset))
6671                             >> offset;
6672                         break;
6673                 case SCSB_FRU_OP_GET_REGDATA:
6674                         rc = scsb->scsb_data_reg[idx];
6675                         break;
6676                 case SCSB_FRU_OP_SET_REGBIT:
6677                         rc = (1 << offset) & 0xff;
6678                         break;
6679                 default:
6680                         break;
6681         }
6682         DEBUG4("scsb_fru_op: unit=%x, base=%x, op=%d, rc=%x\n", unit, base,
6683             op, rc);
6684         return (rc);
6685 }
6686 
6687 /*
6688  * All HSC related functions can fail, but an attempt is made to atleast
6689  * return the right shadow state  on get-state function when SCB is removed.
6690  */
6691 int
6692 scsb_get_slot_state(scsb_state_t *scsb, int pslotnum, int *rstate)
6693 {
6694         int             slotnum, val = 0, rc;
6695 
6696         /*
6697          * When SCB is removed, we could be called with the lock held.
6698          * We call check_config_status anyway since it is a read-only operation
6699          * and HSC could be invoking this function at interrupt context.
6700          * If scsb is already in the doing interrupt postprocess, wait..
6701          */
6702 
6703         rc = scsb_check_config_status(scsb);
6704 
6705         /* check if error is because SCB is removed */
6706         if ((rc != EAGAIN) && (rc != DDI_SUCCESS))
6707                 return (DDI_FAILURE);
6708         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
6709         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_SYSCFG_BASE,
6710             SCSB_FRU_OP_GET_BITVAL);
6711         if (! val) {
6712                 *rstate = HPC_SLOT_EMPTY;
6713                 return (0);
6714         }
6715         /*
6716          * now, lets determine if it is connected or disconnected.
6717          * If reset is asserted, then the slot is disconnected.
6718          */
6719         rc = scsb_reset_slot(scsb, pslotnum, SCSB_GET_SLOT_RESET_STATUS);
6720         /* check if error is because SCB is removed */
6721         if ((rc != EAGAIN) && (rc != DDI_SUCCESS))
6722                 return (DDI_FAILURE);
6723         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
6724             SCSB_FRU_OP_GET_BITVAL);
6725         if (val)
6726                 *rstate = HPC_SLOT_DISCONNECTED;
6727         else {
6728                 if (scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
6729                     SCSB_FRU_OP_GET_BITVAL)) {
6730                         *rstate = HPC_SLOT_CONNECTED;
6731                 } else {
6732                         cmn_err(CE_WARN, "%s#%d: Reset Not Asserted on "
6733                             "Healthy# Failed slot %d!",
6734                             ddi_driver_name(scsb->scsb_dev),
6735                             ddi_get_instance(scsb->scsb_dev), slotnum);
6736                         *rstate = HPC_SLOT_DISCONNECTED;
6737                 }
6738         }
6739         return (0);
6740 }
6741 
6742 int
6743 scsb_reset_slot(scsb_state_t *scsb, int pslotnum, int reset_flag)
6744 {
6745         int             slotnum, error, val, alarm_card = 0;
6746         i2c_transfer_t  *i2cxferp;
6747         uchar_t         reg;
6748         int             index, condition_exists = 0, ac_val;
6749 
6750         if (scsb_debug & 0x8001)
6751                 cmn_err(CE_NOTE, "scsb_reset_slot(%d), flag %x", pslotnum,
6752                     reset_flag);
6753         if (scsb->scsb_state & SCSB_FROZEN)
6754                 return (EAGAIN);
6755         if ((i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle,
6756             I2C_NOSLEEP)) == NULL) {
6757                 return (ENOMEM);
6758         }
6759         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
6760 
6761         if (scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) {
6762                 DEBUG0("alarm card  reset/unreset op:\n");
6763                 alarm_card = 1;
6764         }
6765         reg = SCSB_REG_ADDR(SCTRL_RESET_BASE);
6766         index = SCSB_REG_INDEX(reg);
6767 
6768         mutex_enter(&scsb->scsb_mutex);
6769         i2cxferp->i2c_flags = I2C_WR_RD;
6770         i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS;
6771         i2cxferp->i2c_wbuf[0] = reg;
6772         i2cxferp->i2c_wlen = 1;
6773         scsb->scsb_kstat_flag = B_TRUE;      /* we did an i2c transaction */
6774         if ((error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) == 0) {
6775                 scsb->scsb_i2c_errcnt = 0;
6776                 /*
6777                  * XXX: following statements assume 2 reset registers,
6778                  * which is the case for our current SCB revisions.
6779                  */
6780                 scsb->scsb_data_reg[index]   = i2cxferp->i2c_rbuf[0];
6781                 scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1];
6782         } else {
6783                 scsb->scsb_i2c_errcnt++;
6784                 if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
6785                         scsb->scsb_err_flag = B_TRUE; /* latch until kstat */
6786                 if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
6787                         if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
6788                                 mutex_exit(&scsb->scsb_mutex);
6789                                 scsb_freeze(scsb);
6790                                 mutex_enter(&scsb->scsb_mutex);
6791                 }
6792                 cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error"
6793                     " reading Reset regs\n",
6794                     ddi_driver_name(scsb->scsb_dev),
6795                     ddi_get_instance(scsb->scsb_dev));
6796                 error = DDI_FAILURE;
6797         }
6798 
6799         DEBUG2("pre-reset regs = %x,%x\n", scsb->scsb_data_reg[index],
6800             scsb->scsb_data_reg[index+1]);
6801         if ((reset_flag == SCSB_GET_SLOT_RESET_STATUS) || (error)) {
6802                 mutex_exit(&scsb->scsb_mutex);
6803                 scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6804                 return (error);
6805         }
6806 
6807         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
6808             SCSB_FRU_OP_GET_BITVAL);
6809         if (alarm_card) {
6810                 ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE,
6811                     SCSB_FRU_OP_GET_BITVAL);
6812         }
6813         if (val && (reset_flag == SCSB_RESET_SLOT)) {
6814                 if (alarm_card) {
6815                         if (ac_val) {
6816                                 condition_exists = 1;
6817                                 DEBUG0("Alarm_RST# already active.\n");
6818                         }
6819 #ifndef lint
6820                         else
6821                                 DEBUG1("Alarm_RST# not active! "
6822                                     "Slot%d_RST# active!\n", pslotnum);
6823 #endif
6824                 } else {
6825                         condition_exists = 1;
6826                         DEBUG1("Slot%d_RST# already active!\n", pslotnum);
6827                 }
6828         }
6829         else
6830                 if ((val == 0) && (reset_flag == SCSB_UNRESET_SLOT)) {
6831                         if (alarm_card) {
6832                                 if (!ac_val) {
6833                                         DEBUG0("Alarm_RST# not active.\n");
6834                                         condition_exists = 1;
6835                                 }
6836 #ifndef lint
6837                                 else
6838                                         DEBUG1("Alarm_RST# active"
6839                                             " Slot%d_RST# not active!\n",
6840                                             pslotnum);
6841 #endif
6842                         } else {
6843                                 condition_exists = 1;
6844                                 DEBUG1("Slot%d_RST# already not active!\n",
6845                                     pslotnum);
6846                         }
6847                 }
6848 
6849         if (! condition_exists) {
6850                 i2cxferp->i2c_flags = I2C_WR;
6851                 i2cxferp->i2c_wlen = 2;
6852                 i2cxferp->i2c_wbuf[0] = scsb_fru_op(scsb, SLOT, slotnum,
6853                     SCTRL_RESET_BASE, SCSB_FRU_OP_GET_REG);
6854                 if (reset_flag == SCSB_RESET_SLOT) {
6855                         i2cxferp->i2c_wbuf[1] =
6856                             scsb_fru_op(scsb, SLOT, slotnum,
6857                             SCTRL_RESET_BASE,
6858                             SCSB_FRU_OP_GET_REGDATA) |
6859                             scsb_fru_op(scsb, SLOT, slotnum,
6860                             SCTRL_RESET_BASE,
6861                             SCSB_FRU_OP_SET_REGBIT);
6862 #ifdef  DEBUG           /* dont reset Alarm Card line unless in debug mode */
6863                         if (alarm_card)
6864                                 i2cxferp->i2c_wbuf[1] |=
6865                                     scsb_fru_op(scsb, ALARM, 1,
6866                                     SCTRL_RESET_BASE,
6867                                     SCSB_FRU_OP_SET_REGBIT);
6868 #endif
6869                 } else {
6870                         i2cxferp->i2c_wbuf[1] =
6871                             scsb_fru_op(scsb, SLOT, slotnum,
6872                             SCTRL_RESET_BASE,
6873                             SCSB_FRU_OP_GET_REGDATA) &
6874                             ~(scsb_fru_op(scsb, SLOT, slotnum,
6875                             SCTRL_RESET_BASE,
6876                             SCSB_FRU_OP_SET_REGBIT));
6877 #ifdef  DEBUG           /* dont Unreset Alarm Card line unless in debug mode */
6878                         if (alarm_card)
6879                                 i2cxferp->i2c_wbuf[1] &=
6880                                     scsb_fru_op(scsb, ALARM, 1,
6881                                     SCTRL_RESET_BASE,
6882                                     SCSB_FRU_OP_SET_REGBIT);
6883 #endif
6884                 }
6885 
6886                 if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
6887                         scsb->scsb_i2c_errcnt++;
6888                         if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
6889                                 scsb->scsb_err_flag = B_TRUE; /* latch error */
6890                         mutex_exit(&scsb->scsb_mutex);
6891                         if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
6892                                 if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
6893                                         scsb_freeze(scsb);
6894                         }
6895                         cmn_err(CE_WARN, "%s#%d: reset_slot: error writing to"
6896                             " Reset regs (op=%d, data=%x)\n",
6897                             ddi_driver_name(scsb->scsb_dev),
6898                             ddi_get_instance(scsb->scsb_dev),
6899                             reset_flag, i2cxferp->i2c_wbuf[1]);
6900                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6901                         return (DDI_FAILURE);
6902                 }
6903 
6904                 scsb->scsb_i2c_errcnt = 0;
6905                 /* now read back and update our scsb structure */
6906                 i2cxferp->i2c_flags = I2C_WR_RD;
6907                 i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS;
6908                 i2cxferp->i2c_wbuf[0] = reg;
6909                 i2cxferp->i2c_wlen = 1;
6910                 if ((error = nct_i2c_transfer(scsb->scsb_phandle,
6911                     i2cxferp)) == 0) {
6912                         scsb->scsb_i2c_errcnt = 0;
6913                         scsb->scsb_data_reg[index]   = i2cxferp->i2c_rbuf[0];
6914                         scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1];
6915                 } else {
6916                         scsb->scsb_i2c_errcnt++;
6917                         if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
6918                                 scsb->scsb_err_flag = B_TRUE; /* latch error */
6919                         mutex_exit(&scsb->scsb_mutex);
6920                         if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
6921                                 if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
6922                                         scsb_freeze(scsb);
6923                         }
6924                         cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error"
6925                             " reading Reset regs (post reset)\n",
6926                             ddi_driver_name(scsb->scsb_dev),
6927                             ddi_get_instance(scsb->scsb_dev));
6928                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6929                         return (DDI_FAILURE);
6930                 }
6931                 /* XXX: P1.5 */
6932                 DEBUG2("post-reset regs = %x,%x\n", scsb->scsb_data_reg[index],
6933                     scsb->scsb_data_reg[index+1]);
6934                 val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
6935                     SCSB_FRU_OP_GET_BITVAL);
6936 #ifdef  DEBUG
6937                 if (alarm_card)
6938                         ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE,
6939                             SCSB_FRU_OP_GET_BITVAL);
6940 #endif
6941                 if (val && (reset_flag == SCSB_UNRESET_SLOT)) {
6942                         cmn_err(CE_WARN, "Cannot UnReset Slot %d (reg=%x)\n",
6943                             pslotnum,
6944                             scsb_fru_op(scsb, SLOT, slotnum,
6945                             SCTRL_RESET_BASE,
6946                             SCSB_FRU_OP_GET_REGDATA));
6947 #ifdef  DEBUG
6948                         if (alarm_card) {
6949                                 if (ac_val)
6950                                         cmn_err(CE_WARN, "Cannot Unreset "
6951                                             "Alarm_RST#.\n");
6952                         }
6953 #endif
6954                 }
6955                 else
6956                         if ((val == 0) && (reset_flag == SCSB_RESET_SLOT)) {
6957                                 cmn_err(CE_WARN, "Cannot Reset Slot %d, "
6958                                     "reg=%x\n", pslotnum,
6959                                     scsb_fru_op(scsb, SLOT, slotnum,
6960                                     SCTRL_RESET_BASE,
6961                                     SCSB_FRU_OP_GET_REGDATA));
6962 #ifdef  DEBUG
6963                                 if (alarm_card) {
6964                                         if (!ac_val)
6965                                                 cmn_err(CE_WARN, "Cannot reset "
6966                                                     "Alarm_RST#.\n");
6967                                 }
6968 #endif
6969                         }
6970         }
6971 
6972         mutex_exit(&scsb->scsb_mutex);
6973         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6974 
6975         return (error);
6976 }
6977 
6978 int
6979 scsb_connect_slot(scsb_state_t *scsb, int pslotnum, int healthy)
6980 {
6981         int slotnum, count = 0, val;
6982         int slot_flag = 0;
6983 
6984         /*
6985          * If Power needs to be handled, it should be done here.
6986          * Since there is no power handling for now, lets disable
6987          * reset, wait for healthy to come on and then call it
6988          * connected.
6989          * If HLTHY# does not come on (in how long is the question)
6990          * then we stay disconnected.
6991          */
6992         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
6993 
6994         /*
6995          * P1.5 doesnt require polling healthy as we get an
6996          * interrupt. So we could just update our state as disconnected
6997          * and return waiting for the healthy# interrupt. To make it
6998          * more efficient, lets poll for healthy# a short while since we are
6999          * in the interrupt context anyway. If we dont get a healthy# we
7000          * return, and then wait for the interrupt. Probably the warning
7001          * message needs to be removed then. Need a PROM check flag here.
7002          */
7003         while ((healthy == B_FALSE) && (count < scsb_healthy_poll_count)) {
7004                 if (scsb_read_bhealthy(scsb) != 0)
7005                         return (DDI_FAILURE);
7006                 val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
7007                     SCSB_FRU_OP_GET_BITVAL);
7008                 if (val) {
7009                         healthy = B_TRUE;
7010                         break;
7011                 }
7012                 count++;
7013                 drv_usecwait(100);      /* cant delay(9f) in intr context */
7014         }
7015 
7016         if (healthy == B_FALSE && count == scsb_healthy_poll_count) {
7017                 if (scsb_debug & 0x00004000)
7018                         cmn_err(CE_WARN, "%s#%d: no HEALTHY# signal on"
7019                             " slot %d", ddi_driver_name(scsb->scsb_dev),
7020                             ddi_get_instance(scsb->scsb_dev), pslotnum);
7021         }
7022 
7023         if ((scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) &&
7024             (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES))
7025                 slot_flag = ALARM_CARD_ON_SLOT;
7026         return (hsc_slot_occupancy(pslotnum, 1, slot_flag, healthy));
7027 }
7028 
7029 int
7030 scsb_disconnect_slot(scsb_state_t *scsb, int occupied, int slotnum)
7031 {
7032         int slot_flag = 0;
7033 
7034         /* Reset is must at extraction. Move on even if failure. */
7035         if (scsb_reset_slot(scsb, slotnum, SCSB_RESET_SLOT) != 0) {
7036                 /*
7037                  * If board is still in slot, which means there is a manual
7038                  * disconnection in progress, return failure.
7039                  * Otherwise, a board was removed anyway; so we need to
7040                  * update the status and move on.
7041                  */
7042                 if (occupied == B_TRUE)
7043                         return (DDI_FAILURE);
7044         }
7045         /*
7046          * the following bug needs to be fixed.
7047          * When this function is called from scsb_intr, scsb_state already
7048          * clears the 'AC card present' bit.
7049          * However, hsc module doesn't depend on slot_flag during removal.
7050          */
7051         if ((scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) &&
7052             (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES))
7053                 slot_flag = ALARM_CARD_ON_SLOT;
7054         return (hsc_slot_occupancy(slotnum, occupied, slot_flag, B_FALSE));
7055 }
7056 
7057 static int
7058 scsb_is_alarm_card_slot(scsb_state_t *scsb, int slotnum)
7059 {
7060         return ((scsb->ac_slotnum == slotnum)? B_TRUE:B_FALSE);
7061 }
7062 
7063 /*
7064  * Invoked both by the hsc and the scsb module to exchanges necessary
7065  * information regarding the alarm card.
7066  * scsb calls this function to unconfigure the alarm card while the
7067  * hsc calls this function at different times to check busy status,
7068  * and during post hotswap insert operation so that the user process
7069  * if one waiting can configure the alarm card.
7070  */
7071 int
7072 scsb_hsc_ac_op(scsb_state_t *scsb, int pslotnum, int op)
7073 {
7074         int             rc = B_FALSE;
7075         uint32_t        event_code;
7076 
7077         if (!(scsb->scsb_hsc_state & SCSB_HSC_INIT &&
7078             scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) {
7079                 cmn_err(CE_WARN,
7080                     "scsb: HSC not initialized or AC not present!");
7081                 return (rc);
7082         }
7083         switch (op) {
7084                 /* hsc -> scsb */
7085                 case SCSB_HSC_AC_BUSY:
7086                         if (scsb->scsb_hsc_state & SCSB_ALARM_CARD_IN_USE)
7087                                 rc = B_TRUE;
7088                         break;
7089 
7090                 /* API -> scsb */
7091                 /*
7092                  * NOTE: this could be called multiple times from envmond if
7093                  * the daemon is reinitialized with SIGHUP, or stopped and
7094                  * restarted.
7095                  */
7096                 case SCSB_HSC_AC_SET_BUSY:
7097                         DEBUG0("AC SET BUSY\n");
7098                         if (scsb_debug & 0x00010000) {
7099                                 cmn_err(CE_NOTE,
7100                                     "scsb_hsc_ac_op(SCSB_HSC_AC_SET_BUSY)");
7101                         }
7102                         scsb->scsb_hsc_state |= SCSB_ALARM_CARD_IN_USE;
7103                         rc = B_TRUE;
7104                         break;
7105 
7106                 /* hsc -> scsb */
7107                 case SCSB_HSC_AC_CONFIGURED:
7108                         DEBUG0("AC configured\n");
7109                         if (scsb_debug & 0x00010000) {
7110                                 cmn_err(CE_NOTE,
7111                                 "scsb_hsc_ac_op(SCSB_HSC_AC_CONFIGURED)");
7112                         }
7113                         /*
7114                          * wakeup anyone waiting on AC to be configured
7115                          * Send the ALARM_CARD_CONFIGURE Event to all scsb
7116                          * open streams.
7117                          */
7118                         event_code = SCTRL_EVENT_ALARM_INSERTION;
7119                         (void) scsb_queue_ops(scsb, QPUT_INT32, 1,
7120                             &event_code, "scsb_hsc_ac_op");
7121                         rc = B_TRUE;
7122                         break;
7123 
7124                 /* hsc -> scsb */
7125                 case SCSB_HSC_AC_REMOVAL_ALERT:
7126                         DEBUG0("AC removal alert\n");
7127                         if (scsb_debug & 0x00010000) {
7128                                 cmn_err(CE_NOTE,
7129                                 "scsb_hsc_ac_op(SCSB_HSC_AC_REMOVAL_ALERT)");
7130                         }
7131                         /*
7132                          * Inform (envmond)alarmcard.so that it should save
7133                          * the AC configuration, stop the
7134                          * heartbeat, and shutdown the RSC link.
7135                          */
7136                         event_code = SCTRL_EVENT_ALARM_REMOVAL;
7137                         (void) scsb_queue_ops(scsb, QPUT_INT32, 1,
7138                             &event_code, "scsb_hsc_ac_op");
7139                         rc = B_TRUE;
7140                         break;
7141 
7142                 /* API -> scsb -> hsc */
7143                 case SCSB_HSC_AC_UNCONFIGURE:
7144                         DEBUG0("AC unconfigure\n");
7145                         if (scsb_debug & 0x00010000) {
7146                                 cmn_err(CE_NOTE,
7147                                     "scsb_hsc_ac_op(SCSB_HSC_AC_UNCONFIG"
7148                                     "URE), AC NOT BUSY");
7149                         }
7150                         /*
7151                          * send notification back to HSC to
7152                          * unconfigure the AC, now that the env monitor
7153                          * has given permission to do so.
7154                          */
7155                         scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_IN_USE;
7156                         hsc_ac_op((int)scsb->scsb_instance, pslotnum,
7157                             SCSB_HSC_AC_UNCONFIGURE, NULL);
7158                         rc = B_TRUE;
7159                         break;
7160                 default:
7161                         break;
7162         }
7163 
7164         return (rc);
7165 }
7166 
7167 static void
7168 scsb_healthy_intr(scsb_state_t *scsb, int pslotnum)
7169 {
7170         int val, slotnum;
7171         int healthy = B_FALSE;
7172 
7173         DEBUG1("Healthy Intr on slot %d\n", pslotnum);
7174         /*
7175          * The interrupt source register can have the healthy
7176          * bit set for non-existing slot, e.g slot 7 on Tonga.
7177          * It can also be seen on the Tonga CPU slot. So we make
7178          * sure we have a valid slot before proceeding.
7179          */
7180         if (scsb->scsb_state & SCSB_IS_TONGA) {
7181                 if (pslotnum > TG_MAX_SLOTS || pslotnum == SC_TG_CPU_SLOT) {
7182                         if (scsb_debug & 0x08000000)
7183                                 cmn_err(CE_NOTE, "Healthy interrupt bit set for"
7184                                     " slot %d", pslotnum);
7185                 return;
7186                 }
7187         } else {
7188                 if (pslotnum > MC_MAX_SLOTS || pslotnum == SC_MC_CPU_SLOT ||
7189                     (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
7190                     pslotnum == SC_MC_CTC_SLOT)) {
7191                         if (scsb_debug & 0x08000000)
7192                                 cmn_err(CE_NOTE, "Healthy interrupt bit set for"
7193                                     " slot %d", pslotnum);
7194                 return;
7195                 }
7196         }
7197 
7198         /*
7199          * The board healthy registers are already read before entering
7200          * this routine
7201          */
7202         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
7203 
7204         /*
7205          * P1.5. Following works since slots 1 through 8 are in the same reg
7206          */
7207         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
7208             SCSB_FRU_OP_GET_BITVAL);
7209         if (val)
7210                 healthy = B_TRUE;
7211         (void) scsb_hsc_board_healthy(pslotnum, healthy);
7212 }
7213 
7214 /*
7215  * This function will try to read from scsb irrespective of whether
7216  * SSB is present or SCB is frozen, to get the health kstat information.
7217  */
7218 static int
7219 scsb_blind_read(scsb_state_t *scsb, int op, uchar_t reg, int len,
7220                                 uchar_t *rwbuf, int i2c_alloc)
7221 {
7222         i2c_transfer_t  *i2cxferp;
7223         int             i, rlen, wlen, error = 0;
7224 
7225         if (scsb_debug & 0x0800) {
7226                 cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):",
7227                     (op == I2C_WR) ? "write" : "read",  reg, len);
7228         }
7229 
7230         if (i2c_alloc) {
7231                 i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP);
7232                 if (i2cxferp == NULL) {
7233                         if (scsb_debug & 0x0042)
7234                                 cmn_err(CE_WARN, "scsb_rdwr_register: "
7235                                     "i2ctx allocation failure");
7236                         return (ENOMEM);
7237                 }
7238         } else {
7239                 i2cxferp = scsb->scsb_i2ctp;
7240         }
7241         switch (op) {
7242         case I2C_WR:
7243                 wlen = len + 1; /* add the address */
7244                 rlen = 0;
7245                 i2cxferp->i2c_wbuf[0] = reg;
7246                 for (i = 0; i < len; ++i) {
7247                                 i2cxferp->i2c_wbuf[1 + i] = rwbuf[i];
7248                         if (scsb_debug & 0x0080)
7249                                 cmn_err(CE_NOTE,
7250                                 "scsb_rdwr_register: writing rwbuf[%d]=0x%x",
7251                                     i, rwbuf[i]);
7252                 }
7253                 break;
7254         case I2C_WR_RD:
7255                 wlen = 1;       /* for the address */
7256                 rlen = len;
7257                 i2cxferp->i2c_wbuf[0] = reg;
7258                 break;
7259         default:
7260                 if (i2c_alloc)
7261                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
7262                 return (EINVAL);
7263         }
7264         /* select the register address */
7265         i2cxferp->i2c_flags = op;
7266         i2cxferp->i2c_rlen = rlen;
7267         i2cxferp->i2c_wlen = wlen;
7268         i2cxferp->i2c_wbuf[0] = reg;
7269         scsb->scsb_kstat_flag = B_TRUE;      /* we did a i2c transaction */
7270         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
7271                 error = EIO;
7272         } else if (rlen) {
7273                 /* copy to rwbuf[] */
7274                 for (i = 0; i < len; ++i) {
7275                         rwbuf[i] = i2cxferp->i2c_rbuf[i];
7276                         if (scsb_debug & 0x0080)
7277                                 cmn_err(CE_NOTE,
7278                                 "scsb_rdwr_register: read rwbuf[%d]=0x%x",
7279                                     i, rwbuf[i]);
7280                 }
7281         }
7282         if (i2c_alloc)
7283                 scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
7284         if (error) {
7285                 scsb->scsb_i2c_errcnt++;
7286                 if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
7287                         scsb->scsb_err_flag = B_TRUE; /* latch error */
7288         } else {
7289                 scsb->scsb_i2c_errcnt = 0;
7290         }
7291 
7292         return (error);
7293 }
7294 
7295 /*
7296  * This function will quiesce the PSM_INT line by masking the
7297  * global PSM_INT and writing 1 to SCB_INIT ( for P1.5 and later )
7298  * This effectively translates to writing 0x20 to 0xE1 register.
7299  */
7300 static int
7301 scsb_quiesce_psmint(scsb_state_t *scsb)
7302 {
7303         register int    i;
7304         uchar_t reg, wdata = 0;
7305         uchar_t tmp_reg, intr_addr, clr_bits = 0;
7306         int error, iid, intr_idx, offset;
7307 
7308         /*
7309          * For P1.5, set the SCB_INIT bit in the System Command register,
7310          * and disable global PSM_INT. Before this we need to read the
7311          * interrupt source register corresponding to INIT_SCB and
7312          * clear if set.
7313          */
7314         if (IS_SCB_P15) {
7315                 /*
7316                  * Read INTSRC6 and write back 0x20 in case INIT_SCB is set
7317                  */
7318                 intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
7319                 tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15);
7320                 iid = SCSB_REG_INDEX(intr_addr);
7321                 intr_idx = SCSB_REG_INDEX(tmp_reg) - iid;
7322                 offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE);
7323                 clr_bits = 1 << offset;
7324 
7325                 error = scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg,
7326                     1, &scb_intr_regs[intr_idx], 0);
7327                 /*
7328                  * Now mask the global PSM_INT and write INIT_SCB in case
7329                  * this is an INIT_SCB interrupt
7330                  */
7331                 wdata = 1 << SYS_OFFSET(SCTRL_SYS_SCB_INIT);
7332                 i = SYS_REG_INDEX(SCTRL_SYS_SCB_INIT, SCTRL_SYS_CMD_BASE);
7333                 reg = SCSB_REG_ADDR(i);
7334                 error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
7335                     &wdata, 0);
7336 
7337                 if (scb_intr_regs[intr_idx] & clr_bits) {
7338                         /*
7339                          * There is an SCB_INIT interrupt, which we must clear
7340                          * first to keep SCB_INIT from keeping PSM_INT asserted.
7341                          */
7342                         error = scsb_rdwr_register(scsb, I2C_WR, tmp_reg,
7343                             1, &clr_bits, 0);
7344                 }
7345 
7346                 if (error) {
7347                         cmn_err(CE_WARN, "scsb%d:scsb_quiesce_psmint: "
7348                             " I2C TRANSFER Failed", scsb->scsb_instance);
7349                         if (scsb_debug & 0x0006) {
7350                                 cmn_err(CE_NOTE, "scsb_attach: "
7351                                     " failed to set SCB_INIT");
7352                         }
7353                 }
7354                 scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED;
7355         } else { /* P1.0 or earlier */
7356                 /*
7357                  * read the interrupt source registers, and then
7358                  * write them back.
7359                  */
7360                 /* read the interrupt register from scsb */
7361                 if (error = scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr,
7362                     SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) {
7363                         cmn_err(CE_WARN, "scsb_intr: "
7364                             " Failed read of interrupt registers.");
7365                         scsb->scsb_state &= ~SCSB_IN_INTR;
7366                 }
7367 
7368                 /*
7369                  * Write to the interrupt source registers to stop scsb
7370                  * from interrupting.
7371                  */
7372                 if (error = scsb_rdwr_register(scsb, I2C_WR, intr_addr,
7373                     SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) {
7374                         cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt"
7375                             " registers.");
7376                         scsb->scsb_state &= ~SCSB_IN_INTR;
7377                 }
7378 
7379         }
7380 
7381         if (error)
7382                 return (DDI_FAILURE);
7383         else
7384                 return (DDI_SUCCESS);
7385 }
7386 
7387 /*
7388  * Enables or disables the global PSM_INT interrupt for P1.5, depending
7389  * on the flag, flag = 0 => disable, else enable.
7390  */
7391 static int
7392 scsb_toggle_psmint(scsb_state_t *scsb, int enable)
7393 {
7394         int i;
7395         uchar_t reg, on = 0, rmask = 0x0, off = 0;
7396 
7397         if (enable == B_TRUE) {
7398                 on = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
7399         } else {
7400                 off = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
7401         }
7402 
7403         i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, SCTRL_SYS_CMD_BASE);
7404         reg = SCSB_REG_ADDR(i);
7405         if (scsb_write_mask(scsb, reg, rmask, on, off)) {
7406                 cmn_err(CE_WARN, "scsb_toggle_psmint: Cannot turn %s PSM_INT",
7407                     enable == 1 ? "on" : "off");
7408                 return (DDI_FAILURE);
7409         }
7410         if (enable == 0) {
7411                 scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED;
7412         } else {
7413                 scsb->scsb_state |= SCSB_PSM_INT_ENABLED;
7414         }
7415 
7416         return (DDI_SUCCESS);
7417 }
7418 
7419 /*
7420  * This routine is to be used by all the drivers using this i2c bus
7421  * to synchronize their transfer operations.
7422  */
7423 int
7424 nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran)
7425 {
7426         int retval, initmux = nct_mutex_init;
7427 
7428         /*
7429          * If scsb interrupt mutex is initialized, also hold the
7430          * interrupt mutex to let the i2c_transfer() to complete
7431          */
7432 
7433         if (initmux & MUTEX_INIT) {
7434                 mutex_enter(scb_intr_mutex);
7435         }
7436 
7437         retval = i2c_transfer(i2c_hdl, i2c_tran);
7438 
7439         if (initmux & MUTEX_INIT) {
7440                 mutex_exit(scb_intr_mutex);
7441         }
7442 
7443         return (retval);
7444 }