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