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, drv_sectohz(4));
2771                                         } else
2772 #endif  /* PS_ON_DELAY */
2773                                                 scsb_ps_auto_on((void *)&pao);
2774                                 }
2775                                 /*
2776                                  * Special SLOT handling.
2777                                  * Make sure the OK LED is on for the CPU Slot
2778                                  * and for the FTC (CFTM) Slot for MonteCarlo.
2779                                  * Both will report as FRU_PRESENT.
2780                                  */
2781                                 if (fru_type != SLOT || (fru_type == SLOT &&
2782                                     (fru_ptr->fru_type ==
2783                                     (scsb_utype_t)OC_CPU ||
2784                                     fru_ptr->fru_type ==
2785                                     (scsb_utype_t)OC_CTC))) {
2786                                         /*
2787                                          * Set OK (green) LED register bit
2788                                          */
2789                                         led_data[led_idx] |= 1 << led_bit;
2790                                 }
2791                                 if (IS_SCB_P10)
2792                                         continue;
2793                                 /*
2794                                  * Turn off BLINK register bit.
2795                                  * If single register update, then save the
2796                                  * corresponding blink register in blink_reg.
2797                                  */
2798                                 reg = fru_ptr->i2c_info->blink_reg;
2799                                 if (!reg)
2800                                         continue;
2801                                 blink_bit = fru_ptr->i2c_info->blink_bit;
2802                                 blink_idx = SCSB_REG_INDEX(reg) - bid;
2803                                 blink[blink_idx] |= 1 << blink_bit;
2804                                 if (update_reg && update_reg == led_reg)
2805                                         blink_reg = reg;
2806                         }
2807                 }
2808         }
2809         if (update_reg) {
2810                 reg = update_reg;
2811                 i = SCSB_REG_INDEX(reg);
2812                 puc = &led_data[i - lid];
2813                 i = 1;
2814         } else {
2815                 reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
2816                 puc = led_data;
2817                 i = SCTRL_LED_OK_NUMREGS;
2818         }
2819         if (scsb_debug & 0x0100) {
2820                 cmn_err(CE_NOTE, "scsb_set_scfg_pres(): writing %d bytes "
2821                     "to 0x%x", i, reg);
2822         }
2823         if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, i, puc, 1)) != 0) {
2824                 if (scsb_debug & 0x0102)
2825                         cmn_err(CE_NOTE, "scsb_set_scfg_pres(): "
2826                             "I2C write to 0x%x failed", reg);
2827                 error = EIO;
2828         } else {
2829                 /*
2830                  * Now see which BLINK bits need to be turned off for the
2831                  * corresponding OK LED bits.
2832                  */
2833                 reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
2834                 for (i = 0; i < SCTRL_BLINK_NUMREGS; ++i, ++reg) {
2835                         if (blink_reg && blink_reg != reg)
2836                                 continue;
2837                         if (!blink[i]) {
2838                                 continue;
2839                         }
2840                         if (scsb_debug & 0x0100) {
2841                                 cmn_err(CE_NOTE, "scsb_set_scfg_pres(): turn "
2842                                     "OFF Blink bits 0x%x in 0x%x",
2843                                     blink[i], reg);
2844                         }
2845                         if (scsb_write_mask(scsb, reg, 0, 0, blink[i])) {
2846                                 if (scsb_debug & 0x0102)
2847                                         cmn_err(CE_NOTE,
2848                                             "scsb_set_scfg_pres(): "
2849                                             "Write to 0x%x failed", reg);
2850                                 error = EIO;
2851                                 break;
2852                         }
2853                 }
2854         }
2855         return (error);
2856 }
2857 
2858 static int
2859 scsb_check_config_status(scsb_state_t *scsb)
2860 {
2861         int             error;
2862         uchar_t         reg;
2863         int             index, p06;
2864 
2865         if (scsb_debug & 0x0201) {
2866                 cmn_err(CE_NOTE, "scsb_check_config_status:");
2867         }
2868         /*
2869          * Base of register set
2870          */
2871         reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE);
2872         index = SCSB_REG_INDEX(reg);
2873         /*
2874          * SCB P0.6 workaround: read registers twice, use 2nd value set
2875          */
2876         mutex_enter(&scsb->scsb_mutex);
2877         p06 = 2;
2878         do {
2879                 if (error = scsb_rdwr_register(scsb, I2C_WR_RD, reg,
2880                     SCTRL_CFG_NUMREGS, &scsb->scsb_data_reg[index], 1)) {
2881                         break;
2882                 }
2883                 if (p06 == 1) {
2884                         if (scsb_debug & 0x0200)
2885                                 cmn_err(CE_NOTE,
2886                                 "scsb_check_config_status: P0.6 workaround");
2887                 }
2888                 /*
2889                  * If not P0.6 PROM, just break here
2890                  */
2891                 if (!(scsb->scsb_state & SCSB_P06_PROM))
2892                         break;
2893         } while (--p06);
2894         mutex_exit(&scsb->scsb_mutex);
2895 
2896         if (error == 0) {
2897                 if (!(scsb->scsb_state & SCSB_SCB_PRESENT))
2898                         scsb->scsb_state |= SCSB_SCB_PRESENT;
2899                 if (scsb_fru_op(scsb, SSB, 1, SCTRL_SYSCFG_BASE,
2900                     SCSB_FRU_OP_GET_BITVAL))
2901                         scsb->scsb_state |= SCSB_SSB_PRESENT;
2902                 else
2903                         scsb->scsb_state &= ~SCSB_SSB_PRESENT;
2904         }
2905         return (error);
2906 }
2907 
2908 static void
2909 scsb_set_topology(scsb_state_t *scsb)
2910 {
2911         int             i, t, index, unit, is_tonga = 0;
2912         int             alarm_slot_num, cpu_slot_num, ctc_slot_num;
2913         fru_info_t      *fru_ptr, *last_ptr, *acslot_ptr, *ctcslot_ptr;
2914         uchar_t         syscfg, led_reg, blink_reg, t_uchar;
2915         uchar_t         bit_num, led_bit, blink_bit;
2916         int             pad = 0;
2917 
2918         /*
2919          * Get the presence status from the SysConfigStatus shadow registers
2920          * in scsb->scsb_data_reg[]
2921          */
2922         /* Mid Plane */
2923         i = SYS_REG_INDEX(SCTRL_CFG_MPID0, SCTRL_SYSCFG_BASE);
2924         t_uchar = SCSB_REG_ADDR(i);
2925         index = SCSB_REG_INDEX(t_uchar);
2926         mct_system_info.mid_plane.fru_type = MIDPLANE;
2927         mct_system_info.mid_plane.fru_version = (fru_version_t)0;
2928         t = SYS_OFFSET(SCTRL_CFG_MPID0);
2929         mct_system_info.mid_plane.fru_id = (int)((scsb->scsb_data_reg[index] &
2930             (SCTRL_MPID_MASK << t)) >> t);
2931         switch (mct_system_info.mid_plane.fru_id) {
2932         case SCTRL_MPID_HALF:           /* Monte Carlo          */
2933                 if (scsb_debug & 0x00100005)
2934                         cmn_err(CE_NOTE, "scsb_set_topology: Monte Carlo");
2935                 cpu_slot_num = SC_MC_CPU_SLOT;
2936                 ctc_slot_num = SC_MC_CTC_SLOT;
2937                 alarm_slot_num = scsb->ac_slotnum = SC_MC_AC_SLOT;
2938                 mct_system_info.max_units[SLOT] = MC_MAX_SLOTS;
2939                 mct_system_info.max_units[ALARM] = MC_MAX_AC;
2940                 mct_system_info.max_units[DISK] = MC_MAX_DISK;
2941                 mct_system_info.max_units[FAN] = MC_MAX_FAN;
2942                 mct_system_info.max_units[PS] = MC_MAX_PS;
2943                 mct_system_info.max_units[PDU] = MC_MAX_PDU;
2944                 mct_system_info.max_units[SCB] = MC_MAX_SCB;
2945                 mct_system_info.max_units[SSB] = MC_MAX_SCB;
2946                 mct_system_info.max_units[CFTM] = MC_MAX_CFTM;
2947                 mct_system_info.max_units[CRTM] = MC_MAX_CRTM;
2948                 mct_system_info.max_units[PRTM] = MC_MAX_PRTM;
2949                 break;
2950         case SCTRL_MPID_QUARTER_NODSK:  /* Tonga w/o disk       */
2951         case SCTRL_MPID_QUARTER:        /* Tonga w/  disk       */
2952                 scsb->scsb_state |= SCSB_IS_TONGA;
2953                 is_tonga = 1;
2954                 ctc_slot_num = -1;
2955                 ctcslot_ptr = NULL;
2956                 if (scsb_debug & 0x00100005)
2957                         cmn_err(CE_NOTE, "scsb_set_topology: Tonga%s",
2958                             mct_system_info.mid_plane.fru_id ==
2959                             SCTRL_MPID_QUARTER_NODSK ?
2960                             ", no disk" : " with disk");
2961                 cpu_slot_num = SC_TG_CPU_SLOT;
2962                 alarm_slot_num = scsb->ac_slotnum = SC_TG_AC_SLOT;
2963                 mct_system_info.max_units[SLOT] = TG_MAX_SLOTS;
2964                 mct_system_info.max_units[ALARM] = TG_MAX_AC;
2965                 mct_system_info.max_units[DISK] = TG_MAX_DISK;
2966                 mct_system_info.max_units[FAN] = TG_MAX_FAN;
2967                 mct_system_info.max_units[PS] = TG_MAX_PS;
2968                 mct_system_info.max_units[PDU] = TG_MAX_PDU;
2969                 mct_system_info.max_units[SCB] = TG_MAX_SCB;
2970                 mct_system_info.max_units[SSB] = TG_MAX_SCB;
2971                 mct_system_info.max_units[CFTM] = TG_MAX_CFTM;
2972                 mct_system_info.max_units[CRTM] = TG_MAX_CRTM;
2973                 mct_system_info.max_units[PRTM] = TG_MAX_PRTM;
2974                 break;
2975         default:
2976                 cmn_err(CE_WARN, "%s#%d: Unknown MidPlane Id %x",
2977                     ddi_driver_name(scsb->scsb_dev),
2978                     ddi_get_instance(scsb->scsb_dev),
2979                     mct_system_info.mid_plane.fru_id);
2980                 if (scsb_debug & 0x00100005)
2981                         cmn_err(CE_NOTE, "scsb_set_topology: 0x%x: unknown!",
2982                             mct_system_info.mid_plane.fru_id);
2983                 return;
2984         }
2985         /*
2986          * cPCI Slots
2987          *
2988          * NOTE: The Tonga slot fru_unit needs to get mapped to the logical
2989          * slot number in slot_table[].  The field is not in the slot_table
2990          * at least until we know the format of the OBP slot table for the FCS
2991          * release.
2992          */
2993         mct_system_info.fru_info_list[SLOT] = (fru_info_t *)
2994             kmem_zalloc(sizeof (fru_info_t) *
2995             (mct_system_info.max_units[SLOT] + pad), KM_SLEEP);
2996         fru_ptr = mct_system_info.fru_info_list[SLOT];
2997         for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) {
2998                 int     iunit;
2999                 if (unit == cpu_slot_num) {
3000                         fru_ptr->fru_type = (scsb_utype_t)OC_CPU;
3001                 } else if (unit == ctc_slot_num) {
3002                         /* fru_ptr saved for Transition Card Presence check */
3003                         ctcslot_ptr = fru_ptr;
3004                         fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
3005                 } else if (unit == alarm_slot_num) {
3006                         /* fru_ptr saved for Alarm Card Presence check below */
3007                         acslot_ptr = fru_ptr;
3008                         fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
3009                 } else {
3010                         fru_ptr->fru_type = (scsb_utype_t)OC_UNKN;
3011                 }
3012                 /*
3013                  * Get the slot event code (t), then use it to get the
3014                  * slot bit-offsets for LED, BLINK, and SYSCFG registers.
3015                  * On a P1.5 Tonga, the internal slot number must be used to
3016                  * find the event code.
3017                  * The P1.0 Tonga does not get mapped due to a SSB difference.
3018                  */
3019                 if (IS_SCB_P15) {
3020                         iunit = tonga_psl_to_ssl(scsb, unit);
3021                         t = FRU_UNIT_TO_EVCODE(SLOT, iunit);
3022                 } else {
3023                         t = FRU_UNIT_TO_EVCODE(SLOT, unit);
3024                 }
3025                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3026                 blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3027                 blink_reg = FRU_REG_ADDR(t, SCTRL_BLINK_OK_BASE);
3028                 if (is_tonga && unit <= TG_MAX_SLOTS) {
3029                         bit_num = tonga_pslotnum_to_cfgbit(scsb, unit);
3030                 } else {
3031                         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3032                 }
3033                 /*
3034                  * get the registers addresses and shadow register index for
3035                  * the SYSCFG register
3036                  */
3037                 syscfg = FRU_REG_ADDR(t, SCTRL_SYSCFG_BASE);
3038                 index = SCSB_REG_INDEX(syscfg);
3039                 led_reg = FRU_REG_ADDR(t, SCTRL_LED_OK_BASE);
3040                 /*
3041                  * check and set presence status
3042                  */
3043                 if (scsb->scsb_state & SCSB_P06_PROM) {
3044                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3045                 } else if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3046                         fru_ptr->fru_status = FRU_PRESENT;
3047                 } else {
3048                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3049                 }
3050                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3051                 fru_ptr->fru_id = fru_id_table[event_to_index(
3052                     FRU_UNIT_TO_EVCODE(SLOT, unit))];
3053                 fru_ptr->fru_version = (fru_version_t)0;
3054                 fru_ptr->type_list = (fru_options_t *)NULL;
3055                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3056                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3057                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3058                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3059                 fru_ptr->i2c_info->ledata_reg = led_reg;
3060                 fru_ptr->i2c_info->ledata_bit = led_bit;
3061                 fru_ptr->i2c_info->blink_reg = blink_reg;
3062                 fru_ptr->i2c_info->blink_bit = blink_bit;
3063                 last_ptr = fru_ptr;
3064                 fru_ptr++;
3065                 last_ptr->next = fru_ptr;
3066         }
3067         last_ptr->next = (fru_info_t *)NULL;
3068         /*
3069          * PDU
3070          */
3071         mct_system_info.fru_info_list[PDU] = (fru_info_t *)
3072             kmem_zalloc(sizeof (fru_info_t) *
3073             (mct_system_info.max_units[PDU] + pad), KM_SLEEP);
3074         fru_ptr = mct_system_info.fru_info_list[PDU];
3075         for (unit = 1; unit <= mct_system_info.max_units[PDU]; ++unit) {
3076                 fru_ptr->fru_type = PDU;
3077                 /* SCB15 */
3078                 /*
3079                  * get the FRU event code (t), then use it to get the
3080                  * FRU bit-offsets for LED and SYSCFG registers
3081                  */
3082                 t = FRU_UNIT_TO_EVCODE(PDU, unit);
3083                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3084                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3085                 if (IS_SCB_P15) {
3086                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3087                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3088                         blink_reg = SCSB_REG_ADDR(i);
3089                 } else {
3090                         blink_bit = 0;
3091                         blink_reg = 0;
3092                 }
3093                 /*
3094                  * get the registers addresses and shadow register index for
3095                  * the SYSCFG register
3096                  */
3097                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3098                 syscfg = SCSB_REG_ADDR(i);
3099                 index = SCSB_REG_INDEX(syscfg);
3100                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3101                 led_reg = SCSB_REG_ADDR(i);
3102                 /*
3103                  * check and set presence status
3104                  */
3105                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3106                         fru_ptr->fru_status = FRU_PRESENT;
3107                         fru_ptr->fru_version = (fru_version_t)0;
3108                 } else {
3109                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3110                         fru_ptr->fru_version = (fru_version_t)0;
3111                 }
3112                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3113                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3114                 fru_ptr->type_list = (fru_options_t *)NULL;
3115                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3116                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3117                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3118                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3119                 fru_ptr->i2c_info->ledata_reg = led_reg;
3120                 fru_ptr->i2c_info->ledata_bit = led_bit;
3121                 fru_ptr->i2c_info->blink_reg = blink_reg;
3122                 fru_ptr->i2c_info->blink_bit = blink_bit;
3123                 last_ptr = fru_ptr;
3124                 fru_ptr++;
3125                 last_ptr->next = fru_ptr;
3126         }
3127         last_ptr->next = (fru_info_t *)NULL;
3128         /*
3129          * Power Supplies
3130          */
3131         mct_system_info.fru_info_list[PS] = (fru_info_t *)
3132             kmem_zalloc(sizeof (fru_info_t) *
3133             (mct_system_info.max_units[PS] + pad), KM_SLEEP);
3134         fru_ptr = mct_system_info.fru_info_list[PS];
3135         for (unit = 1; unit <= mct_system_info.max_units[PS]; ++unit) {
3136                 /*
3137                  * get the FRU event code (t), then use it to get the
3138                  * FRU bit-offsets for LED and SYSCFG registers
3139                  */
3140                 t = FRU_UNIT_TO_EVCODE(PS, unit);
3141                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3142                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3143                 if (IS_SCB_P15) {
3144                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3145                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3146                         blink_reg = SCSB_REG_ADDR(i);
3147                 } else {
3148                         blink_bit = 0;
3149                         blink_reg = 0;
3150                 }
3151                 /*
3152                  * get the registers addresses and shadow register index for
3153                  * the SYSCFG register
3154                  */
3155                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3156                 syscfg = SCSB_REG_ADDR(i);
3157                 index = SCSB_REG_INDEX(syscfg);
3158                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3159                 led_reg = SCSB_REG_ADDR(i);
3160                 /*
3161                  * check and set presence status
3162                  */
3163                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3164                         fru_ptr->fru_status = FRU_PRESENT;
3165                 } else {
3166                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3167                 }
3168                 fru_ptr->fru_type = PS;
3169                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3170                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3171                 fru_ptr->fru_version = (fru_version_t)0;
3172                 fru_ptr->type_list = (fru_options_t *)NULL;
3173                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3174                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3175                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3176                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3177                 fru_ptr->i2c_info->ledata_reg = led_reg;
3178                 fru_ptr->i2c_info->ledata_bit = led_bit;
3179                 fru_ptr->i2c_info->blink_reg = blink_reg;
3180                 fru_ptr->i2c_info->blink_bit = blink_bit;
3181                 last_ptr = fru_ptr;
3182                 fru_ptr++;
3183                 last_ptr->next = fru_ptr;
3184         }
3185         last_ptr->next = (fru_info_t *)NULL;
3186         /*
3187          * SCSI Disks and removable media
3188          */
3189         mct_system_info.fru_info_list[DISK] = (fru_info_t *)
3190             kmem_zalloc(sizeof (fru_info_t) *
3191             (mct_system_info.max_units[DISK] + pad), KM_SLEEP);
3192         fru_ptr = mct_system_info.fru_info_list[DISK];
3193         for (unit = 1; unit <= mct_system_info.max_units[DISK]; ++unit) {
3194                 /* SCB15 */
3195                 /*
3196                  * get the FRU event code (t), then use it to get the
3197                  * FRU bit-offsets for LED and SYSCFG registers
3198                  */
3199                 t = FRU_UNIT_TO_EVCODE(DISK, unit);
3200                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3201                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3202                 if (IS_SCB_P15) {
3203                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3204                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3205                         blink_reg = SCSB_REG_ADDR(i);
3206                 } else {
3207                         blink_bit = 0;
3208                         blink_reg = 0;
3209                 }
3210                 /*
3211                  * get the registers addresses and shadow register index for
3212                  * the SYSCFG register
3213                  */
3214                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3215                 syscfg = SCSB_REG_ADDR(i);
3216                 index = SCSB_REG_INDEX(syscfg);
3217                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3218                 led_reg = SCSB_REG_ADDR(i);
3219                 /*
3220                  * check and set presence status
3221                  */
3222                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3223                         fru_ptr->fru_status = FRU_PRESENT;
3224                         fru_ptr->fru_version = (fru_version_t)0;
3225                 } else
3226                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3227                 fru_ptr->fru_type = DISK;
3228                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3229                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3230                 fru_ptr->type_list = (fru_options_t *)NULL;
3231                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3232                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3233                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3234                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3235                 fru_ptr->i2c_info->ledata_reg = led_reg;
3236                 fru_ptr->i2c_info->ledata_bit = led_bit;
3237                 fru_ptr->i2c_info->blink_reg = blink_reg;
3238                 fru_ptr->i2c_info->blink_bit = blink_bit;
3239                 last_ptr = fru_ptr;
3240                 fru_ptr++;
3241                 last_ptr->next = fru_ptr;
3242         }
3243         last_ptr->next = (fru_info_t *)NULL;
3244         /*
3245          * Fan Trays
3246          */
3247         mct_system_info.fru_info_list[FAN] = (fru_info_t *)
3248             kmem_zalloc(sizeof (fru_info_t) *
3249             (mct_system_info.max_units[FAN] + pad), KM_SLEEP);
3250         fru_ptr = mct_system_info.fru_info_list[FAN];
3251         for (unit = 1; unit <= mct_system_info.max_units[FAN]; ++unit) {
3252                 int             bit_num;
3253                 /* SCB15 */
3254                 /*
3255                  * get the FRU event code (t), then use it to get the
3256                  * FRU bit-offsets for LED and SYSCFG registers
3257                  */
3258                 t = FRU_UNIT_TO_EVCODE(FAN, unit);
3259                 led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3260                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3261                 if (IS_SCB_P15) {
3262                         blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3263                         i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3264                         blink_reg = SCSB_REG_ADDR(i);
3265                 } else {
3266                         blink_bit = 0;
3267                         blink_reg = 0;
3268                 }
3269                 /*
3270                  * get the registers addresses and shadow register index for
3271                  * the SYSCFG register
3272                  */
3273                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3274                 syscfg = SCSB_REG_ADDR(i);
3275                 index = SCSB_REG_INDEX(syscfg);
3276                 i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3277                 led_reg = SCSB_REG_ADDR(i);
3278                 /*
3279                  * check and set presence status
3280                  */
3281                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3282                         fru_ptr->fru_status = FRU_PRESENT;
3283                 } else {
3284                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3285                 }
3286                 fru_ptr->fru_type = FAN;
3287                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3288                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3289                 fru_ptr->fru_version = (fru_version_t)0;
3290                 fru_ptr->type_list = (fru_options_t *)NULL;
3291                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3292                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3293                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3294                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3295                 fru_ptr->i2c_info->ledata_reg = led_reg;
3296                 fru_ptr->i2c_info->ledata_bit = led_bit;
3297                 fru_ptr->i2c_info->blink_reg = blink_reg;
3298                 fru_ptr->i2c_info->blink_bit = blink_bit;
3299                 last_ptr = fru_ptr;
3300                 fru_ptr++;
3301                 last_ptr->next = fru_ptr;
3302         }
3303         last_ptr->next = (fru_info_t *)NULL;
3304         /*
3305          * Alarm Cards
3306          */
3307         mct_system_info.fru_info_list[ALARM] = (fru_info_t *)
3308             kmem_zalloc(sizeof (fru_info_t) *
3309             (mct_system_info.max_units[ALARM] + pad), KM_SLEEP);
3310         fru_ptr = mct_system_info.fru_info_list[ALARM];
3311         for (unit = 1; unit <= mct_system_info.max_units[ALARM]; ++unit) {
3312                 int             bit_num;
3313 
3314                 /*
3315                  * get the FRU event code (t), then use it to get the
3316                  * FRU bit-offsets for SYSCFG register
3317                  */
3318                 t = FRU_UNIT_TO_EVCODE(ALARM, unit);
3319                 bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3320                 /*
3321                  * get the registers addresses and shadow register index for
3322                  * the SYSCFG register
3323                  */
3324                 i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3325                 syscfg = SCSB_REG_ADDR(i);
3326                 index = SCSB_REG_INDEX(syscfg);
3327                 /*
3328                  * check and set presence status
3329                  */
3330                 if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3331                         fru_ptr->fru_status = FRU_PRESENT;
3332                         if (acslot_ptr != NULL && acslot_ptr->fru_status ==
3333                             FRU_PRESENT) {
3334                                 acslot_ptr->fru_type = (scsb_utype_t)OC_AC;
3335                                 /*
3336                                  * acslot_ptr->fru_id =
3337                                  *      fru_id_table[event_to_index(t)];
3338                                  */
3339                         }
3340                 } else {
3341                         fru_ptr->fru_status = FRU_NOT_PRESENT;
3342                 }
3343 
3344                 fru_ptr->fru_type = ALARM;
3345                 fru_ptr->fru_unit = (scsb_unum_t)unit;
3346                 fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3347                 fru_ptr->fru_version = (fru_version_t)0;
3348                 fru_ptr->type_list = (fru_options_t *)NULL;
3349                 fru_ptr->i2c_info = (fru_i2c_info_t *)
3350                     kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3351                 fru_ptr->i2c_info->syscfg_reg = syscfg;
3352                 fru_ptr->i2c_info->syscfg_bit = bit_num;
3353                 fru_ptr->i2c_info->ledata_reg = 0;
3354                 fru_ptr->i2c_info->ledata_bit = 0;
3355                 fru_ptr->i2c_info->blink_reg = 0;
3356                 fru_ptr->i2c_info->blink_bit = 0;
3357                 last_ptr = fru_ptr;
3358                 fru_ptr++;
3359                 last_ptr->next = fru_ptr;
3360         }
3361         last_ptr->next = (fru_info_t *)NULL;
3362         /*
3363          * SCB
3364          */
3365         mct_system_info.fru_info_list[SCB] = (fru_info_t *)
3366             kmem_zalloc(sizeof (fru_info_t) *
3367             (mct_system_info.max_units[SCB] + pad), KM_SLEEP);
3368         fru_ptr = mct_system_info.fru_info_list[SCB];
3369         unit = 1;
3370         /* SCB15 */
3371         /*
3372          * get the FRU event code (t), then use it to get the
3373          * FRU bit-offset for LED register
3374          */
3375         t = FRU_UNIT_TO_EVCODE(SCB, unit);
3376         led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3377         i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3378         led_reg = SCSB_REG_ADDR(i);
3379         if (IS_SCB_P15) {
3380                 blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3381                 i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3382                 blink_reg = SCSB_REG_ADDR(i);
3383         } else {
3384                 blink_bit = 0;
3385                 blink_reg = 0;
3386         }
3387         i = SYS_REG_INDEX(SCTRL_SCBID0, SCTRL_SCBID_BASE);
3388         index = SCSB_REG_ADDR(i);
3389         /*
3390          * check and set presence status
3391          */
3392         if (scsb->scsb_state & SCSB_SCB_PRESENT) {
3393                 fru_ptr->fru_status = FRU_PRESENT;
3394         } else {
3395                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3396         }
3397         fru_ptr->fru_type = SCB;
3398         fru_ptr->fru_unit = (scsb_unum_t)unit;
3399         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3400         /* get PROM_VERSION from shadow registers */
3401         if (scsb_rdwr_register(scsb, I2C_WR_RD, index, 1, &t_uchar, 1))
3402                 fru_ptr->fru_version = (fru_version_t)0;
3403         else
3404                 fru_ptr->fru_version = (fru_version_t)t_uchar;
3405         fru_ptr->type_list = (fru_options_t *)NULL;
3406         fru_ptr->i2c_info = (fru_i2c_info_t *)
3407             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3408         fru_ptr->i2c_info->syscfg_reg = 0;
3409         fru_ptr->i2c_info->syscfg_bit = 0;
3410         fru_ptr->i2c_info->ledata_reg = led_reg;
3411         fru_ptr->i2c_info->ledata_bit = led_bit;
3412         fru_ptr->i2c_info->blink_reg = blink_reg;
3413         fru_ptr->i2c_info->blink_bit = blink_bit;
3414         fru_ptr->next = (fru_info_t *)NULL;
3415         /*
3416          * SSB
3417          */
3418         mct_system_info.fru_info_list[SSB] = (fru_info_t *)
3419             kmem_zalloc(sizeof (fru_info_t) *
3420             (mct_system_info.max_units[SSB] + pad), KM_SLEEP);
3421         fru_ptr = mct_system_info.fru_info_list[SSB];
3422         unit = 1;
3423         /* SCB15 */
3424         /*
3425          * get the FRU event code (t), then use it to get the
3426          * FRU bit-offset for SYSCFG register
3427          */
3428         t = FRU_UNIT_TO_EVCODE(SSB, unit);
3429         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3430         /*
3431          * get the registers addresses and shadow register index for
3432          * the SYSCFG register
3433          */
3434         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3435         syscfg = SCSB_REG_ADDR(i);
3436         index = SCSB_REG_INDEX(syscfg);
3437         /*
3438          * check and set presence status
3439          */
3440         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3441                 fru_ptr->fru_status = FRU_PRESENT;
3442         } else {
3443                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3444         }
3445         fru_ptr->fru_type = SSB;
3446         fru_ptr->fru_unit = (scsb_unum_t)unit;
3447         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3448         fru_ptr->fru_version = (fru_version_t)0;
3449         fru_ptr->type_list = (fru_options_t *)NULL;
3450         fru_ptr->i2c_info = (fru_i2c_info_t *)
3451             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3452         fru_ptr->i2c_info->syscfg_reg = syscfg;
3453         fru_ptr->i2c_info->syscfg_bit = bit_num;
3454         fru_ptr->i2c_info->ledata_reg = 0;
3455         fru_ptr->i2c_info->ledata_bit = 0;
3456         fru_ptr->i2c_info->blink_reg = 0;
3457         fru_ptr->i2c_info->blink_bit = 0;
3458         fru_ptr->next = (fru_info_t *)NULL;
3459         /*
3460          * CFTM
3461          */
3462         mct_system_info.fru_info_list[CFTM] = (fru_info_t *)
3463             kmem_zalloc(sizeof (fru_info_t) *
3464             (mct_system_info.max_units[CFTM] + pad), KM_SLEEP);
3465         fru_ptr = mct_system_info.fru_info_list[CFTM];
3466         unit = 1;
3467         /* SCB15 */
3468         /*
3469          * get the FRU event code (t), then use it to get the
3470          * FRU bit-offsets for LED and SYSCFG registers
3471          */
3472         t = FRU_UNIT_TO_EVCODE(CFTM, unit);
3473         led_bit = FRU_OFFSET(t, SCTRL_LED_OK_BASE);
3474         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3475         if (IS_SCB_P15) {
3476                 blink_bit = FRU_OFFSET(t, SCTRL_BLINK_OK_BASE);
3477                 i = FRU_REG_INDEX(t, SCTRL_BLINK_OK_BASE);
3478                 blink_reg = SCSB_REG_ADDR(i);
3479         } else {
3480                 blink_bit = 0;
3481                 blink_reg = 0;
3482         }
3483         /*
3484          * get the registers addresses and shadow register index for
3485          * the SYSCFG register
3486          */
3487         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3488         syscfg = SCSB_REG_ADDR(i);
3489         index = SCSB_REG_INDEX(syscfg);
3490         i = FRU_REG_INDEX(t, SCTRL_LED_OK_BASE);
3491         led_reg = SCSB_REG_ADDR(i);
3492         /*
3493          * check and set presence status
3494          */
3495         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3496                 fru_ptr->fru_status = FRU_PRESENT;
3497                 if (ctcslot_ptr != NULL && ctcslot_ptr->fru_status ==
3498                     FRU_PRESENT) {
3499                         ctcslot_ptr->fru_type = (scsb_utype_t)OC_CTC;
3500                         scsb->scsb_hsc_state |= SCSB_HSC_CTC_PRES;
3501                 }
3502         } else {
3503                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3504         }
3505         fru_ptr->fru_type = CFTM;
3506         fru_ptr->fru_unit = (scsb_unum_t)1;
3507         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3508         fru_ptr->fru_version = (fru_version_t)0;
3509         fru_ptr->type_list = (fru_options_t *)NULL;
3510         fru_ptr->i2c_info = (fru_i2c_info_t *)
3511             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3512         fru_ptr->i2c_info->syscfg_reg = syscfg;
3513         fru_ptr->i2c_info->syscfg_bit = bit_num;
3514         fru_ptr->i2c_info->ledata_reg = led_reg;
3515         fru_ptr->i2c_info->ledata_bit = led_bit;
3516         fru_ptr->i2c_info->blink_reg = blink_reg;
3517         fru_ptr->i2c_info->blink_bit = blink_bit;
3518         fru_ptr->next = (fru_info_t *)NULL;
3519         /*
3520          * CRTM
3521          */
3522         mct_system_info.fru_info_list[CRTM] = (fru_info_t *)
3523             kmem_zalloc(sizeof (fru_info_t) *
3524             (mct_system_info.max_units[CRTM] + pad),
3525             KM_SLEEP);
3526         fru_ptr = mct_system_info.fru_info_list[CRTM];
3527         unit = 1;
3528         /* SCB15 */
3529         /*
3530          * get the FRU event code (t), then use it to get the
3531          * FRU bit-offsets for LED and SYSCFG registers
3532          */
3533         t = FRU_UNIT_TO_EVCODE(CRTM, unit);
3534         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3535         /*
3536          * get the registers addresses and shadow register index for
3537          * the SYSCFG register
3538          */
3539         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3540         syscfg = SCSB_REG_ADDR(i);
3541         index = SCSB_REG_INDEX(syscfg);
3542         /*
3543          * check and set presence status
3544          */
3545         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3546                 fru_ptr->fru_status = FRU_PRESENT;
3547         } else {
3548                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3549         }
3550         fru_ptr->fru_type = CRTM;
3551         fru_ptr->fru_unit = (scsb_unum_t)unit;
3552         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3553         fru_ptr->fru_version = (fru_version_t)0;
3554         fru_ptr->type_list = (fru_options_t *)NULL;
3555         fru_ptr->i2c_info = (fru_i2c_info_t *)
3556             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3557         fru_ptr->i2c_info->syscfg_reg = syscfg;
3558         fru_ptr->i2c_info->syscfg_bit = bit_num;
3559         fru_ptr->i2c_info->ledata_reg = 0;
3560         fru_ptr->i2c_info->ledata_bit = 0;
3561         fru_ptr->i2c_info->blink_reg = 0;
3562         fru_ptr->i2c_info->blink_bit = 0;
3563         fru_ptr->next = (fru_info_t *)NULL;
3564         /*
3565          * PRTM
3566          */
3567         mct_system_info.fru_info_list[PRTM] = (fru_info_t *)
3568             kmem_zalloc(sizeof (fru_info_t) *
3569             (mct_system_info.max_units[PRTM] + pad), KM_SLEEP);
3570         fru_ptr = mct_system_info.fru_info_list[PRTM];
3571         unit = 1;
3572         /*
3573          * SCB15
3574          * get the FRU event code (t), then use it to get the
3575          * FRU bit-offsets for LED and SYSCFG registers
3576          */
3577         t = FRU_UNIT_TO_EVCODE(PRTM, unit);
3578         bit_num = FRU_OFFSET(t, SCTRL_SYSCFG_BASE);
3579         /*
3580          * get the registers addresses and shadow register index for
3581          * the SYSCFG register
3582          */
3583         i = FRU_REG_INDEX(t, SCTRL_SYSCFG_BASE);
3584         syscfg = SCSB_REG_ADDR(i);
3585         index = SCSB_REG_INDEX(syscfg);
3586         /*
3587          * check and set presence status
3588          */
3589         if (scsb->scsb_data_reg[index] & (1 << bit_num)) {
3590                 fru_ptr->fru_status = FRU_PRESENT;
3591         } else {
3592                 fru_ptr->fru_status = FRU_NOT_PRESENT;
3593         }
3594         fru_ptr->fru_type = PRTM;
3595         fru_ptr->fru_unit = (scsb_unum_t)unit;
3596         fru_ptr->fru_id = fru_id_table[event_to_index(t)];
3597         fru_ptr->fru_version = (fru_version_t)0;
3598         fru_ptr->type_list = (fru_options_t *)NULL;
3599         fru_ptr->i2c_info = (fru_i2c_info_t *)
3600             kmem_zalloc(sizeof (fru_i2c_info_t), KM_SLEEP);
3601         fru_ptr->i2c_info->syscfg_reg = syscfg;
3602         fru_ptr->i2c_info->syscfg_bit = bit_num;
3603         fru_ptr->i2c_info->ledata_reg = 0;
3604         fru_ptr->i2c_info->ledata_bit = 0;
3605         fru_ptr->i2c_info->blink_reg = 0;
3606         fru_ptr->i2c_info->blink_bit = 0;
3607         fru_ptr->next = (fru_info_t *)NULL;
3608 
3609         scsb->scsb_state |= SCSB_TOPOLOGY;
3610 #ifdef DEBUG
3611         mct_topology_dump(scsb, 0);
3612 #endif
3613 }
3614 
3615 /*ARGSUSED*/
3616 static void
3617 scsb_free_topology(scsb_state_t *scsb)
3618 {
3619         int             i;
3620         fru_info_t      *fru_ptr;
3621 
3622         if (scsb_debug & 0x00100005)
3623                 cmn_err(CE_NOTE, "scsb_free_topology:");
3624         for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
3625                 fru_ptr = mct_system_info.fru_info_list[i];
3626                 while (fru_ptr != NULL) {
3627                         if (fru_ptr->i2c_info != (fru_i2c_info_t *)NULL)
3628                                 kmem_free(fru_ptr->i2c_info,
3629                                     sizeof (fru_i2c_info_t));
3630                         fru_ptr = fru_ptr->next;
3631                 }
3632                 if ((fru_ptr = mct_system_info.fru_info_list[i]) !=
3633                     (fru_info_t *)NULL) {
3634                         kmem_free(fru_ptr, sizeof (fru_info_t) *
3635                             mct_system_info.max_units[i]);
3636                         mct_system_info.fru_info_list[i] = (fru_info_t *)NULL;
3637                 }
3638         }
3639 }
3640 
3641 #ifdef DEBUG
3642 static void
3643 mct_topology_dump(scsb_state_t *scsb, int force)
3644 {
3645         int             i;
3646         fru_info_t      *fru_ptr;
3647 
3648         if (!force && !(scsb_debug & 0x00200000))
3649                 return;
3650         if (force && !(scsb->scsb_state & (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE)))
3651                 return;
3652         if (!(scsb->scsb_state & SCSB_TOPOLOGY)) {
3653                 cmn_err(CE_NOTE, "mct_topology_dump: Topology not set!");
3654                 return;
3655         }
3656         for (i = 0; i < SCSB_UNIT_TYPES; ++i) {
3657                 fru_ptr = mct_system_info.fru_info_list[i];
3658                 switch ((scsb_utype_t)i) {
3659                 case SLOT:
3660                         cmn_err(CE_NOTE, "MCT: Number of Slots: %d",
3661                             mct_system_info.max_units[SLOT]);
3662                         break;
3663                 case ALARM:
3664                         cmn_err(CE_NOTE, "MCT: MAX Number of Alarm Cards: %d",
3665                             mct_system_info.max_units[ALARM]);
3666                         break;
3667                 case DISK:
3668                         cmn_err(CE_NOTE, "MCT: MAX Number of SCSI Devices: %d",
3669                             mct_system_info.max_units[DISK]);
3670                         break;
3671                 case FAN:
3672                         cmn_err(CE_NOTE, "MCT: MAX Number of Fan Trays: %d",
3673                             mct_system_info.max_units[FAN]);
3674                         break;
3675                 case PDU:
3676                         cmn_err(CE_NOTE, "MCT: MAX Number of PDUs: %d",
3677                             mct_system_info.max_units[PDU]);
3678                         break;
3679                 case PS:
3680                         cmn_err(CE_NOTE,
3681                             "MCT: MAX Number of Power Supplies: %d",
3682                             mct_system_info.max_units[PS]);
3683                         break;
3684                 case SCB:
3685                         cmn_err(CE_NOTE, "MCT: MAX Number of SCBs: %d",
3686                             mct_system_info.max_units[SCB]);
3687                         break;
3688                 case SSB:
3689                         cmn_err(CE_NOTE, "MCT: MAX Number of SSBs: %d",
3690                             mct_system_info.max_units[SSB]);
3691                         break;
3692                 }
3693                 while (fru_ptr != NULL) {
3694                         if (fru_ptr->fru_status & FRU_PRESENT) {
3695                                 cmn_err(CE_NOTE,
3696                                     "MCT:   type=%d, unit=%d, id=0x%x, "
3697                                     "version=0x%x",
3698                                     fru_ptr->fru_type,
3699                                     fru_ptr->fru_unit,
3700                                     fru_ptr->fru_id,
3701                                     fru_ptr->fru_version);
3702                         }
3703                         fru_ptr = fru_ptr->next;
3704                 }
3705         }
3706 }
3707 
3708 /*
3709  * Sends an event when the system controller board I2C errors
3710  * exceed the threshold.
3711  */
3712 static void
3713 scsb_failing_event(scsb_state_t *scsb)
3714 {
3715         uint32_t scsb_event_code = SCTRL_EVENT_SCB;
3716 
3717         add_event_code(scsb, scsb_event_code);
3718         (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code,
3719         "scsb_intr");
3720 }
3721 #endif
3722 
3723 int
3724 scsb_read_bhealthy(scsb_state_t *scsb)
3725 {
3726         int             error;
3727         uchar_t         reg;
3728         int             index;
3729 
3730         if (scsb_debug & 0x8001) {
3731                 cmn_err(CE_NOTE, "scsb_read_bhealthy()");
3732         }
3733         reg = SCSB_REG_ADDR(SCTRL_BHLTHY_BASE);
3734         index = SCSB_REG_INDEX(reg);
3735         error = scsb_rdwr_register(scsb, I2C_WR_RD, reg,
3736             SCTRL_BHLTHY_NUMREGS, &scsb->scsb_data_reg[index], 1);
3737         return (error);
3738 }
3739 
3740 /*
3741  * Returns the health status of a slot
3742  */
3743 int
3744 scsb_read_slot_health(scsb_state_t *scsb, int pslotnum)
3745 {
3746         int slotnum = tonga_psl_to_ssl(scsb, pslotnum);
3747         return (scsb_fru_op(scsb, SLOT, slotnum,
3748             SCTRL_BHLTHY_BASE, SCSB_FRU_OP_GET_BITVAL));
3749 }
3750 
3751 /*
3752  * DIAGNOSTIC and DEBUG only.
3753  * Called from ioctl command (SCSBIOC_BHEALTHY_GET)
3754  */
3755 int
3756 scsb_bhealthy_slot(scsb_state_t *scsb, scsb_uinfo_t *suip)
3757 {
3758         int             error = 0;
3759         int             base, code, unit_number;
3760         uchar_t         reg;
3761         int             index;
3762 
3763         if (scsb->scsb_state & SCSB_FROZEN)
3764                 return (EAGAIN);
3765 
3766         /* operation valid for slots only */
3767         if (suip == NULL || suip->unit_type != SLOT) {
3768                 return (EINVAL);
3769         }
3770 
3771         if (scsb_debug & 0x8001)
3772                 cmn_err(CE_NOTE, "scsb_bhealthy_slot: slot %d",
3773                     suip->unit_number);
3774         if (suip->unit_number > mct_system_info.max_units[SLOT]) {
3775                 return (EINVAL);
3776         }
3777         /*
3778          * Map 1.0 Tonga Slot Number, if necessary
3779          */
3780         tonga_slotnum_check(scsb, suip);
3781         base = SCTRL_BHLTHY_BASE;
3782         code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
3783         unit_number = FRU_OFFSET(code, base);
3784         index = FRU_REG_INDEX(code, base);
3785         reg = SCSB_REG_ADDR(index);
3786         index = SCSB_REG_INDEX(reg);            /* shadow index */
3787 
3788         if (scsb->scsb_state & SCSB_P10_PROM) {
3789                 error = scsb_read_bhealthy(scsb);
3790         }
3791         /* else shadow regs are updated by interrupt handler */
3792         if (error == 0) {
3793                 if (scsb->scsb_data_reg[index] & (1 << unit_number))
3794                         suip->unit_state = ON;
3795                 else
3796                         suip->unit_state = OFF;
3797         }
3798         return (error);
3799 }
3800 
3801 /*
3802  * Called from HSC and ioctl command (SCSBIOC_RESET_UNIT)
3803  * to reset one specified slot
3804  */
3805 int
3806 scsb_reset_unit(scsb_state_t *scsb, scsb_uinfo_t *suip)
3807 {
3808         int             error;
3809         int             unit_number;
3810         uchar_t         reg;
3811         int             index, slotnum, reset_state;
3812 
3813         if (scsb->scsb_state & SCSB_FROZEN)
3814                 return (EAGAIN);
3815         if (scsb_debug & 0x8001) {
3816                 cmn_err(CE_NOTE, "scsb_reset_slot(%d): slot %d, state %d\n",
3817                     scsb->scsb_instance, suip->unit_number,
3818                     suip->unit_state);
3819         }
3820         if (suip->unit_type != ALARM && !(scsb->scsb_state &
3821             (SCSB_DIAGS_MODE | SCSB_DEBUG_MODE))) {
3822                 return (EINVAL);
3823         }
3824         if (suip->unit_state != ON && suip->unit_state != OFF) {
3825                 return (EINVAL);
3826         }
3827         error = 0;
3828         switch (suip->unit_type) {
3829         case ALARM:
3830         {
3831                 int     i, code;
3832                 if (suip->unit_number != 1)
3833                         return (EINVAL);
3834                 code = FRU_UNIT_TO_EVCODE(suip->unit_type, suip->unit_number);
3835                 unit_number = FRU_OFFSET(code, SCTRL_RESET_BASE);
3836                 i = ALARM_RESET_REG_INDEX(code, SCTRL_RESET_BASE);
3837                 reg = SCSB_REG_ADDR(i);
3838                 break;
3839         }
3840         case SLOT:
3841                 slotnum = suip->unit_number;
3842                 reset_state = (suip->unit_state == ON) ? SCSB_RESET_SLOT :
3843                     SCSB_UNRESET_SLOT;
3844                 if (scsb->scsb_state & SCSB_IS_TONGA) {
3845                         if (slotnum > TG_MAX_SLOTS ||
3846                             slotnum == SC_TG_CPU_SLOT) {
3847                                 return (EINVAL);
3848                         }
3849                 } else {
3850                         if (slotnum > MC_MAX_SLOTS ||
3851                             slotnum == SC_MC_CPU_SLOT ||
3852                             (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
3853                             slotnum == SC_MC_CTC_SLOT)) {
3854                                 return (EINVAL);
3855                         }
3856                 }
3857                 return (scsb_reset_slot(scsb, slotnum, reset_state));
3858         default:
3859                 return (EINVAL);
3860         }
3861         index = SCSB_REG_INDEX(reg);
3862         mutex_enter(&scsb->scsb_mutex);
3863         if (suip->unit_state == ON)
3864                 scsb->scsb_data_reg[index] |= (1 << unit_number);
3865         else /* OFF */
3866                 scsb->scsb_data_reg[index] &= ~(1 << unit_number);
3867         if ((error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
3868             &scsb->scsb_data_reg[index], 0)) != 0) {
3869                 if (scsb_debug & 0x8002)
3870                         cmn_err(CE_WARN,
3871                             "scsb_leds: write failure to 0x%x", reg);
3872                 return (error);
3873         }
3874         mutex_exit(&scsb->scsb_mutex);
3875         return (error);
3876 }
3877 
3878 /*
3879  * Diagnostic and DEBUG
3880  * This is a helper function for the helper ioctl to pretend that
3881  * scsb h/w is doing its job!!!
3882  */
3883 int
3884 scsb_slot_occupancy(scsb_state_t *scsb, scsb_uinfo_t *suip)
3885 {
3886         int             error;
3887         int             saved_unit_number;
3888 
3889         if (!(scsb->scsb_state & (SCSB_DEBUG_MODE | SCSB_DIAGS_MODE)))
3890                 return (EACCES);
3891         if (scsb->scsb_state & SCSB_FROZEN) {
3892                 return (EAGAIN);
3893         }
3894         error = 0;
3895         switch (suip->unit_type) {
3896         case ALARM:
3897                 if (suip->unit_number !=
3898                     (mct_system_info.fru_info_list[ALARM])->fru_unit) {
3899                         return (EINVAL);
3900                 }
3901                 break;
3902 
3903         case SLOT:
3904                 /*
3905                  * All slots are acceptable, except slots 11 & 12.
3906                  */
3907                 if (suip->unit_number < 1 || suip->unit_number >
3908                     mct_system_info.max_units[ALARM]) {
3909                         error = EINVAL;
3910                         break;
3911                 }
3912                 /* Map 1.0 Tonga Slot Numbers if necessary */
3913                 saved_unit_number = suip->unit_number;
3914                 tonga_slotnum_check(scsb, suip);
3915                 break;
3916 
3917         default:
3918                 error = EINVAL;
3919                 break;
3920         }
3921 
3922         if (error)
3923                 return (error);
3924         if (suip->unit_state == ON) {
3925                 if (hsc_slot_occupancy(saved_unit_number, B_TRUE, 0, B_TRUE)
3926                     != 0)
3927                         error = EFAULT;
3928         } else {
3929                 if (hsc_slot_occupancy(saved_unit_number, B_FALSE, 0, B_FALSE)
3930                     != 0)
3931                         error = EFAULT;
3932         }
3933 
3934         return (error);
3935 }
3936 
3937 static int
3938 scsb_clear_intptrs(scsb_state_t *scsb)
3939 {
3940         int             i, error;
3941         uchar_t         wbuf[SCTRL_MAX_GROUP_NUMREGS];
3942         error = 0;
3943         for (i = 1; i <= SCTRL_INTR_NUMREGS; ++i) {
3944                 wbuf[i] = 0xff;
3945         }
3946         if (error = scsb_rdwr_register(scsb, I2C_WR,
3947             SCSB_REG_ADDR(SCTRL_INTSRC_BASE),
3948             SCTRL_INTR_NUMREGS, wbuf, 1)) {
3949                 if (scsb_debug & 0x0402)
3950                         cmn_err(CE_NOTE, "scsb_clear_intptrs(): "
3951                             "write to 0x%x failed",
3952                             SCSB_REG_ADDR(SCTRL_INTSRC_BASE));
3953         }
3954         return (error);
3955 }
3956 
3957 static int
3958 scsb_setall_intmasks(scsb_state_t *scsb)
3959 {
3960         int             error;
3961         uchar_t         reg, wdata, rmask;
3962         int             i;
3963 
3964         /*
3965          * write loop for Interrupt Mask registers
3966          */
3967         if (scsb_debug & 0x0401)
3968                 cmn_err(CE_NOTE, "setall_intmasks()");
3969         error = 0;
3970         rmask = 0;
3971         wdata = 0xff;
3972         reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE);
3973         for (i = 0; i < SCTRL_MASK_NUMREGS; ++i, ++reg) {
3974                 if (error = scsb_write_mask(scsb, reg, rmask, wdata, 0)) {
3975                         if (scsb_debug & 0x0402)
3976                                 cmn_err(CE_NOTE, "scsb_setall_intmasks: "
3977                                     "write to 0x%x failed: %d", reg, error);
3978                         error = EIO;
3979                         break;
3980                 }
3981         }
3982         return (error);
3983 }
3984 
3985 
3986 /*
3987  * Clear Interrupt masks based on the FRUs that could be installed
3988  * for this particular topology, determined by the MidPlane ID
3989  * from SCTRL_SYSCFG registers
3990  *      case SCTRL_MPID_HALF:
3991  *              1 CPU, 1 AlarmCard, 1 SCB/SSB, 2 PS, 3 FAN, 3 SCSI, 8 Slots
3992  *      case SCTRL_MPID_QUARTER:
3993  *              1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 1 SCSI, 4 Slots
3994  *      case SCTRL_MPID_QUARTER_NODSK:
3995  *              1 CPU, 1 AlarmCard, 1 SCB/SSB, 1 PS, 2 FAN, 0 SCSI, 4 Slots
3996  */
3997 static int
3998 scsb_clear_intmasks(scsb_state_t *scsb)
3999 {
4000         int             error;
4001         uchar_t         msk_reg, reg, wdata, rmask;
4002         uchar_t         mask_data[SCTRL_MAX_GROUP_NUMREGS];
4003         int             tmp, idx, code, unit, offset, mbid;
4004         scsb_utype_t    fru_type;
4005         fru_info_t      *fru_ptr;
4006 
4007         if (scsb->scsb_state & SCSB_FROZEN &&
4008             !(scsb->scsb_state & SCSB_IN_INTR)) {
4009                 return (EAGAIN);
4010         }
4011         error = 0;
4012         for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp)
4013                 mask_data[tmp] = 0;
4014         msk_reg = SCSB_REG_ADDR(SCTRL_INTMASK_BASE);
4015         mbid    = SCSB_REG_INDEX(msk_reg); /* the Mask Base Index Delta */
4016         if (scsb_debug & 0x0400) {
4017                 cmn_err(CE_NOTE, "clear_intmasks: msk_reg=0x%x; mbid=%d",
4018                     msk_reg, mbid);
4019         }
4020         for (fru_type = 0; fru_type < SCSB_UNIT_TYPES; ++fru_type) {
4021                 if (fru_type == SCB)
4022                         continue;       /* handle below, 2 reg offsets */
4023                 fru_ptr = mct_system_info.fru_info_list[fru_type];
4024                 for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
4025                         unit = fru_ptr->fru_unit;
4026                         code   = FRU_UNIT_TO_EVCODE(fru_type, unit);
4027                         offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4028                         reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
4029                         idx    = SCSB_REG_INDEX(reg);
4030                         tmp = idx - mbid;
4031                         mask_data[tmp] |= (1 << offset);
4032                         if (scsb_debug & 0x0400)
4033                                 cmn_err(CE_NOTE,
4034                                 "clear_intmasks:%d:%d: PRES mask[%d]:0x%x",
4035                                     fru_type, unit, tmp, mask_data[tmp]);
4036                         if ((fru_type == SLOT) && (IS_SCB_P15)) {
4037                                 /*
4038                                  * Unmask the corresponding Slot HLTHY mask
4039                                  * Use Slot bit and register offsets,
4040                                  *  but with SCTRL_INTMASK_HLTHY_BASE
4041                                  */
4042                                 reg = FRU_REG_ADDR(code,
4043                                     SCTRL_INTMASK_HLTHY_BASE);
4044                                 idx = SCSB_REG_INDEX(reg);
4045                                 tmp = idx - mbid;
4046                                 mask_data[tmp] |= (1 << offset);
4047                                 if (scsb_debug & 0x0400) {
4048                                         cmn_err(CE_NOTE,
4049                                 "clear_intmasks:Slot:%d: HLTHY mask[%d]:0x%x"
4050                                 "; reg=0x%x, idx=%d, mbid=%d",
4051                                             unit, tmp, mask_data[tmp],
4052                                             reg, idx, mbid);
4053                                 }
4054                         }
4055                 }
4056         }
4057         /*
4058          * Now unmask these non-fru interrupt events
4059          *      SCTRL_EVENT_PWRDWN      (almost normal)
4060          *      SCTRL_EVENT_REPLACE     (not used)
4061          *      SCTRL_EVENT_ALARM_INT   (not working in P0.6/P1.0)
4062          *      SCTRL_EVENT_SCB         (SCB 1.5 ONLY; plus SCB_INT_OFFSET)
4063          */
4064         code   = SCTRL_EVENT_PWRDWN;
4065         offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4066         reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
4067         idx    = SCSB_REG_INDEX(reg);
4068         tmp = idx - mbid;
4069         mask_data[tmp] |= (1 << offset);
4070         if (IS_SCB_P15) {
4071                 code   = SCTRL_EVENT_SCB;
4072                 offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4073                 reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE) + SCB_INT_OFFSET;
4074                 idx    = SCSB_REG_INDEX(reg);
4075                 tmp = idx - mbid;
4076                 mask_data[tmp] |= (1 << offset);
4077                 code   = SCTRL_EVENT_ALARM_INT;
4078                 offset = FRU_OFFSET(code, SCTRL_INTMSK_BASE);
4079                 reg    = FRU_REG_ADDR(code, SCTRL_INTMSK_BASE);
4080                 idx    = SCSB_REG_INDEX(reg);
4081                 tmp = idx - mbid;
4082                 mask_data[tmp] |= (1 << offset);
4083         }
4084         for (tmp = 0; tmp < SCTRL_MASK_NUMREGS; ++tmp) {
4085                 rmask = 0;
4086                 wdata = mask_data[tmp];
4087                 if (scsb_debug & 0x0400)
4088                         cmn_err(CE_NOTE, "clear_intmasks:0x%x: ~(0x%x),0x%x",
4089                             msk_reg, (~wdata) & 0xff, wdata);
4090                 mutex_enter(&scsb->scsb_mutex);
4091                 if (error = scsb_write_mask(scsb, msk_reg, rmask,
4092                     (~wdata) & 0xff, wdata)) {
4093                         mutex_exit(&scsb->scsb_mutex);
4094                         if (scsb_debug & 0x0402)
4095                                 cmn_err(CE_NOTE, "scsb_clear_intmasks: "
4096                                     "write to 0x%x failed: %d",
4097                                     msk_reg, error);
4098                         error = EIO;
4099                         break;
4100                 }
4101                 mutex_exit(&scsb->scsb_mutex);
4102                 ++msk_reg;
4103         }
4104         return (error);
4105 }
4106 
4107 static int
4108 scsb_get_status(scsb_state_t *scsb, scsb_status_t *smp)
4109 {
4110         register int    i;
4111 
4112         if (smp == NULL) {
4113                 return (EFAULT);
4114         }
4115         if (scsb_debug & 0x40000000 &&
4116             (scsb->scsb_state & SCSB_DEBUG_MODE ||
4117             scsb->scsb_state & SCSB_DIAGS_MODE)) {
4118                 if (scsb->scsb_state & SCSB_FROZEN) {
4119                         return (EAGAIN);
4120                 }
4121                 mutex_enter(&scsb->scsb_mutex);
4122                 if (scsb_debug & 0x80000000) {
4123                         if ((i = scsb_readall_regs(scsb)) != 0 &&
4124                             scsb->scsb_state & SCSB_DEBUG_MODE)
4125                                 cmn_err(CE_WARN, "scsb_get_status: "
4126                                     "scsb_readall_regs() FAILED");
4127                 } else {
4128                         if ((i = scsb_check_config_status(scsb)) == 0) {
4129                                 i = scsb_set_scfg_pres_leds(scsb, NULL);
4130                         }
4131                 }
4132                 mutex_exit(&scsb->scsb_mutex);
4133                 if (i) {
4134                         cmn_err(CE_WARN,
4135                             "scsb_get_status: FAILED Presence LEDs update");
4136                         return (EIO);
4137                 }
4138         }
4139         for (i = 0; i < SCSB_DATA_REGISTERS; ++i)
4140                 smp->scsb_reg[i] = scsb->scsb_data_reg[i];
4141         return (0);
4142 }
4143 
4144 /*
4145  * scsb_freeze_check:
4146  *      Turn all the leds off on the system monitor card, without changing
4147  *      the state of what we have for scsb. This routine is called only when
4148  *      replacing system monitor card, so the state of the card leds could be
4149  *      restored, using scsb_restore().
4150  *      Also, set state to SCSB_FROZEN which denies access to scsb while in
4151  *      freeze mode.
4152  */
4153 static char  *BAD_BOARD_MSG =
4154         "SCSB: Should NOT remove SCB(%d) while cPCI Slot %d is "
4155         "in RESET with a possible bad board.";
4156 static int      slots_in_reset[SCTRL_MAX_GROUP_NUMREGS];
4157 
4158 static void
4159 scsb_freeze_check(scsb_state_t *scsb)
4160 {
4161         register int    i;
4162         int             offset;
4163         int             unit, slotnum;
4164         int             index;
4165         fru_info_t      *fru_ptr;
4166         uint32_t        code;
4167         uchar_t         reg;
4168 
4169         if (scsb_debug & 0x20001)
4170                 cmn_err(CE_NOTE, "scsb_freeze_check(%d):", scsb->scsb_instance);
4171 
4172         if (scsb->scsb_state & SCSB_FROZEN) {
4173                 return;
4174         }
4175         mutex_enter(&scsb->scsb_mutex);
4176         for (i = 0; i < SCTRL_MAX_GROUP_NUMREGS; ++i)
4177                 slots_in_reset[i] = 0;
4178         /*
4179          * We allow the SCB to be removed only if none of
4180          * the cPCI resets are asserted for occupied slots.
4181          * There shouldn't be a bad board plugged in the system
4182          * while swapping the SCB.
4183          */
4184         fru_ptr = mct_system_info.fru_info_list[SLOT];
4185         for (unit = 1; unit <= mct_system_info.max_units[SLOT]; ++unit) {
4186                 if (IS_SCB_P15) {
4187                         slotnum = tonga_psl_to_ssl(scsb, unit);
4188                 } else {
4189                         slotnum = unit;
4190                 }
4191                 code = FRU_UNIT_TO_EVCODE(SLOT, slotnum);
4192                 offset = FRU_OFFSET(code, SCTRL_RESET_BASE);
4193                 reg = FRU_REG_ADDR(code, SCTRL_RESET_BASE);
4194                 index = SCSB_REG_INDEX(reg);
4195                 if (scsb->scsb_data_reg[index] & (1 << offset)) {
4196                         if (fru_ptr[unit - 1].fru_status == FRU_PRESENT) {
4197                                 slots_in_reset[unit - 1] = unit;
4198                                 cmn_err(CE_NOTE, BAD_BOARD_MSG,
4199                                     scsb->scsb_instance, unit);
4200                         }
4201                 }
4202         }
4203         mutex_exit(&scsb->scsb_mutex);
4204 }
4205 
4206 static void
4207 scsb_freeze(scsb_state_t *scsb)
4208 {
4209         uint32_t        code;
4210         if (scsb_debug & 0x00020002) {
4211                 cmn_err(CE_WARN, "scsb_freeze: SCB%d possibly removed",
4212                     scsb->scsb_instance);
4213         }
4214         if (scsb->scsb_state & SCSB_FROZEN)
4215                 return;
4216         scsb->scsb_state |= SCSB_FROZEN;
4217         scsb->scsb_state &= ~SCSB_SCB_PRESENT;
4218         (void) scsb_hsc_freeze(scsb->scsb_dev);
4219         /*
4220          * Send the EVENT_SCB since there is evidence that the
4221          * System Controller Board has been removed.
4222          */
4223         code = SCTRL_EVENT_SCB;
4224         if (!(scsb->scsb_state & SCSB_IN_INTR))
4225                 scsb_event_code = code;
4226         check_fru_info(scsb, code);
4227         add_event_code(scsb, code);
4228         (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &code, "scsb_freeze");
4229 }
4230 
4231 /*
4232  * scsb_restore will only be called from the interrupt handler context on
4233  * INIT_SCB interrupt for newly inserted SCB.
4234  * Called with mutex held.
4235  */
4236 static void
4237 scsb_restore(scsb_state_t *scsb)
4238 {
4239         if (scsb_debug & 0x20001)
4240                 cmn_err(CE_NOTE, "scsb_restore(%d):", scsb->scsb_instance);
4241 
4242         if (initialize_scb(scsb) != DDI_SUCCESS) {
4243                 if (scsb_debug & 0x00020002) {
4244                         cmn_err(CE_WARN, "scsb_restore: INIT Failed");
4245                 return;
4246                 }
4247         }
4248         /* 9. Clear all Interrupts */
4249         if (scsb_clear_intmasks(scsb)) {
4250                 cmn_err(CE_WARN,
4251                     "scsb%d: I2C TRANSFER Failed", scsb->scsb_instance);
4252                 if (scsb_debug & 0x00020002) {
4253                         cmn_err(CE_WARN, "scsb_restore: clear_intmasks Failed");
4254                 }
4255                 return;
4256         }
4257 
4258         /* 10. */
4259         /* Check if Alarm Card present at boot and set flags */
4260         if (scsb_fru_op(scsb, ALARM, 1, SCTRL_SYSCFG_BASE,
4261             SCSB_FRU_OP_GET_BITVAL))
4262                 scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
4263         else
4264                 scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES;
4265 
4266         scsb->scsb_state &= ~SCSB_FROZEN;
4267         (void) scsb_hsc_restore(scsb->scsb_dev);
4268 }
4269 
4270 /*
4271  * Given an Event Code,
4272  * Return:
4273  *      FRU type    in LSByte
4274  *      unit number in MSByte
4275  */
4276 uint16_t
4277 event_to_type(uint32_t evcode)
4278 {
4279         int             i, li, unit;
4280         uint32_t        ec;
4281         uint16_t        ret;
4282         for (i = li = 0; i < SCSB_UNIT_TYPES; ++i) {
4283                 if (evcode == type_to_code1[i]) {
4284                         ret = (uint16_t)(0x0100 | i);
4285                         return (ret);
4286                 }
4287                 if (evcode < type_to_code1[i]) {
4288                         unit = 1;
4289                         ec = type_to_code1[li];
4290                         while (ec < evcode)
4291                                 ec = ec << 1, ++unit;
4292                         ret = (unit << 8) | li;
4293                         return (ret);
4294                 }
4295                 li = i;
4296         }
4297         return ((uint16_t)0xffff);
4298 }
4299 
4300 /*
4301  * scsb interrupt handler for (MC) PSM_INT vector
4302  * P0.6: HW shipped to beta customers
4303  *      1. did not have Slot Occupant Presense support
4304  *      2. I2C interrupt-map properties not yet tested, using polling daemon
4305  *      3. Polling detects each event reliably twice.
4306  *         clr_bits# are used to keep track of events to be ignored 2nd time
4307  *
4308  * retval flags allow all events to be checked, and still returning the
4309  * correct DDI value.
4310  *
4311  */
4312 #define SCSB_INTR_CLAIMED       1
4313 #define SCSB_INTR_UNCLAIMED     2
4314 #define SCSB_INTR_EVENT         4
4315 
4316 /*
4317  * Does preprocessing of the interrupt. The only thing this
4318  * needs to do is to ask scsb to release the interrupt line.
4319  * and then schedule delayed actual processing using timeout()
4320  */
4321 uint_t
4322 scsb_intr_preprocess(caddr_t arg)
4323 {
4324         scsb_state_t    *scsb = (scsb_state_t *)arg;
4325 
4326         scb_pre_s = gethrtime();
4327 
4328         /*
4329          * If SCSB_IN_INTR is already set in scsb_state,
4330          * it means we are being interrupted by someone else. This can
4331          * happen only if the interrupt does not belong to scsb, and some
4332          * other device, e.g. a FAN or PS is interrupting. So, we
4333          * cancel the previous timeout().
4334          */
4335 
4336         if (scsb->scsb_state & SCSB_IN_INTR) {
4337                 (void) untimeout(scsb_intr_tid);
4338                 (void) scsb_invoke_intr_chain();
4339                 (void) scsb_toggle_psmint(scsb, 1);
4340                 scsb->scsb_state &= ~SCSB_IN_INTR;
4341                 goto intr_end;
4342         }
4343         scsb->scsb_state |= SCSB_IN_INTR;
4344 
4345         /*
4346          * Stop scsb from interrupting first.
4347          */
4348         if (scsb_quiesce_psmint(scsb) != DDI_SUCCESS) {
4349                 goto intr_end;
4350         }
4351 
4352         /*
4353          * Schedule a timeout to actually process the
4354          * interrupt.
4355          */
4356         scsb_intr_tid = timeout((void (*)(void *))scsb_intr, arg,
4357             drv_usectohz(1000));
4358 
4359 intr_end:
4360 
4361         scb_pre_e = gethrtime();
4362         return (DDI_INTR_CLAIMED);
4363 }
4364 
4365 static void scsb_healthy_intr(scsb_state_t *scsb, int pslotnum);
4366 void
4367 scsb_intr(caddr_t arg)
4368 {
4369         scsb_state_t    *scsb = (scsb_state_t *)arg;
4370         int             i, idx, offset, unit, numregs, error;
4371         int             intr_idx, index, offset_base, retval, slotnum, val;
4372         uint32_t        code;
4373         uchar_t         intr_reg, tmp_reg, intr_addr, clr_bits = 0;
4374         uchar_t         ac_slot = B_FALSE;
4375         uchar_t         *int_masks;
4376         uchar_t         cstatus_regs[SCTRL_MAX_GROUP_NUMREGS];
4377         scsb_utype_t    fru_type;
4378         fru_info_t      *fru_ptr;
4379         int             ac_present;
4380 
4381         /*
4382          * Avoid mayhem, make sure we have only one timeout thread running.
4383          */
4384         mutex_enter(&scsb->scsb_mutex);
4385         while (scsb_in_postintr)
4386                 cv_wait(&scsb->scsb_cv, &scsb->scsb_mutex);
4387         scsb_in_postintr = 1;
4388         mutex_exit(&scsb->scsb_mutex);
4389 
4390         scb_post_s = gethrtime();
4391         if (scsb_debug & 0x00002000)
4392                 cmn_err(CE_NOTE, "scsb_intr(%d)", scsb->scsb_instance);
4393         retval = 0;
4394         tmp_reg = 0;
4395         /*
4396          * XXX: Problem, when we want to support swapping between SCB
4397          * versions, then we need to check the SCB PROM ID (CF) register here
4398          * before assuming the same SCB version was re-inserted.
4399          * We will have to duplicate some of the scb_initialization()
4400          * code to set the scsb_state PROM ID bits and to set up the
4401          * register table pointers.
4402          *
4403          * Only if NOT SSB_PRESENT, check the SCB PROM ID
4404          */
4405         if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
4406                 if (scb_check_version(scsb) != DDI_SUCCESS) {
4407 #ifdef DEBUG
4408                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4409                             scsb->scsb_i2c_errcnt > scsb_err_threshold)
4410                                 scsb_failing_event(scsb);
4411 #endif
4412                         goto intr_error;
4413                 }
4414         }
4415         if (IS_SCB_P15) {
4416                 int_masks = scb_15_int_masks;
4417         } else {
4418                 int_masks = scb_10_int_masks;
4419         }
4420         /*
4421          * Now check the INTSRC registers for set bits.
4422          * Do a quick check by OR'ing INTSRC registers together as we copy
4423          * them from the transfer buffer. For P1.0 or earlier we had already
4424          * read the interrupt source registers and wrote them back to stop
4425          * interrupt. So we need to do this step only for P1.5 or later.
4426          * We already read INTSRC6 to take care of SCB insertion case, so
4427          * do not read INTSRC6 again.
4428          */
4429 
4430         if (IS_SCB_P15) {
4431                 intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
4432                 /* read the interrupt register from scsb */
4433                 if (scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr,
4434                     SCTRL_INTR_NUMREGS - 1, scb_intr_regs, 1)) {
4435                         cmn_err(CE_WARN, "scsb_intr: "
4436                             " Failed read of interrupt registers.");
4437 #ifdef DEBUG
4438                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4439                             scsb->scsb_i2c_errcnt > scsb_err_threshold)
4440                                 scsb_failing_event(scsb);
4441 #endif
4442                         goto intr_error;
4443                 }
4444         }
4445 
4446         /*
4447          * We have seen that an interrupt source bit can be set
4448          * even though the corresponding interrupt mask bit
4449          * has been set to mask the interrupt. So we must
4450          * clear all bits set in the interrupt source register.
4451          */
4452         for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) {
4453                 retval |= scb_intr_regs[i];             /* Quick INTSRC check */
4454 #ifdef DEBUG
4455                 if (scsb_debug & 0x08000000) {
4456                         if (tmp_reg || scb_intr_regs[i]) {
4457                                 cmn_err(CE_NOTE, "scsb_intr: INTSRC%d=0x%x",
4458                                     i + 1, scb_intr_regs[i]);
4459                                 ++tmp_reg;
4460                         }
4461                 }
4462 #endif
4463         }
4464         /*
4465          * Any bits from quick check? If this is not our interrupt,
4466          * something is wrong. FAN/PS interrupts are supposed to be
4467          * blocked, but we can not be sure. So, go ahead and call the
4468          * emergency interrupt handlers for FAN/PS devices and mask
4469          * their interrupts, if they aren't already masked.
4470          */
4471         if (retval == 0) {
4472                 goto intr_error;
4473         }
4474 
4475         retval = 0;
4476 
4477         /*
4478          * If SCB 1.5 or 2.0, check for the INIT_SCB Interrupt
4479          * to support Hot SCB Insertion.
4480          * The check was moved here during debugging of the SCB hot insertion.
4481          * Theoretically, this code could be moved back to the check for
4482          * SCTRL_EVENT_SCB in the processing loop below.
4483          */
4484         if (IS_SCB_P15) {
4485                 int     iid;
4486                 iid = SCSB_REG_INDEX(intr_addr);
4487                 offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE);
4488                 tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15);
4489                 intr_idx = SCSB_REG_INDEX(tmp_reg) - iid;
4490                 clr_bits = 1 << offset;
4491                 if (scb_intr_regs[intr_idx] & clr_bits) {
4492                         /*
4493                          * Must be newly inserted SCB
4494                          * Time to re-initialize.
4495                          */
4496                         if (scsb_debug & 0x00023000) {
4497                                 cmn_err(CE_NOTE,
4498                                     "scsb_intr(%d): INIT_SCB INT",
4499                                     scsb->scsb_instance);
4500                         }
4501                         scsb_restore(scsb);
4502                         retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4503                         /*
4504                          * The INTSRC bit will be cleared by the
4505                          * scsb_restore() function.
4506                          * Also, leave the bit set in scb_intr_regs[] so we can
4507                          * report the event code as we check for other
4508                          * interrupt source bits.
4509                          *
4510                          * scsb_write_mask(scsb, tmp_reg, 0, clr_bits, 0);
4511                          * scb_intr_regs[intr_idx] &= ~clr_bits;
4512                          */
4513                 }
4514                 /*
4515                  * In case this is a power down interrupt, check the validity
4516                  * of the request to make sure it's not an I2C noise
4517                  */
4518                 offset = FRU_OFFSET(SCTRL_EVENT_PWRDWN,
4519                     SCTRL_INTPTR_BASE);
4520                 clr_bits = 1 << offset;
4521                 intr_reg = scb_intr_regs[intr_idx];
4522                 if (intr_reg & clr_bits) {
4523                         /*
4524                          * A shutdown request has been detected. Poll
4525                          * the corresponding register ? more times to
4526                          * make sure it's a genuine shutdown request.
4527                          */
4528                         for (i = 0; i < scsb_shutdown_count; i++) {
4529                                 drv_usecwait(1000);
4530                                 if (scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg,
4531                                     1, &intr_reg, 1)) {
4532                                         cmn_err(CE_WARN, "Failed to read "
4533                                             " interrupt register");
4534                                         goto intr_error;
4535                                 }
4536                                 if (scsb_debug & 0x08000000) {
4537                                         cmn_err(CE_NOTE, "scsb_intr: "
4538                                             " INTSRC6[%d]=0x%x", i,
4539                                             intr_reg);
4540                                 }
4541                                 if (!(intr_reg & clr_bits)) {
4542                                         scb_intr_regs[intr_idx] &= ~clr_bits;
4543                                         break;
4544                                 }
4545                         }
4546                 }
4547         }
4548         /*
4549          * if retval == 0, then we didn't call scsb_restore,
4550          * so we update the shadow copy of SYSCFG registers
4551          * We *MUST* read the syscfg registers before any attempt
4552          * to clear the interrupt source registers is made.
4553          */
4554         if (retval == 0 && scsb_check_config_status(scsb)) {
4555                 cmn_err(CE_WARN,
4556                     "scsb_intr: Failed read of config/status registers");
4557                 if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) {
4558                         if (!scsb_debug) {
4559                                 goto intr_error;
4560                         }
4561                 }
4562 #ifdef DEBUG
4563                 if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4564                     scsb->scsb_i2c_errcnt > scsb_err_threshold) {
4565                         scsb_failing_event(scsb);
4566                 }
4567 #endif
4568                 /*
4569                  * Allow to go on so we clear the INTSRC bits
4570                  */
4571         }
4572 
4573         /*
4574          * Read the board healthy registers here, if any of the healthy
4575          * interrupts are set.
4576          */
4577         if (IS_SCB_P15) {
4578                 intr_idx = intr_reg = 0;
4579                 intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
4580                 index = SCSB_REG_INDEX(intr_addr);
4581                 for (i = 0; i < SCTRL_BHLTHY_NUMREGS; ++i, ++intr_idx) {
4582                         scsb->scsb_data_reg[index++] =
4583                             scb_intr_regs[intr_idx] & int_masks[intr_idx];
4584                         intr_reg |= scb_intr_regs[i];
4585                 }
4586 
4587                 if (intr_reg && scsb_read_bhealthy(scsb) != 0) {
4588                         cmn_err(CE_WARN, "%s#%d: Error Reading Healthy# "
4589                             " Registers", ddi_driver_name(scsb->scsb_dev),
4590                             ddi_get_instance(scsb->scsb_dev));
4591 #ifdef DEBUG
4592                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4593                             scsb->scsb_i2c_errcnt > scsb_err_threshold) {
4594                                 scsb_failing_event(scsb);
4595                         }
4596 #endif
4597                         goto intr_error;
4598                 }
4599         }
4600 
4601         /*
4602          * We clear the interrupt source registers now itself so that
4603          * future interrupts can be latched quickly, instead of after
4604          * finishing processing of all interrupt conditions. The global
4605          * interrupt mask however remain disabled.
4606          */
4607         if (IS_SCB_P15) {
4608                 if (scsb_rdwr_register(scsb, I2C_WR, intr_addr,
4609                     SCTRL_INTR_NUMREGS, scb_intr_regs, 1)) {
4610                         cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt"
4611                             " registers.");
4612 #ifdef DEBUG
4613                         if (scsb->scsb_state & SCSB_SSB_PRESENT &&
4614                             scsb->scsb_i2c_errcnt > scsb_err_threshold) {
4615                                 scsb_failing_event(scsb);
4616                         }
4617 #endif
4618                         goto intr_error;
4619                 }
4620         }
4621 
4622         /*
4623          * At this point, all interrupt source registers are read.
4624          * We only handle interrups which are not masked
4625          */
4626         for (i = 0; i < SCTRL_INTR_NUMREGS; ++i) {
4627                 scb_intr_regs[i] &= int_masks[i];
4628         }
4629 
4630         /*
4631          * We are here means that there was some bit set in the interrupt
4632          * source register. So we must claim the interrupt no matter
4633          * whatever error we may encounter in the course of processing.
4634          */
4635         retval |= SCSB_INTR_CLAIMED;
4636 
4637         /* store config status data */
4638         tmp_reg = SCSB_REG_ADDR(SCTRL_SYSCFG_BASE);
4639         index = SCSB_REG_INDEX(tmp_reg);
4640         for (i = 0; i < SCTRL_CFG_NUMREGS; ++i)
4641                 cstatus_regs[i] = scsb->scsb_data_reg[index + i];
4642         /*
4643          * Clear the event code,
4644          * then check to see what kind(s) of events we were interrupted for.
4645          * Check all SCTRL_INTSRC registers
4646          */
4647         scsb_event_code = 0;
4648         clr_bits = 0;
4649         intr_idx = 0;
4650         numregs = SCTRL_INTR_NUMREGS;
4651         index = SCSB_REG_INDEX(intr_addr);
4652         /*
4653          * If SCB 1.5, adjust some variables to skip the SCTRL_BHLTHY_REGS
4654          * which will be handled last in this function.
4655          */
4656         if (IS_SCB_P15) {
4657                 i = SCTRL_BHLTHY_NUMREGS;
4658                 intr_idx += i;
4659                 intr_addr += i;
4660                 index += i;
4661         }
4662         /*
4663          * For the rest of the INTSRC registers, we walk through the
4664          * scb_fru_offset[] table, matching register offsets with our offset
4665          * counter.  Then we check for the scb_fru_offset[] bit in intr_reg.
4666          * The scb_fru_offset[] index is now the SCTRL_EVENT code.
4667          * The code is then compared to type_to_code1[] entries to find the
4668          * fru_type.  The fru_type will help us recognize when to do
4669          * SLOT Hot Swap processing.
4670          *
4671          * offset_base:         the appropriate scb_fru_offset[] base index
4672          *                      for the INTPTR_BASE register group
4673          * offset:              bit offset found in INTSRC register
4674          * intr_idx:            index to temporary INTSRC register copies
4675          * intr:                modified copy of current INTR register
4676          * intr_addr:           SCB register address of current INTR register
4677          * index:               index to current INTR shadow register
4678          * idx:                 bit-number of current INTR event bit
4679          * uc:                  uchar_t from scb_fru_offset[] table,
4680          *                      containing register and FRU offsets.
4681          * j:                   used to walk fru_offset[] table, which is also
4682          *                      the bit-number of the current event code
4683          * code:                manufactured event code for current INT event
4684          */
4685         offset_base = FRU_OFFSET_BASE(SCTRL_INTPTR_BASE);
4686         for (offset = 0; intr_idx < numregs;
4687             ++offset, ++intr_idx, ++intr_addr, ++index) {
4688                 scsb->scsb_data_reg[index] = scb_intr_regs[intr_idx];
4689                 intr_reg = scb_intr_regs[intr_idx];
4690                 while (intr_reg) {      /* for each INTSRC bit that's set */
4691                         int             j;
4692                         uint16_t        ui;
4693                         uchar_t         uc;
4694                         idx = event_to_index((uint32_t)intr_reg); /* offset */
4695                         code = (1 << idx);                /* back to bit mask */
4696                         clr_bits |= code;
4697                         intr_reg = intr_reg & ~code;        /* clear this one   */
4698                         for (j = 0; j < MCT_MAX_FRUS; ++j) {
4699                                 /*
4700                                  * Get register offset from table and check
4701                                  * for a match with our loop offset counter.
4702                                  * Then check for intr_reg bit-offset match
4703                                  * with bit-offset from table entry.
4704                                  */
4705                                 uc = scb_fru_offset[offset_base + j];
4706                                 if (offset != ((uc >> 4) & 0xf)) {
4707                                         if (IS_SCB_P10)
4708                                                 continue;
4709                                         if (j != FRU_INDEX(SCTRL_EVENT_SCB))
4710                                                 continue;
4711                                         if (offset != ((uc >> 4) & 0xf)
4712                                             + SCB_INT_OFFSET)
4713                                                 continue;
4714                                 }
4715                                 if (idx == (uc & 0xf))
4716                                         break;
4717                         }
4718                         if (uc == 0xff) {
4719                                 /*
4720                                  * bit idx not recognized, check another.
4721                                  */
4722                                 continue;
4723                         }
4724                         /*
4725                          * We found the fru_offset[] entry, now use the index
4726                          * to get the event code.
4727                          */
4728                         code = (uint32_t)(1 << j);
4729                         if (scsb_debug & 0x00002000) {
4730                                 cmn_err(CE_NOTE, "scsb_intr: code=0x%x", code);
4731                         }
4732                         /*
4733                          * Now check for the NON-FRU type events.
4734                          */
4735                         if (code ==  SCTRL_EVENT_PWRDWN) {
4736                                 if (scsb_debug & 0x1002) {
4737                                         cmn_err(CE_NOTE,
4738                                             "scsb_intr(%d): power down req."
4739                                             " INT.", scsb->scsb_instance);
4740                                 }
4741                                 scsb_event_code |= code;
4742                                 if (scsb->scsb_state & SCSB_OPEN &&
4743                                     scsb->scsb_rq != (queue_t *)NULL) {
4744                                         /*
4745                                          * inform applications using poll(2)
4746                                          * about this event, and provide the
4747                                          * event code to EnvMon scsb policy
4748                                          */
4749                                         if (!(scsb_debug & 0x00040000))
4750                                         (void) scsb_queue_put(scsb->scsb_rq, 1,
4751                                             &scsb_event_code, "scsb_intr");
4752                                         goto intr_error;
4753                                 }
4754                                 continue;
4755                         } else if (code == SCTRL_EVENT_REPLACE) {
4756                                 if (scsb_debug & 0x1002) {
4757                                         cmn_err(CE_NOTE,
4758                                             "scsb_intr(%d): replacement "
4759                                             "req. INT.",
4760                                             scsb->scsb_instance);
4761                                 }
4762                                 scsb_freeze_check(scsb);
4763                                 scsb_freeze(scsb);
4764                                 scsb_event_code |= code;
4765                                 retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4766                                 continue;
4767                         } else if (code == SCTRL_EVENT_SCB) {
4768                                 int     tmp;
4769                                 /*
4770                                  * Must be newly inserted SCB
4771                                  * Time to re-initialize.
4772                                  */
4773                                 if (scsb_debug & 0x1002) {
4774                                         cmn_err(CE_NOTE,
4775                                             "scsb_intr(%d): INIT SCB INTR",
4776                                             scsb->scsb_instance);
4777                                 }
4778                                 /*
4779                                  * SCB initialization already handled, but we
4780                                  * set the event code bit here in order to
4781                                  * report the event to interested utilities.
4782                                  *
4783                                  * scsb_restore(scsb);
4784                                  * The INTSRC bit is already cleared,
4785                                  * so we won't do it again.
4786                                  */
4787                                 tmp = FRU_OFFSET(SCTRL_EVENT_SCB,
4788                                     SCTRL_INTPTR_BASE);
4789                                 clr_bits &= ~(1 << tmp);
4790                                 scsb_event_code |= code;
4791                                 retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4792                                 continue;
4793                         } else if (code == SCTRL_EVENT_ALARM_INT) {
4794                                 /*
4795                                  * P0.6/P1.0: SCTRL_INTR_ALARM_INT is always
4796                                  * set and cannot be cleared, so ignore it.
4797                                  */
4798                                 if (!IS_SCB_P15) {
4799                                         continue;
4800                                 }
4801                                 if (scsb_debug & 0x1002) {
4802                                         cmn_err(CE_NOTE,
4803                                             "scsb_intr(%d): Alarm INT.",
4804                                             scsb->scsb_instance);
4805                                 }
4806                                 scsb_event_code |= code;
4807                                 retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
4808                                 /*
4809                                  * XXX:
4810                                  * Must service the Alarm INT by clearing INT
4811                                  * condition on Alarm Card,
4812                                  * then clear the SCTRL_INTR_ALARM_INT bit here.
4813                                  * Waiting for specs and test environment.
4814                                  */
4815                                 continue;
4816                         } else if ((ui = event_to_type(code)) == 0xffff) {
4817                                 /*
4818                                  * FRU type not found
4819                                  */
4820                                 break;
4821                         }
4822                         /*
4823                          * Check for special processing
4824                          * now that we found the FRU type.
4825                          */
4826                         fru_type = (scsb_utype_t)(ui & 0xff);
4827                         unit = (ui >> 8) & 0xff;
4828                         if (scsb_debug & 0x00002000) {
4829                                 cmn_err(CE_NOTE, "scsb_intr: "
4830                                     "FRU type/unit/code %d/%d/0x%x",
4831                                     fru_type, unit, code);
4832                         }
4833                         switch (fru_type) {
4834                         case PDU:
4835                                 break;
4836                         case PS:
4837                                 break;
4838                         case DISK:
4839                                 break;
4840                         case FAN:
4841                                 break;
4842                         case SSB:
4843                                 /*
4844                                  * in check_fru_info() below, we see if the
4845                                  * SSB has been removed, then check for
4846                                  * occupied slots in reset to see if we should
4847                                  * WARN agains SCB removal
4848                                  */
4849                                 break;
4850                         case CFTM:
4851                                 break;
4852                         case CRTM:
4853                                 break;
4854                         case PRTM:
4855                                 break;
4856                         case SLOT:
4857                                 slotnum = tonga_ssl_to_psl(scsb, unit);
4858                                 if (scsb_debug & 0x00002000) {
4859                                         cmn_err(CE_NOTE, "scsb_intr: "
4860                                             "unit/slot %d/%d",
4861                                             unit, slotnum);
4862                                 }
4863 
4864                                 /*
4865                                  * If the slot number is not valid, continue.
4866                                  */
4867                                 if (scsb->scsb_state & SCSB_IS_TONGA) {
4868                                         if (slotnum > TG_MAX_SLOTS ||
4869                                             slotnum == SC_TG_CPU_SLOT) {
4870                                                 continue;
4871                                         }
4872                                         /*
4873                                          * For a tonga, we need to return
4874                                          * the code corresponding to the
4875                                          * actual physical slot
4876                                          */
4877                                         code = FRU_UNIT_TO_EVCODE(SLOT,
4878                                             slotnum);
4879                                 } else {
4880                                         if (slotnum > MC_MAX_SLOTS ||
4881                                             slotnum == SC_MC_CPU_SLOT ||
4882                                             (scsb->scsb_hsc_state &
4883                                             SCSB_HSC_CTC_PRES &&
4884                                             slotnum == SC_MC_CTC_SLOT)) {
4885                                                 continue;
4886                                         }
4887                                 }
4888                         /* FALLTHROUGH */
4889                         case ALARM:
4890                 /*
4891                  * INDENT CHEATING, 2 indentations
4892                  */
4893                 ac_present = 0;
4894                 /*
4895                  * If it is an Alarm Card Interrupt, we just do some sanity
4896                  * checks and then wait for the slot interrupt to take
4897                  * connect or disconnect action.
4898                  * XXX - Is there a gaurantee that ALARM int will occur first ?
4899                  */
4900                 if (fru_type == ALARM) {
4901                         DEBUG2("AC Intr %d(%d)\n", scsb->ac_slotnum, idx+1);
4902                         val = scsb_fru_op(scsb, SLOT,
4903                             tonga_ssl_to_psl(scsb, scsb->ac_slotnum),
4904                             SCTRL_SYSCFG_BASE, SCSB_FRU_OP_GET_BITVAL);
4905                         ac_present = scsb_fru_op(scsb, ALARM, 1,
4906                             SCTRL_SYSCFG_BASE,
4907                             SCSB_FRU_OP_GET_BITVAL);
4908                         /*
4909                          * It is observed that slot presence and Alarm
4910                          * presence bits do not go ON at the same time.
4911                          * Hence we wait till both events happen.
4912                          */
4913 #ifdef DEBUG
4914                         if ((((val) && (!ac_present)) ||
4915                             ((!val) && (ac_present))) &&
4916                             (scsb->scsb_hsc_state &
4917                             SCSB_AC_SLOT_INTR_DONE))
4918 
4919                                 cmn_err(CE_WARN, "?Alarm and Slot presence "
4920                                     "state bits do not match! (%x,%x)",
4921                                     val, ac_present);
4922 #endif
4923                         if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE)
4924                                 scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE;
4925                         else
4926                                 scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE;
4927                         break;  /* we break and wait for slot interrupt. */
4928                 }
4929 
4930                 /*
4931                  * cPCI slot interrupt event
4932                  */
4933                 if (scsb->scsb_state & SCSB_IS_TONGA) {
4934                         if (slotnum > TG_MAX_SLOTS ||
4935                             slotnum == SC_TG_CPU_SLOT) {
4936                                 continue;
4937                         }
4938                 } else {
4939                         if (slotnum > MC_MAX_SLOTS ||
4940                             slotnum == SC_MC_CPU_SLOT ||
4941                             (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
4942                             slotnum == SC_MC_CTC_SLOT)) {
4943                                 continue;
4944                         }
4945                 }
4946                 if (scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) {
4947                         DEBUG2("AC slot Intr %d(%d)\n", slotnum, idx+1);
4948                         ac_slot = B_TRUE;
4949                 }
4950                 val = scsb_fru_op(scsb, SLOT, unit, SCTRL_SYSCFG_BASE,
4951                     SCSB_FRU_OP_GET_BITVAL);
4952                 if (ac_slot == B_TRUE) {
4953                         ac_present = scsb_fru_op(scsb, ALARM, 1,
4954                             SCTRL_SYSCFG_BASE,
4955                             SCSB_FRU_OP_GET_BITVAL);
4956 #ifdef DEBUG
4957                         if ((((val) && (!ac_present)) ||
4958                             ((!val) && (ac_present))) &&
4959                             (scsb->scsb_hsc_state &
4960                             SCSB_AC_SLOT_INTR_DONE)) {
4961 
4962                                 cmn_err(CE_WARN, "?Alarm and Slot presence "
4963                                     "state bits do not match! (%x,%x)",
4964                                     val, ac_present);
4965                         }
4966 #endif
4967                         if (scsb->scsb_hsc_state & SCSB_AC_SLOT_INTR_DONE)
4968                                 scsb->scsb_hsc_state &= ~SCSB_AC_SLOT_INTR_DONE;
4969                         else
4970                                 scsb->scsb_hsc_state |= SCSB_AC_SLOT_INTR_DONE;
4971                 }
4972                 if (val) {
4973                         if (ac_present) {
4974                                 DEBUG1("AC insertion on slot %d!\n", slotnum);
4975                                 if (scsb_debug & 0x00010000) {
4976                                         cmn_err(CE_NOTE, "scsb_intr: "
4977                                         "AC_PRES slot %d", slotnum);
4978                                 }
4979                                 scsb->scsb_hsc_state |= SCSB_ALARM_CARD_PRES;
4980                         }
4981 #ifndef lint
4982                         else
4983                                 DEBUG1("IO Insertion on slot %d!\n", slotnum);
4984 #endif
4985                         /*
4986                          * Special case : check MPID type.
4987                          * If MC midplane type,
4988                          * check to make sure the Alarm Card present
4989                          * bit is ON. If not, this is a regular IO card.
4990                          */
4991                         (void) scsb_connect_slot(scsb, slotnum, B_FALSE);
4992                 } else {
4993                         if ((ac_slot == B_TRUE) &&
4994                             (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) {
4995 
4996                                 DEBUG1("AC Removal on slot %d!\n", slotnum);
4997 #ifdef DEBUG
4998                                 if (scsb_debug & 0x00010000) {
4999                                         cmn_err(CE_NOTE, "scsb_intr: "
5000                                             "!AC_PRES slot %d",
5001                                             slotnum);
5002                                 }
5003 #endif /* DEBUG */
5004                                 scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_PRES;
5005                         }
5006 #ifndef lint
5007                         else
5008                                 DEBUG1("IO Removal on slot %d!\n", slotnum);
5009 #endif
5010                         (void) scsb_disconnect_slot(scsb, B_FALSE, slotnum);
5011                 }
5012                 /*
5013                  * END INDENT CHEATING, 2 indentations
5014                  */
5015 
5016                                 break;
5017                         default:
5018                                 /*
5019                                  * ERROR: Did not find cause of INTSRC bit
5020                                  */
5021                                 if (scsb_debug & 0x00000002) {
5022                                         cmn_err(CE_WARN,
5023                                             "scsb_intr: FRU type %d"
5024                                             " not recognized", fru_type);
5025                                 }
5026                                 continue;
5027                         }
5028                         scsb_event_code |= code;
5029                         retval |= (SCSB_INTR_CLAIMED | SCSB_INTR_EVENT);
5030                         if (fru_type == SLOT)
5031                                 continue;
5032                         error = 0;
5033                         fru_ptr = mct_system_info.fru_info_list[fru_type];
5034                         for (; fru_ptr != NULL; fru_ptr = fru_ptr->next) {
5035                                 if (unit != fru_ptr->fru_unit)
5036                                         continue;
5037                                 if (fru_ptr->i2c_info == NULL ||
5038                                     (tmp_reg = fru_ptr->i2c_info->
5039                                     ledata_reg) == 0)
5040                                         continue;
5041                                 error = scsb_set_scfg_pres_leds(scsb, fru_ptr);
5042                                 if (error) {
5043                                         cmn_err(CE_WARN, "scsb_intr(): "
5044                                             "I2C write error to 0x%x",
5045                                             tmp_reg);
5046                                         if (!(scsb->scsb_state &
5047                                             SCSB_DEBUG_MODE)) {
5048                                                 goto intr_error;
5049                                         }
5050                                 }
5051                                 break;
5052                         }
5053                 }
5054                 if (clr_bits) {
5055                         clr_bits = 0;
5056                 }
5057         }
5058         /*
5059          * Check for SCB 1.5 interrupt for SLOT HEALTHY changes
5060          */
5061         clr_bits = 0;
5062         intr_idx = 0;
5063         numregs = SCTRL_INTR_NUMREGS;
5064         intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
5065         index = SCSB_REG_INDEX(intr_addr);
5066         if (IS_SCB_P15) {
5067                 for (i = 0; i < SCTRL_BHLTHY_NUMREGS;
5068                     ++i, ++intr_idx, ++intr_addr) {
5069                         scsb->scsb_data_reg[index++] = scb_intr_regs[intr_idx];
5070                         intr_reg = scb_intr_regs[i];
5071                         while (intr_reg) {
5072                                 idx = event_to_index((uint32_t)intr_reg);
5073                                 code = (1 << idx);
5074                                 clr_bits |= code;
5075                                 intr_reg = intr_reg & ~code;
5076                                 /* idx + 1 because bit 0 is for Slot 1 */
5077                                 slotnum = tonga_ssl_to_psl(scsb, idx + 1);
5078                                 if (scsb->scsb_state & SCSB_IS_TONGA) {
5079                                         if (slotnum > TG_MAX_SLOTS ||
5080                                             slotnum == SC_TG_CPU_SLOT) {
5081                                                 continue;
5082                                         }
5083                                 } else {
5084                                         if (slotnum > MC_MAX_SLOTS ||
5085                                             slotnum == SC_MC_CPU_SLOT ||
5086                                             (scsb->scsb_hsc_state &
5087                                             SCSB_HSC_CTC_PRES &&
5088                                             slotnum == SC_MC_CTC_SLOT)) {
5089                                                 continue;
5090                                         }
5091                                 }
5092                                 scsb_healthy_intr(scsb, slotnum);
5093                         }
5094                         if (clr_bits) {
5095                                 clr_bits = 0;
5096                         }
5097                 }
5098         }
5099         code = scsb_event_code;
5100         if (retval & SCSB_INTR_EVENT &&
5101             !(scsb->scsb_state & SCSB_P06_NOINT_KLUGE)) {
5102                 check_fru_info(scsb, code);
5103                 add_event_code(scsb, code);
5104                 (void) scsb_queue_ops(scsb, QPUT_INT32, 1, &scsb_event_code,
5105                 "scsb_intr");
5106         }
5107 intr_error:
5108         scb_post_e = gethrtime();
5109 
5110         if (scsb_debug & 0x8000000)
5111                 cmn_err(CE_NOTE, "Summary of times in nsec: pre_time %llu, \
5112                         post_time %llu", scb_pre_e - scb_pre_s,
5113                     scb_post_e - scb_post_s);
5114 
5115 
5116         mutex_enter(&scsb->scsb_mutex);
5117         scsb_in_postintr = 0;
5118         cv_broadcast(&scsb->scsb_cv);
5119         mutex_exit(&scsb->scsb_mutex);
5120 
5121         /*
5122          * Re-enable interrupt now.
5123          */
5124         (void) scsb_toggle_psmint(scsb, 1);
5125         scsb->scsb_state &= ~SCSB_IN_INTR;
5126 }
5127 
5128 static int
5129 scsb_polled_int(scsb_state_t *scsb, int cmd, uint32_t *set)
5130 {
5131         if (scsb_debug & 0x4000)
5132                 cmn_err(CE_NOTE, "scsb_polled_int(scsb,0x%x)", cmd);
5133         *set = 0;
5134         if (cmd == SCSBIOC_SHUTDOWN_POLL) {
5135                 return (EINVAL);
5136         }
5137         if (cmd != SCSBIOC_INTEVENT_POLL) {
5138                 return (EINVAL);
5139         }
5140         if (scsb->scsb_state & SCSB_P06_NOINT_KLUGE) {
5141                 /*
5142                  * scsb_intr() may modify scsb_event_code
5143                  */
5144                 scsb_event_code = SCTRL_EVENT_NONE;
5145                 (void) scsb_intr((caddr_t)scsb);
5146                 *set = scsb_event_code;
5147                 scsb_event_code = 0;
5148         } else {
5149                 /*
5150                  * SCSB_P06_INTR_ON, we know there was an event
5151                  * and we're retrieving the event code from the event FIFO.
5152                  */
5153                 *set = get_event_code();
5154         }
5155         if (scsb_debug & 0x01004000) {
5156                 cmn_err(CE_NOTE, "scsb_polled_int: event_code = 0x%x", *set);
5157         }
5158         return (0);
5159 }
5160 
5161 static int
5162 scsb_leds_switch(scsb_state_t *scsb, scsb_ustate_t op)
5163 {
5164         register int    i;
5165         int             index;
5166         uchar_t         reg, idata, rwbuf[SCTRL_MAX_GROUP_NUMREGS];
5167 
5168         if (scsb->scsb_state & SCSB_FROZEN &&
5169             !(scsb->scsb_state & SCSB_IN_INTR)) {
5170                 return (EAGAIN);
5171         }
5172         if (scsb_debug & 0x0101) {
5173                 cmn_err(CE_NOTE, "scsb_leds_switch(%s):",
5174                     op == ON ? "ON" : "OFF");
5175         }
5176         /* Step 1: turn ON/OFF all NOK LEDs. */
5177         if (scsb_debug & 0x0100) {
5178                 cmn_err(CE_NOTE, "scsb%d: turning all NOK LEDs %s",
5179                     scsb->scsb_instance,
5180                     op == ON ? "ON" : "OFF");
5181         }
5182         if (op == ON)
5183                 idata = 0xff;
5184         else    /* off */
5185                 idata = 0x00;
5186         reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE);
5187         index = SCSB_REG_INDEX(reg);
5188         for (i = 0; i < SCTRL_LED_NOK_NUMREGS;  ++i) {
5189                 rwbuf[i] = idata;
5190                 scsb->scsb_data_reg[index + i] = idata;
5191         }
5192         mutex_enter(&scsb->scsb_mutex);
5193         i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_NOK_NUMREGS,
5194             rwbuf, 1);
5195         mutex_exit(&scsb->scsb_mutex);
5196         if (i) {
5197                 if (scsb_debug & 0x0102)
5198                         cmn_err(CE_WARN, "scsb_leds_switch(): "
5199                             "Failed to turn %s NOK LEDs",
5200                             op == ON ? "ON" : "OFF");
5201         }
5202         /* Step 2: turn ON/OFF all OK LEDs. */
5203         if (scsb_debug & 0x0100) {
5204                 cmn_err(CE_NOTE, "scsb%d: turning all OK LEDs %s",
5205                     scsb->scsb_instance,
5206                     op == ON ? "ON" : "OFF");
5207         }
5208         reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
5209         index = SCSB_REG_INDEX(reg);
5210         for (i = 0; i < SCTRL_LED_OK_NUMREGS;  ++i) {
5211                 rwbuf[i] = idata;
5212                 scsb->scsb_data_reg[index + i] = idata;
5213         }
5214         mutex_enter(&scsb->scsb_mutex);
5215         i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_LED_OK_NUMREGS,
5216             rwbuf, 1);
5217         mutex_exit(&scsb->scsb_mutex);
5218         if (i) {
5219                 if (scsb_debug & 0x0102)
5220                         cmn_err(CE_WARN, "scsb_leds_switch(): "
5221                             "Failed to turn %s NOK LEDs",
5222                             op == ON ? "ON" : "OFF");
5223         }
5224         /* Step 3: turn OFF all BLINK LEDs. */
5225         if (op == OFF) {
5226                 reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
5227                 index = SCSB_REG_INDEX(reg);
5228                 for (i = 0; i < SCTRL_BLINK_NUMREGS;  ++i) {
5229                         rwbuf[i] = idata;
5230                         scsb->scsb_data_reg[index + i] = idata;
5231                 }
5232                 mutex_enter(&scsb->scsb_mutex);
5233                 i = scsb_rdwr_register(scsb, I2C_WR, reg, SCTRL_BLINK_NUMREGS,
5234                     rwbuf, 1);
5235                 mutex_exit(&scsb->scsb_mutex);
5236                 if (i) {
5237                         if (scsb_debug & 0x0102)
5238                                 cmn_err(CE_WARN, "scsb_leds_switch(): "
5239                                     "Failed to turn %s BLINK BITs",
5240                                     op == ON ? "ON" : "OFF");
5241                 }
5242         }
5243         return (0);
5244 }
5245 
5246 static int
5247 scsb_readall_regs(scsb_state_t *scsb)
5248 {
5249         int             error;
5250         int             index;
5251         uchar_t         reg;
5252 
5253         if (!(scsb_debug & 0x40000000))
5254                 return (0);
5255         if (scsb_debug & 0x0005) {
5256                 cmn_err(CE_NOTE, "scsb_readall_regs:");
5257         }
5258         if (scsb->scsb_state & SCSB_FROZEN) {
5259                 return (EAGAIN);
5260         }
5261         reg = SCSB_REG_ADDR_START;      /* 1st register in set */
5262         index = SCSB_REG_INDEX(reg);
5263         error = scsb_rdwr_register(scsb, I2C_WR_RD, reg, SCSB_DATA_REGISTERS,
5264             &scsb->scsb_data_reg[index], 1);
5265         return (error);
5266 }
5267 
5268 
5269 /*
5270  * read 1-byte register, mask with read bits (rmask),
5271  * turn ON bits in on_mask, turn OFF bits in off_mask
5272  * write the byte back to register
5273  * NOTE: MUST be called with mutex held
5274  */
5275 static int
5276 scsb_write_mask(scsb_state_t *scsb,
5277                 uchar_t reg,
5278                 uchar_t rmask,
5279                 uchar_t on_mask,
5280                 uchar_t off_mask)
5281 {
5282         i2c_transfer_t  *i2cxferp;
5283         int             index, error = 0;
5284         uchar_t         reg_data;
5285 
5286         if (scsb_debug & 0x0800) {
5287                 cmn_err(CE_NOTE, "scsb_write_mask(,%x,,%x,%x):",
5288                     reg, on_mask, off_mask);
5289         }
5290         if (scsb->scsb_state & SCSB_FROZEN &&
5291             !(scsb->scsb_state & SCSB_IN_INTR)) {
5292                 return (EAGAIN);
5293         }
5294         /* select the register address and read the register */
5295         i2cxferp = (i2c_transfer_t *)scsb->scsb_i2ctp;
5296         i2cxferp->i2c_flags = I2C_WR_RD;
5297         i2cxferp->i2c_wlen = 1;
5298         i2cxferp->i2c_rlen = 1;
5299         i2cxferp->i2c_wbuf[0] = reg;
5300         i2cxferp->i2c_rbuf[0] = 0;
5301         scsb->scsb_kstat_flag = B_TRUE;      /* we did a i2c transaction */
5302         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
5303                 error = EIO;
5304                 goto wm_error;
5305         }
5306         scsb->scsb_i2c_errcnt = 0;
5307         if (scsb_debug & 0x0800)
5308                 cmn_err(CE_NOTE, "scsb_write_mask() read 0x%x",
5309                     i2cxferp->i2c_rbuf[0]);
5310         reg_data = i2cxferp->i2c_rbuf[0];
5311         if (rmask)
5312                 reg_data &= rmask;
5313         if (off_mask)
5314                 reg_data &= ~off_mask;
5315         if (on_mask)
5316                 reg_data |= on_mask;
5317         i2cxferp->i2c_flags = I2C_WR;
5318         i2cxferp->i2c_wlen = 2;
5319         i2cxferp->i2c_wbuf[0] = reg;
5320         i2cxferp->i2c_wbuf[1] = reg_data;
5321         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
5322                 error = EIO;
5323                 goto wm_error;
5324         }
5325         /* keep shadow registers updated */
5326         index = SCSB_REG_INDEX(reg);
5327         scsb->scsb_data_reg[index] = reg_data;
5328         if (scsb_debug & 0x0800)
5329                 cmn_err(CE_NOTE, "scsb_write_mask() wrote 0x%x", reg_data);
5330         scsb->scsb_i2c_errcnt = 0;
5331         return (error);
5332 wm_error:
5333         scsb->scsb_i2c_errcnt++;
5334         if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
5335                 scsb->scsb_err_flag = B_TRUE; /* latch error */
5336         if (scsb->scsb_state & SCSB_SSB_PRESENT) {
5337                 if (scsb_debug & 0x0802)
5338                         cmn_err(CE_WARN,
5339                             "scsb_write_mask(): reg %x %s error, data=%x",
5340                             reg,
5341                             i2cxferp->i2c_flags & I2C_WR ? "write" : "read",
5342                             i2cxferp->i2c_flags & I2C_WR ?
5343                             i2cxferp->i2c_wbuf[1] : i2cxferp->i2c_rbuf[0]);
5344         } else {
5345                 if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
5346                         scsb_freeze(scsb);
5347                 return (EAGAIN);
5348         }
5349         return (error);
5350 }
5351 
5352 /*
5353  * read/write len consecutive single byte registers to/from rbuf
5354  * NOTE: should be called with mutex held
5355  */
5356 static int
5357 scsb_rdwr_register(scsb_state_t *scsb, int op, uchar_t reg, int len,
5358                                 uchar_t *rwbuf, int i2c_alloc)
5359 {
5360         i2c_transfer_t  *i2cxferp;
5361         int             i, rlen, wlen, index, error = 0;
5362 
5363         if (scsb_debug & 0x0800) {
5364                 cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):",
5365                     (op == I2C_WR) ? "write" : "read",  reg, len);
5366         }
5367         if (scsb->scsb_state & SCSB_FROZEN &&
5368             !(scsb->scsb_state & SCSB_IN_INTR)) {
5369                 return (EAGAIN);
5370         }
5371         if (i2c_alloc) {
5372                 i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP);
5373                 if (i2cxferp == NULL) {
5374                         if (scsb_debug & 0x0042)
5375                                 cmn_err(CE_WARN, "scsb_rdwr_register: "
5376                                     "i2ctx allocation failure");
5377                         return (ENOMEM);
5378                 }
5379         } else {
5380                 i2cxferp = scsb->scsb_i2ctp;
5381         }
5382         index = SCSB_REG_INDEX(reg);
5383         switch (op) {
5384         case I2C_WR:
5385                 wlen = len + 1; /* add the address */
5386                 rlen = 0;
5387                 i2cxferp->i2c_wbuf[0] = reg;
5388                 for (i = 0; i < len; ++i) {
5389                         scsb->scsb_data_reg[index + i] =
5390                             i2cxferp->i2c_wbuf[1 + i] = rwbuf[i];
5391                         if (scsb_debug & 0x0080)
5392                                 cmn_err(CE_NOTE,
5393                                 "scsb_rdwr_register: writing rwbuf[%d]=0x%x",
5394                                     i, rwbuf[i]);
5395                 }
5396                 break;
5397         case I2C_WR_RD:
5398                 wlen = 1;       /* for the address */
5399                 rlen = len;
5400                 i2cxferp->i2c_wbuf[0] = reg;
5401                 break;
5402         default:
5403                 if (i2c_alloc)
5404                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
5405                 return (EINVAL);
5406         }
5407         /* select the register address */
5408         i2cxferp->i2c_flags = op;
5409         i2cxferp->i2c_rlen = rlen;
5410         i2cxferp->i2c_wlen = wlen;
5411         i2cxferp->i2c_wbuf[0] = reg;
5412         scsb->scsb_kstat_flag = B_TRUE;      /* we did a i2c transaction */
5413         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
5414                 error = EIO;
5415         } else if (rlen) {
5416                 /* copy to rwbuf[] and keep shadow registers updated */
5417                 for (i = 0; i < len; ++i) {
5418                         scsb->scsb_data_reg[index + i] = rwbuf[i] =
5419                             i2cxferp->i2c_rbuf[i];
5420                         if (scsb_debug & 0x0080)
5421                                 cmn_err(CE_NOTE,
5422                                 "scsb_rdwr_register: read rwbuf[%d]=0x%x",
5423                                     i, rwbuf[i]);
5424                 }
5425         }
5426         if (i2c_alloc)
5427                 scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
5428         if (error) {
5429                 scsb->scsb_i2c_errcnt++;
5430                 if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
5431                         scsb->scsb_err_flag = B_TRUE; /* latch error */
5432                 if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
5433                         if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
5434                                 scsb_freeze(scsb);
5435                         return (EAGAIN);
5436                 } else {
5437                         cmn_err(CE_WARN,
5438                             "scsb_rdwr_register(): I2C read error from %x",
5439                             reg);
5440                 }
5441         } else {
5442                 scsb->scsb_i2c_errcnt = 0;
5443         }
5444 
5445         return (error);
5446 }
5447 
5448 /*
5449  * Called from scsb_intr()
5450  * First find the fru_info for this fru_id, and set fru_status for callback.
5451  * Then check for a registered call_back entry for this fru_id,
5452  * and if found, call it.
5453  * Recursize call until no EVENTS left in evcode.
5454  */
5455 static  void
5456 check_fru_info(scsb_state_t *scsb, int evcode)
5457 {
5458         struct scsb_cb_entry    *cbe_ptr;
5459         fru_info_t              *fru_ptr;
5460         fru_id_t                fru_id;
5461         scsb_fru_status_t       fru_status;
5462         int                     i, new_evcode;
5463 
5464         if (scsb_debug & 0x00100001)
5465                 cmn_err(CE_NOTE, "check_fru_info(scsb,0x%x)", evcode);
5466         if (evcode == 0)
5467                 return;
5468         i = event_to_index((uint32_t)evcode);
5469         new_evcode = evcode & ~(1 << i);
5470         if (i > MCT_MAX_FRUS) {
5471                 if (scsb_debug & 0x00100000)
5472                         cmn_err(CE_NOTE,
5473                             "check_fru_info: index %d out of range", i);
5474                 check_fru_info(scsb, new_evcode);
5475                 return;
5476         }
5477         fru_id = fru_id_table[i];
5478         fru_ptr = find_fru_info(fru_id);
5479         if (fru_ptr == (fru_info_t *)NULL) {
5480                 check_fru_info(scsb, new_evcode);
5481                 return;
5482         }
5483         update_fru_info(scsb, fru_ptr);
5484         if (fru_ptr->fru_status & FRU_PRESENT) {
5485                 fru_status = FRU_PRESENT;
5486         } else {
5487                 fru_status = FRU_NOT_PRESENT;
5488                 if (fru_ptr->fru_type == SSB) {
5489                         /*
5490                          * WARN against SCB removal if any
5491                          * occupied slots are in reset
5492                          */
5493                         scsb_freeze_check(scsb);
5494                 }
5495         }
5496         /*
5497          * check for an entry in the CallBack table
5498          */
5499         for (cbe_ptr = scsb_cb_table; cbe_ptr != NULL;
5500             cbe_ptr = cbe_ptr->cb_next) {
5501                 if (cbe_ptr->cb_fru_id == fru_id &&
5502                     cbe_ptr->cb_fru_ptr == fru_ptr) {
5503                         if (scsb_debug & 0x00800000)
5504                                 cmn_err(CE_NOTE,
5505                                     "check_fru_info: callback for FRU_ID "
5506                                     "0x%x; device is %spresent",
5507                                     (int)fru_id,
5508                                     fru_status == FRU_PRESENT ?
5509                                     "" : "not ");
5510                         (*cbe_ptr->cb_func)(
5511                             cbe_ptr->cb_softstate_ptr,
5512                             cbe_ptr->cb_event,
5513                             fru_status);
5514                         break;
5515                 }
5516         }
5517         check_fru_info(scsb, new_evcode);
5518 }
5519 
5520 /*
5521  * -----------------------------
5522  * scsb kstat support functions.
5523  * -----------------------------
5524  */
5525 /*
5526  * Create and initialize the kstat data structures
5527  */
5528 static int
5529 scsb_alloc_kstats(scsb_state_t *scsb)
5530 {
5531         kstat_named_t   *kn;
5532         /*
5533          * scsb_ks_leddata_t for "scsb_leddata"
5534          */
5535         if (scsb_debug & 0x00080001)
5536                 cmn_err(CE_NOTE,
5537                     "scsb_alloc_kstats: create scsb_leddata: %lu bytes",
5538                     sizeof (scsb_ks_leddata_t));
5539         if ((scsb->ks_leddata = kstat_create(scsb_name, scsb->scsb_instance,
5540             SCSB_KS_LEDDATA, "misc", KSTAT_TYPE_RAW,
5541             sizeof (scsb_ks_leddata_t), KSTAT_FLAG_PERSISTENT))
5542             == NULL) {
5543                 scsb->scsb_state |= SCSB_KSTATS;
5544                 scsb_free_kstats(scsb);
5545                 return (DDI_FAILURE);
5546         }
5547         scsb->ks_leddata->ks_update = update_ks_leddata;
5548         scsb->ks_leddata->ks_private = (void *)scsb;
5549         if (update_ks_leddata(scsb->ks_leddata, KSTAT_READ) != DDI_SUCCESS) {
5550                 scsb->scsb_state |= SCSB_KSTATS;
5551                 scsb_free_kstats(scsb);
5552                 return (DDI_FAILURE);
5553         }
5554         kstat_install(scsb->ks_leddata);
5555         /*
5556          * scsb_ks_state_t for "scsb_state"
5557          */
5558         if (scsb_debug & 0x00080000)
5559                 cmn_err(CE_NOTE,
5560                     "scsb_alloc_kstats: create scsb_state: %lu bytes",
5561                     sizeof (scsb_ks_state_t));
5562         if ((scsb->ks_state = kstat_create(scsb_name, scsb->scsb_instance,
5563             SCSB_KS_STATE, "misc", KSTAT_TYPE_RAW,
5564             sizeof (scsb_ks_state_t), KSTAT_FLAG_PERSISTENT))
5565             == NULL) {
5566                 scsb->scsb_state |= SCSB_KSTATS;
5567                 scsb_free_kstats(scsb);
5568                 return (DDI_FAILURE);
5569         }
5570         scsb->ks_state->ks_update = update_ks_state;
5571         scsb->ks_state->ks_private = (void *)scsb;
5572         if (update_ks_state(scsb->ks_state, KSTAT_READ) != DDI_SUCCESS) {
5573                 scsb->scsb_state |= SCSB_KSTATS;
5574                 scsb_free_kstats(scsb);
5575                 return (DDI_FAILURE);
5576         }
5577         kstat_install(scsb->ks_state);
5578         /*
5579          * mct_topology_t for "env_topology"
5580          */
5581         if (scsb_debug & 0x00080000)
5582                 cmn_err(CE_NOTE,
5583                     "scsb_alloc_kstats: create env_toploogy: %lu bytes",
5584                     sizeof (mct_topology_t));
5585         if ((scsb->ks_topology = kstat_create(scsb_name, scsb->scsb_instance,
5586             SCSB_KS_TOPOLOGY, "misc", KSTAT_TYPE_RAW,
5587             sizeof (mct_topology_t), KSTAT_FLAG_PERSISTENT))
5588             == NULL) {
5589                 scsb->scsb_state |= SCSB_KSTATS;
5590                 scsb_free_kstats(scsb);
5591                 return (DDI_FAILURE);
5592         }
5593         scsb->ks_topology->ks_update = update_ks_topology;
5594         scsb->ks_topology->ks_private = (void *)scsb;
5595         if (update_ks_topology(scsb->ks_topology, KSTAT_READ) != DDI_SUCCESS) {
5596                 scsb->scsb_state |= SCSB_KSTATS;
5597                 scsb_free_kstats(scsb);
5598                 return (DDI_FAILURE);
5599         }
5600         kstat_install(scsb->ks_topology);
5601         /*
5602          * kstat_named_t * 2 for "scsb_evc_register"
5603          */
5604         if (scsb_debug & 0x00080001)
5605                 cmn_err(CE_NOTE,
5606                     "scsb_alloc_kstats: create scsb_evc_register: %lu bytes",
5607                     sizeof (kstat_named_t) * 2);
5608         if ((scsb->ks_evcreg = kstat_create(scsb_name, scsb->scsb_instance,
5609             SCSB_KS_EVC_REGISTER, "misc", KSTAT_TYPE_NAMED, 2,
5610             KSTAT_FLAG_PERSISTENT|KSTAT_FLAG_WRITABLE)) == NULL) {
5611                 scsb->scsb_state |= SCSB_KSTATS;
5612                 scsb_free_kstats(scsb);
5613                 return (DDI_FAILURE);
5614         }
5615         scsb->ks_evcreg->ks_update = update_ks_evcreg;
5616         scsb->ks_evcreg->ks_private = (void *)scsb;
5617         kn = KSTAT_NAMED_PTR(scsb->ks_evcreg);
5618         kstat_named_init(&kn[0], "pid_register", KSTAT_DATA_INT64);
5619         kstat_named_init(&kn[1], "pid_unregister", KSTAT_DATA_INT64);
5620         kstat_install(scsb->ks_evcreg);
5621         /*
5622          * Done, set the flag for scsb_detach() and other checks
5623          */
5624         scsb->scsb_state |= SCSB_KSTATS;
5625         return (DDI_SUCCESS);
5626 }
5627 
5628 static int
5629 update_ks_leddata(kstat_t *ksp, int rw)
5630 {
5631         scsb_state_t            *scsb;
5632         scsb_ks_leddata_t       *pks_leddata;
5633         int                     i, numregs, index, error = DDI_SUCCESS;
5634         uchar_t                 reg;
5635 
5636         scsb = (scsb_state_t *)ksp->ks_private;
5637         if (scsb_debug & 0x00080001)
5638                 cmn_err(CE_NOTE, "update_ks_leddata: KS_UPDATE%sset",
5639                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5640         /*
5641          * Since this is satisfied from the shadow registers, let it succeed
5642          * even if the SCB is not present.  It would be nice to return the
5643          * shadow values with a warning.
5644          *
5645          * if (scsb->scsb_state & SCSB_FROZEN) {
5646          *      return (DDI_FAILURE);
5647          * }
5648          */
5649         if (rw == KSTAT_WRITE) {
5650                 return (EACCES);
5651         }
5652         mutex_enter(&scsb->scsb_mutex);
5653         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5654                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5655                         mutex_exit(&scsb->scsb_mutex);
5656                         return (EINTR);
5657                 }
5658         }
5659         scsb->scsb_state |= SCSB_KS_UPDATE;
5660         mutex_exit(&scsb->scsb_mutex);
5661         if (scsb_debug & 0x00080001)
5662                 cmn_err(CE_NOTE, "update_ks_leddata: updating data");
5663         pks_leddata = (scsb_ks_leddata_t *)ksp->ks_data;
5664         /*
5665          * Call tonga_slotnum_led_shift() for each register that
5666          * contains Slot 1-5 information, the first register at each base:
5667          * NOK_BASE, OK_BASE, BLINK_OK_BASE
5668          * XXX: breaking register table access rules by not using macros.
5669          */
5670         /* NOK */
5671         reg = SCSB_REG_ADDR(SCTRL_LED_NOK_BASE);
5672         index = SCSB_REG_INDEX(reg);
5673         numregs = SCTRL_LED_NOK_NUMREGS;
5674         i = 0;
5675         if (IS_SCB_P15)
5676                 reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
5677         else
5678                 reg = scsb->scsb_data_reg[index];
5679         pks_leddata->scb_led_regs[i] = reg;
5680         for (++i, ++index; i < numregs; ++i, ++index)
5681                 pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
5682         /* OK */
5683         reg = SCSB_REG_ADDR(SCTRL_LED_OK_BASE);
5684         index = SCSB_REG_INDEX(reg);
5685         numregs += SCTRL_LED_OK_NUMREGS;
5686         if (IS_SCB_P15)
5687                 reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
5688         else
5689                 reg = scsb->scsb_data_reg[index];
5690         pks_leddata->scb_led_regs[i] = reg;
5691         for (++i, ++index; i < numregs; ++i, ++index)
5692                 pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
5693         /* BLINK */
5694         reg = SCSB_REG_ADDR(SCTRL_BLINK_OK_BASE);
5695         index = SCSB_REG_INDEX(reg);
5696         numregs += SCTRL_BLINK_NUMREGS;
5697         if (IS_SCB_P15)
5698                 reg = tonga_slotnum_led_shift(scsb, scsb->scsb_data_reg[index]);
5699         else
5700                 reg = scsb->scsb_data_reg[index];
5701         pks_leddata->scb_led_regs[i] = reg;
5702         for (++i, ++index; i < numregs; ++i, ++index)
5703                 pks_leddata->scb_led_regs[i] = scsb->scsb_data_reg[index];
5704         mutex_enter(&scsb->scsb_mutex);
5705         scsb->scsb_state &= ~SCSB_KS_UPDATE;
5706         cv_signal(&scsb->scsb_cv);
5707         mutex_exit(&scsb->scsb_mutex);
5708         if (scsb_debug & 0x00080001)
5709                 cmn_err(CE_NOTE, "update_ks_leddata: returning");
5710         return (error);
5711 }
5712 
5713 static int
5714 update_ks_evcreg(kstat_t *ksp, int rw)
5715 {
5716         scsb_state_t            *scsb;
5717         int                     error = 0;
5718         kstat_named_t           *kn = KSTAT_NAMED_PTR(ksp);
5719         pid_t                   pid;
5720 
5721         scsb = (scsb_state_t *)ksp->ks_private;
5722         if (scsb_debug & 0x00080001)
5723                 cmn_err(CE_NOTE, "update_ks_evcreg: %s(%d), KS_UPDATE%sset",
5724                     rw == KSTAT_READ ? "read" : "write", rw,
5725                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5726         /*
5727          * Let this registration succeed
5728          *
5729          * if (scsb->scsb_state & SCSB_FROZEN) {
5730          *      return (DDI_FAILURE);
5731          * }
5732          */
5733         mutex_enter(&scsb->scsb_mutex);
5734         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5735                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5736                         mutex_exit(&scsb->scsb_mutex);
5737                         return (EINTR);
5738                 }
5739         }
5740         scsb->scsb_state |= SCSB_KS_UPDATE;
5741         mutex_exit(&scsb->scsb_mutex);
5742         if (rw == KSTAT_READ) {
5743                 kn[0].value.i64 = (int64_t)0;
5744                 kn[1].value.i64 = (int64_t)0;
5745         } else if (rw == KSTAT_WRITE) {
5746                 /*
5747                  * kn[0] is "pid_register", kn[1] is "pid_unregister"
5748                  */
5749                 if (kn[0].value.i64 != 0 && kn[1].value.i64 == 0) {
5750                         pid = (pid_t)kn[0].value.i64;
5751                         if (add_event_proc(scsb, pid)) {
5752                                 if (scsb_debug & 0x02000002) {
5753                                         cmn_err(CE_WARN,
5754                                             "update_ks_evcreg: "
5755                                             "process add failed for %d",
5756                                             pid);
5757                                 }
5758                                 error = EOVERFLOW;
5759                         }
5760                 } else if (kn[0].value.i64 == 0 && kn[1].value.i64 != 0) {
5761                         pid = (pid_t)kn[1].value.i64;
5762                         if (del_event_proc(scsb, pid)) {
5763                                 if (scsb_debug & 0x02000000) {
5764                                         cmn_err(CE_NOTE,
5765                                             "update_ks_evcreg: "
5766                                             "process delete failed for %d",
5767                                             pid);
5768                                 }
5769                                 error = EOVERFLOW;
5770                         }
5771                 } else if (kn[0].value.i64 == 0 && kn[1].value.i64 == 0) {
5772                         /*
5773                          * rewind the pointers and counts, zero the table.
5774                          */
5775                         rew_event_proc(scsb);
5776                 } else {
5777                         error = EINVAL;
5778                 }
5779         } else {
5780                 error = EINVAL;
5781         }
5782         mutex_enter(&scsb->scsb_mutex);
5783         scsb->scsb_state &= ~SCSB_KS_UPDATE;
5784         cv_signal(&scsb->scsb_cv);
5785         mutex_exit(&scsb->scsb_mutex);
5786         return (error);
5787 }
5788 
5789 static int
5790 update_ks_state(kstat_t *ksp, int rw)
5791 {
5792         scsb_state_t            *scsb;
5793         scsb_ks_state_t         *pks_state;
5794         int                     error = DDI_SUCCESS;
5795         uint32_t                current_evc;
5796 
5797         scsb = (scsb_state_t *)ksp->ks_private;
5798         if (scsb_debug & 0x00080001)
5799                 cmn_err(CE_NOTE, "update_ks_state: KS_UPDATE%sset",
5800                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5801         /*
5802          * Let this succeed based on last known data
5803          *
5804          * if (scsb->scsb_state & SCSB_FROZEN) {
5805          *      return (DDI_FAILURE);
5806          * }
5807          */
5808         if (rw == KSTAT_WRITE) {
5809                 return (EACCES);
5810         }
5811         mutex_enter(&scsb->scsb_mutex);
5812         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5813                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5814                         mutex_exit(&scsb->scsb_mutex);
5815                         return (EINTR);
5816                 }
5817         }
5818         scsb->scsb_state |= SCSB_KS_UPDATE;
5819         /*
5820          * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence
5821          * by initiating an I2C read from the SCB.  If an error occurs,
5822          * scsb_freeze() will be called to update SCB info and scsb state.
5823          */
5824         if (!(scsb->scsb_state & SCSB_SSB_PRESENT) &&
5825             !(scsb->scsb_state & SCSB_FROZEN)) {
5826                 uchar_t         data;
5827                 /* Read the SCB PROM ID */
5828                 if (data = scsb_rdwr_register(scsb, I2C_WR_RD,
5829                     (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1))
5830                         if (scsb_debug & 0x00080002)
5831                                 cmn_err(CE_NOTE, "update_ks_state: SCB/I2C "
5832                                     "failure %d", data);
5833         }
5834         mutex_exit(&scsb->scsb_mutex);
5835         pks_state = (scsb_ks_state_t *)ksp->ks_data;
5836         pks_state->scb_present = (scsb->scsb_state & SCSB_SCB_PRESENT) ? 1 : 0;
5837         pks_state->ssb_present = (scsb->scsb_state & SCSB_SSB_PRESENT) ? 1 : 0;
5838         pks_state->scsb_frozen = (scsb->scsb_state & SCSB_FROZEN) ? 1 : 0;
5839         if (scsb->scsb_state & SCSB_DEBUG_MODE)
5840                 pks_state->scsb_mode = (uint8_t)ENVC_DEBUG_MODE;
5841         else if (scsb->scsb_state & SCSB_DIAGS_MODE)
5842                 pks_state->scsb_mode = (uint8_t)ENVCTRL_DIAG_MODE;
5843         else
5844                 pks_state->scsb_mode = (uint8_t)ENVCTRL_NORMAL_MODE;
5845         /*
5846          * If scsb_attach() has not completed the kstat installs,
5847          * then there are no event processes to check for.
5848          */
5849         if (scsb->scsb_state & SCSB_KSTATS) {
5850                 switch (check_event_procs(&current_evc)) {
5851                 case EVC_NO_EVENT_CODE:
5852                         pks_state->event_code = 0;
5853                         break;
5854                 case EVC_NEW_EVENT_CODE:
5855                 /* FALLTHROUGH */
5856                 case EVC_NO_CURR_PROC:
5857                         pks_state->event_code = current_evc;
5858                         break;
5859                 case EVC_OR_EVENT_CODE:
5860                         pks_state->event_code |= current_evc;
5861                         break;
5862                 case EVC_FAILURE:
5863                         pks_state->event_code = 0;
5864                         error = DDI_FAILURE;
5865                         break;
5866                 }
5867         } else {
5868                 pks_state->event_code = 0;
5869         }
5870         mutex_enter(&scsb->scsb_mutex);
5871         scsb->scsb_state &= ~SCSB_KS_UPDATE;
5872         cv_signal(&scsb->scsb_cv);
5873         mutex_exit(&scsb->scsb_mutex);
5874         return (error);
5875 }
5876 
5877 static int
5878 update_ks_topology(kstat_t *ksp, int rw)
5879 {
5880         scsb_state_t            *scsb;
5881         mct_topology_t          *pks_topo;
5882         fru_info_t              *fru_ptr;
5883         int                     i, val, error = DDI_SUCCESS, slotnum;
5884 
5885         scsb = (scsb_state_t *)ksp->ks_private;
5886         if (scsb_debug & 0x00080001)
5887                 cmn_err(CE_NOTE, "update_ks_topology: KS_UPDATE%sset",
5888                     scsb->scsb_state & SCSB_KS_UPDATE ? " " : " not ");
5889         /*
5890          * Let this succeed based on last known data
5891          *
5892          * if (scsb->scsb_state & SCSB_FROZEN) {
5893          *      return (DDI_FAILURE);
5894          * }
5895          */
5896         if (rw == KSTAT_WRITE) {
5897                 return (EACCES);
5898         }
5899         mutex_enter(&scsb->scsb_mutex);
5900         while (scsb->scsb_state & SCSB_KS_UPDATE) {
5901                 if (cv_wait_sig(&scsb->scsb_cv, &scsb->scsb_mutex) <= 0) {
5902                         mutex_exit(&scsb->scsb_mutex);
5903                         return (EINTR);
5904                 }
5905         }
5906         scsb->scsb_state |= SCSB_KS_UPDATE;
5907         /*
5908          * If SSB not present and scsb not SCSB_FROZEN, check for SCB presence
5909          * by initiating an I2C read from the SCB.  If an error occurs,
5910          * scsb_freeze() will be called to update SCB info and scsb state.
5911          */
5912         if (!(scsb->scsb_state & SCSB_SSB_PRESENT) &&
5913             !(scsb->scsb_state & SCSB_FROZEN)) {
5914                 uchar_t         data;
5915                 /* Read the SCB PROM ID */
5916                 if (data = scsb_rdwr_register(scsb, I2C_WR_RD,
5917                     (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1))
5918                         if (scsb_debug & 0x00080002)
5919                                 cmn_err(CE_NOTE, "update_ks_topology: SCB/I2C "
5920                                     "failure %d", data);
5921         }
5922         mutex_exit(&scsb->scsb_mutex);
5923         pks_topo = (mct_topology_t *)ksp->ks_data;
5924         for (i = SLOT; i < SCSB_UNIT_TYPES; ++i) {
5925                 pks_topo->max_units[i] = mct_system_info.max_units[i];
5926         }
5927 
5928         pks_topo->mid_plane.fru_status = FRU_PRESENT;
5929         pks_topo->mid_plane.fru_unit = (scsb_unum_t)1;
5930         pks_topo->mid_plane.fru_type = mct_system_info.mid_plane.fru_type;
5931         pks_topo->mid_plane.fru_id = mct_system_info.mid_plane.fru_id;
5932         pks_topo->mid_plane.fru_version = mct_system_info.mid_plane.fru_version;
5933         pks_topo->mid_plane.fru_health = MCT_HEALTH_OK;
5934         fru_ptr = mct_system_info.fru_info_list[SLOT];
5935         for (i = 0; i < pks_topo->max_units[SLOT]; ++i, ++fru_ptr) {
5936                 pks_topo->mct_slots[i].fru_status = fru_ptr->fru_status;
5937                 pks_topo->mct_slots[i].fru_type = fru_ptr->fru_type;
5938                 pks_topo->mct_slots[i].fru_unit = fru_ptr->fru_unit;
5939                 pks_topo->mct_slots[i].fru_id = fru_ptr->fru_id;
5940                 pks_topo->mct_slots[i].fru_version = fru_ptr->fru_version;
5941                 /*
5942                  * XXX: need to check healthy regs to set fru_health
5943                  */
5944                 slotnum = tonga_psl_to_ssl(scsb, i+1);
5945                 val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
5946                     SCSB_FRU_OP_GET_BITVAL);
5947                 pks_topo->mct_slots[i].fru_health = (val) ?
5948                     MCT_HEALTH_OK : MCT_HEALTH_NOK;
5949         }
5950         fru_ptr = mct_system_info.fru_info_list[PDU];
5951         for (i = 0; i < pks_topo->max_units[PDU]; ++i, ++fru_ptr) {
5952                 pks_topo->mct_pdu[i].fru_status = fru_ptr->fru_status;
5953                 pks_topo->mct_pdu[i].fru_type = fru_ptr->fru_type;
5954                 pks_topo->mct_pdu[i].fru_unit = fru_ptr->fru_unit;
5955                 pks_topo->mct_pdu[i].fru_id = fru_ptr->fru_id;
5956                 pks_topo->mct_pdu[i].fru_version = fru_ptr->fru_version;
5957                 pks_topo->mct_pdu[i].fru_health = MCT_HEALTH_NA;
5958         }
5959         fru_ptr = mct_system_info.fru_info_list[PS];
5960         for (i = 0; i < pks_topo->max_units[PS]; ++i, ++fru_ptr) {
5961                 pks_topo->mct_ps[i].fru_status = fru_ptr->fru_status;
5962                 pks_topo->mct_ps[i].fru_type = fru_ptr->fru_type;
5963                 pks_topo->mct_ps[i].fru_unit = fru_ptr->fru_unit;
5964                 pks_topo->mct_ps[i].fru_id = fru_ptr->fru_id;
5965                 pks_topo->mct_ps[i].fru_version = fru_ptr->fru_version;
5966                 pks_topo->mct_ps[i].fru_health = MCT_HEALTH_NA;
5967         }
5968         fru_ptr = mct_system_info.fru_info_list[DISK];
5969         for (i = 0; i < pks_topo->max_units[DISK]; ++i, ++fru_ptr) {
5970                 pks_topo->mct_disk[i].fru_status = fru_ptr->fru_status;
5971                 pks_topo->mct_disk[i].fru_type = fru_ptr->fru_type;
5972                 pks_topo->mct_disk[i].fru_unit = fru_ptr->fru_unit;
5973                 pks_topo->mct_disk[i].fru_id = fru_ptr->fru_id;
5974                 pks_topo->mct_disk[i].fru_version = fru_ptr->fru_version;
5975                 pks_topo->mct_disk[i].fru_health = MCT_HEALTH_NA;
5976         }
5977         fru_ptr = mct_system_info.fru_info_list[FAN];
5978         for (i = 0; i < pks_topo->max_units[FAN]; ++i, ++fru_ptr) {
5979                 pks_topo->mct_fan[i].fru_status = fru_ptr->fru_status;
5980                 pks_topo->mct_fan[i].fru_type = fru_ptr->fru_type;
5981                 pks_topo->mct_fan[i].fru_unit = fru_ptr->fru_unit;
5982                 pks_topo->mct_fan[i].fru_id = fru_ptr->fru_id;
5983                 pks_topo->mct_fan[i].fru_version = fru_ptr->fru_version;
5984                 pks_topo->mct_fan[i].fru_health = MCT_HEALTH_NA;
5985         }
5986         fru_ptr = mct_system_info.fru_info_list[SCB];
5987         for (i = 0; i < pks_topo->max_units[SCB]; ++i, ++fru_ptr) {
5988                 pks_topo->mct_scb[i].fru_status = fru_ptr->fru_status;
5989                 pks_topo->mct_scb[i].fru_type = fru_ptr->fru_type;
5990                 pks_topo->mct_scb[i].fru_unit = fru_ptr->fru_unit;
5991                 pks_topo->mct_scb[i].fru_id = fru_ptr->fru_id;
5992                 pks_topo->mct_scb[i].fru_version = fru_ptr->fru_version;
5993                 /*
5994                  * To get the scsb health, if there was no i2c transaction
5995                  * until this read, generate an i2c transaction.
5996                  */
5997                 if (scsb->scsb_kstat_flag == B_FALSE) {
5998                         uchar_t         data;
5999                         (void) scsb_blind_read(scsb, I2C_WR_RD,
6000                             (uchar_t)SCTRL_PROM_VERSION, 1, &data, 1);
6001                 }
6002                 pks_topo->mct_scb[i].fru_health = ((scsb->scsb_err_flag ==
6003                     B_TRUE || scsb->scsb_i2c_errcnt > scsb_err_threshold)
6004                     ?  MCT_HEALTH_NOK : MCT_HEALTH_OK);
6005 #ifdef DEBUG
6006                 if (pks_topo->mct_scb[i].fru_health == MCT_HEALTH_NOK)
6007                         cmn_err(CE_WARN, "SCSB kstat health:%d", pks_topo->
6008                             mct_scb[i].fru_health);
6009 #endif
6010                 scsb->scsb_err_flag = B_FALSE; /* clear error flag once read */
6011                 scsb->scsb_kstat_flag = B_FALSE; /* false? read from i2c */
6012         }
6013         fru_ptr = mct_system_info.fru_info_list[SSB];
6014         for (i = 0; i < pks_topo->max_units[SSB]; ++i, ++fru_ptr) {
6015                 pks_topo->mct_ssb[i].fru_status = fru_ptr->fru_status;
6016                 pks_topo->mct_ssb[i].fru_type = fru_ptr->fru_type;
6017                 pks_topo->mct_ssb[i].fru_unit = fru_ptr->fru_unit;
6018                 pks_topo->mct_ssb[i].fru_id = fru_ptr->fru_id;
6019                 pks_topo->mct_ssb[i].fru_version = fru_ptr->fru_version;
6020                 pks_topo->mct_ssb[i].fru_health = MCT_HEALTH_NA;
6021         }
6022         fru_ptr = mct_system_info.fru_info_list[ALARM];
6023         for (i = 0; i < pks_topo->max_units[ALARM]; ++i, ++fru_ptr) {
6024                 pks_topo->mct_alarm[i].fru_status = fru_ptr->fru_status;
6025                 pks_topo->mct_alarm[i].fru_type = fru_ptr->fru_type;
6026                 pks_topo->mct_alarm[i].fru_unit = fru_ptr->fru_unit;
6027                 pks_topo->mct_alarm[i].fru_id = fru_ptr->fru_id;
6028                 pks_topo->mct_alarm[i].fru_version = fru_ptr->fru_version;
6029                 pks_topo->mct_alarm[i].fru_health = MCT_HEALTH_NA;
6030         }
6031         fru_ptr = mct_system_info.fru_info_list[CFTM];
6032         for (i = 0; i < pks_topo->max_units[CFTM]; ++i, ++fru_ptr) {
6033                 pks_topo->mct_cftm[i].fru_status = fru_ptr->fru_status;
6034                 pks_topo->mct_cftm[i].fru_type = fru_ptr->fru_type;
6035                 pks_topo->mct_cftm[i].fru_unit = fru_ptr->fru_unit;
6036                 pks_topo->mct_cftm[i].fru_id = fru_ptr->fru_id;
6037                 pks_topo->mct_cftm[i].fru_version = fru_ptr->fru_version;
6038                 pks_topo->mct_cftm[i].fru_health = MCT_HEALTH_NA;
6039         }
6040         fru_ptr = mct_system_info.fru_info_list[CRTM];
6041         for (i = 0; i < pks_topo->max_units[CRTM]; ++i, ++fru_ptr) {
6042                 pks_topo->mct_crtm[i].fru_status = fru_ptr->fru_status;
6043                 pks_topo->mct_crtm[i].fru_type = fru_ptr->fru_type;
6044                 pks_topo->mct_crtm[i].fru_unit = fru_ptr->fru_unit;
6045                 pks_topo->mct_crtm[i].fru_id = fru_ptr->fru_id;
6046                 pks_topo->mct_crtm[i].fru_version = fru_ptr->fru_version;
6047                 pks_topo->mct_crtm[i].fru_health = MCT_HEALTH_NA;
6048         }
6049         fru_ptr = mct_system_info.fru_info_list[PRTM];
6050         for (i = 0; i < pks_topo->max_units[PRTM]; ++i, ++fru_ptr) {
6051                 pks_topo->mct_prtm[i].fru_status = fru_ptr->fru_status;
6052                 pks_topo->mct_prtm[i].fru_type = fru_ptr->fru_type;
6053                 pks_topo->mct_prtm[i].fru_unit = fru_ptr->fru_unit;
6054                 pks_topo->mct_prtm[i].fru_id = fru_ptr->fru_id;
6055                 pks_topo->mct_prtm[i].fru_version = fru_ptr->fru_version;
6056                 pks_topo->mct_prtm[i].fru_health = MCT_HEALTH_NA;
6057         }
6058         mutex_enter(&scsb->scsb_mutex);
6059         scsb->scsb_state &= ~SCSB_KS_UPDATE;
6060         cv_signal(&scsb->scsb_cv);
6061         mutex_exit(&scsb->scsb_mutex);
6062         return (error);
6063 }
6064 
6065 static void
6066 scsb_free_kstats(scsb_state_t *scsb)
6067 {
6068         if (!(scsb->scsb_state & SCSB_KSTATS))
6069                 return;
6070         /*
6071          * free the allocated kstat data
6072          */
6073         if (scsb->ks_evcreg != NULL) {
6074                 kstat_delete(scsb->ks_evcreg);
6075         }
6076         if (scsb->ks_topology != NULL) {
6077                 kstat_delete(scsb->ks_topology);
6078         }
6079         if (scsb->ks_state != NULL) {
6080                 kstat_delete(scsb->ks_state);
6081         }
6082         if (scsb->ks_leddata != NULL) {
6083                 kstat_delete(scsb->ks_leddata);
6084         }
6085         scsb->ks_leddata = NULL;
6086         scsb->ks_state = NULL;
6087         scsb->ks_topology = NULL;
6088         scsb->ks_evcreg = NULL;
6089         scsb->scsb_state &= ~SCSB_KSTATS;
6090 }
6091 
6092 
6093 /*
6094  * --------------------------------------
6095  * Miscellaneous scsb internal functions.
6096  * --------------------------------------
6097  *
6098  * allocate I2C transfer structure
6099  */
6100 static i2c_transfer_t *
6101 scsb_alloc_i2ctx(i2c_client_hdl_t phandle, uint_t sleep)
6102 {
6103         i2c_transfer_t  *tp;
6104 
6105         if (i2c_transfer_alloc(phandle, &tp, SCSB_DATA_REGISTERS + 2,
6106             SCSB_DATA_REGISTERS + 2, sleep) == I2C_FAILURE) {
6107                 return (NULL);
6108         }
6109         return (tp);
6110 }
6111 
6112 /*
6113  * free I2C transfer structure
6114  */
6115 static void
6116 scsb_free_i2ctx(i2c_client_hdl_t phandle, i2c_transfer_t *tp)
6117 {
6118         i2c_transfer_free(phandle, tp);
6119 }
6120 
6121 static  void
6122 update_fru_info(scsb_state_t *scsb, fru_info_t *fru_ptr)
6123 {
6124         int             index;
6125         uchar_t         reg, bit;
6126         fru_info_t      *acslot_ptr = NULL;
6127         fru_id_t        acslot_id = 0;
6128         if (scsb_debug & 0x00100001)
6129                 cmn_err(CE_NOTE, "update_fru_info(scsb,0x%p)", (void *)fru_ptr);
6130         if (fru_ptr == (fru_info_t *)NULL ||
6131             fru_ptr->i2c_info == (fru_i2c_info_t *)NULL)
6132                 return;
6133         /*
6134          * If this is an Alarm Card update, then we also need to get
6135          * Alarm Card Slot fru_ptr to update it's fru_type, and maybe fru_id
6136          */
6137         if (fru_ptr->fru_id == fru_id_table[FRU_INDEX(SCTRL_EVENT_ALARM)]) {
6138                 /*
6139                  * SCTRL_EVENT_SLOT1 == 0x01 so
6140                  * fru_id_table[] index for Slot 1 == 0
6141                  */
6142                 acslot_id = fru_id_table[(scsb->ac_slotnum - 1)];
6143                 acslot_ptr = find_fru_info(acslot_id);
6144         }
6145         reg = fru_ptr->i2c_info->syscfg_reg;
6146         bit = fru_ptr->i2c_info->syscfg_bit;
6147         if (reg == 0 && fru_ptr->fru_type == SCB) {
6148                 if (scsb->scsb_state & SCSB_SCB_PRESENT)
6149                         fru_ptr->fru_status = FRU_PRESENT;
6150                 else
6151                         fru_ptr->fru_status = FRU_NOT_PRESENT;
6152         } else if (reg) {
6153                 index = SCSB_REG_INDEX(reg);
6154                 if (scsb->scsb_data_reg[index] & (1 << bit)) {
6155                         fru_ptr->fru_status = FRU_PRESENT;
6156                         /*
6157                          * XXX: need to add version register, and maybe a
6158                          *       method, to the fru_ptr->i2c_info structure.
6159                          *
6160                          * fru_ptr->fru_version = (fru_version_t)0;
6161                          */
6162                         /*
6163                          * Because scsb_intr() sometimes gets the AC present
6164                          * INT before the ACSLOT present INT,
6165                          * do not check the ACSLOT fru_status
6166                          *
6167                          * if (acslot_ptr != NULL && acslot_ptr->fru_status ==
6168                          *                                      FRU_PRESENT)
6169                          */
6170                         if (acslot_ptr != NULL)
6171                                 acslot_ptr->fru_type = (scsb_utype_t)OC_AC;
6172                 } else {
6173                         fru_ptr->fru_status = FRU_NOT_PRESENT;
6174                         /*
6175                          * fru_ptr->fru_version = (fru_version_t)0;
6176                          */
6177                         if (acslot_ptr != NULL) {
6178                                 /* AC just removed, but AC Slot is occupied? */
6179                                 if (acslot_ptr->fru_status == FRU_PRESENT)
6180                                         /* for now it's unknown */
6181                                         acslot_ptr->fru_type =
6182                                             (scsb_utype_t)OC_UNKN;
6183                                 else
6184                                         acslot_ptr->fru_type =
6185                                             (scsb_utype_t)OC_UNKN;
6186                         }
6187                 }
6188         }
6189         if (scsb_debug & 0x00100000)
6190                 cmn_err(CE_NOTE,
6191                     "update_fru_info: type %d unit %d is %spresent",
6192                     fru_ptr->fru_type, fru_ptr->fru_unit,
6193                     fru_ptr->fru_status == FRU_PRESENT
6194                     ? "" : "not ");
6195 }
6196 
6197 /*
6198  * Convert EVENT code to FRU index
6199  * by finding the highest bit number in 32 bit word
6200  */
6201 static int
6202 event_to_index(uint32_t evcode)
6203 {
6204         int     i = 0;
6205         if (evcode == 0)
6206                 return (MCT_MAX_FRUS - 1);
6207         for (; (evcode >>= 1); i++)
6208                 ;
6209         return (i);
6210 }
6211 
6212 #ifdef DEBUG
6213 void
6214 scsb_debug_prnt(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
6215         uintptr_t a4, uintptr_t a5)
6216 {
6217         if (scsb_debug & 0x8000 ||
6218             (*fmt == 'X' && scsb_debug & 0x00010000)) {
6219                 if (*fmt == 'X')
6220                         ++fmt;
6221                 prom_printf("scsb: ");
6222                 prom_printf(fmt, a1, a2, a3, a4, a5);
6223                 prom_printf("\n");
6224         }
6225 }
6226 #endif
6227 
6228 /*
6229  * event code functions to deliver event codes
6230  * and to manage:
6231  *      the event code fifo
6232  *      the process handle table for registered processes interested in
6233  *        event codes
6234  */
6235 /*
6236  * Send signal to processes registered for event code delivery
6237  */
6238 static void
6239 signal_evc_procs(scsb_state_t *scsb)
6240 {
6241         int     i = 0, c = 0;
6242         if (evc_proc_count == 0)
6243                 return;
6244         for (; i < EVC_PROCS_MAX; ++i) {
6245                 if (evc_procs[i] != NULL) {
6246                         if (proc_signal(evc_procs[i], SIGPOLL)) {
6247                                 if (scsb_debug & 0x02000002)
6248                                         cmn_err(CE_WARN,
6249                                             "scsb:signal_evc_procs: "
6250                                             "signal to %d failed",
6251                                             ((struct pid *)
6252                                             evc_procs[i])->pid_id);
6253                                 (void) del_event_proc(scsb,
6254                                     ((struct pid *)evc_procs[i])->pid_id);
6255                         }
6256                         if (++c >= evc_proc_count) {
6257                                 if (scsb_debug & 0x02000000) {
6258                                         cmn_err(CE_NOTE,
6259                                             "signal_evc_procs: signaled "
6260                                             "%d/%d processes", c,
6261                                             evc_proc_count);
6262                                 }
6263                                 break;
6264                         }
6265                 }
6266         }
6267 }
6268 
6269 /*
6270  * bump FIFO ptr, taking care of wrap around
6271  */
6272 static uint32_t *
6273 inc_fifo_ptr(uint32_t *ptr)
6274 {
6275         if (++ptr >= evc_fifo + EVC_FIFO_SIZE)
6276                 ptr = evc_fifo;
6277         return (ptr);
6278 }
6279 
6280 /* ARGSUSED */
6281 static void
6282 reset_evc_fifo(scsb_state_t *scsb)
6283 {
6284         evc_wptr = evc_fifo;
6285         evc_rptr = evc_fifo;
6286         evc_fifo_count = 0;
6287 }
6288 
6289 /*
6290  * Called from scsb_intr() when a new event occurs, to put new code in FIFO,
6291  * and signal any interested processes in evc_procs[].
6292  * Always succeeds.
6293  */
6294 static void
6295 add_event_code(scsb_state_t *scsb, uint32_t event_code)
6296 {
6297         if (event_proc_count(scsb) == 0) {
6298                 return;
6299         }
6300         *evc_wptr = event_code;
6301         evc_wptr = inc_fifo_ptr(evc_wptr);
6302         if (++evc_fifo_count > EVC_FIFO_SIZE) {
6303                 --evc_fifo_count;               /* lose the oldest event */
6304                 evc_rptr = inc_fifo_ptr(evc_rptr);
6305         }
6306         if (scsb_debug & 0x01000000) {
6307                 cmn_err(CE_NOTE, "add_event_code: 0x%x, FIFO size = %d",
6308                     event_code, evc_fifo_count);
6309         }
6310         signal_evc_procs(scsb);
6311 }
6312 
6313 /*
6314  * called from check_event_procs() when the last registered process
6315  * retrieved the oldest event
6316  */
6317 static uint32_t
6318 del_event_code()
6319 {
6320         uint32_t evc = 0;
6321         if (!evc_fifo_count)
6322                 return (scsb_event_code);
6323         evc = *evc_rptr;
6324         evc_rptr = inc_fifo_ptr(evc_rptr);
6325         --evc_fifo_count;
6326         if (scsb_debug & 0x01000000) {
6327                 cmn_err(CE_NOTE, "del_event_code: 0x%x, FIFO size = %d",
6328                     evc, evc_fifo_count);
6329         }
6330         return (evc);
6331 }
6332 
6333 /*
6334  * called from check_event_procs() to retrieve the current event code
6335  */
6336 static uint32_t
6337 get_event_code()
6338 {
6339         if (!evc_fifo_count)
6340                 return (0);
6341         return (*evc_rptr);
6342 }
6343 
6344 /*
6345  * called from an application interface (ie: an ioctl command)
6346  * to register a process id interested in SCB events.
6347  * NOTE: proc_ref() must be called from USER context, so since this is a
6348  * streams driver, a kstat interface is used for process registration.
6349  * return:
6350  *      0 = event_proc was added
6351  *      1 = out of space
6352  */
6353 /* ARGSUSED */
6354 static int
6355 add_event_proc(scsb_state_t *scsb, pid_t pid)
6356 {
6357         int     i = 0;
6358         void    *curr_proc;
6359         pid_t   curr_pid;
6360         if (evc_proc_count >= EVC_PROCS_MAX)
6361                 return (1);
6362         curr_proc = proc_ref();
6363         curr_pid = (pid_t)(((struct pid *)curr_proc)->pid_id);
6364         if (curr_pid != pid) {
6365                 if (scsb_debug & 0x02000000) {
6366                         cmn_err(CE_WARN,
6367                             "add_event_proc: current %d != requestor %d",
6368                             curr_pid, pid);
6369                 } else {
6370                         proc_unref(curr_proc);
6371                         return (1);
6372                 }
6373         }
6374         for (; i < EVC_PROCS_MAX; ++i) {
6375                 if (evc_procs[i] == NULL) {
6376                         evc_procs[i] = curr_proc;
6377                         evc_proc_count++;
6378                         if (scsb_debug & 0x02000000) {
6379                                 cmn_err(CE_NOTE,
6380                                     "add_event_proc: %d; evc_proc_count=%d",
6381                                     pid, evc_proc_count);
6382                         }
6383                         return (0);
6384                 }
6385         }
6386         proc_unref(curr_proc);
6387         return (1);
6388 }
6389 
6390 /*
6391  * called from an application interface (ie: an ioctl command)
6392  * to unregister a process id interested in SCB events.
6393  * return:
6394  *      0 = event_proc was deleted
6395  *      1 = event_proc was not found, or table was empty
6396  */
6397 /* ARGSUSED */
6398 static int
6399 del_event_proc(scsb_state_t *scsb, pid_t pid)
6400 {
6401         int     i = 0;
6402         int     cnt = 0;
6403         void    *this_proc;
6404         if (evc_proc_count == 0)
6405                 return (1);
6406         for (; i < EVC_PROCS_MAX; ++i) {
6407                 if (evc_procs[i] == NULL)
6408                         continue;
6409                 this_proc = evc_procs[i];
6410                 if (pid == ((struct pid *)this_proc)->pid_id) {
6411                         evc_procs[i] = NULL;
6412                         if (--evc_proc_count == 0) {
6413                                 /*
6414                                  * reset evc fifo cound and pointers
6415                                  */
6416                                 reset_evc_fifo(scsb);
6417                         }
6418                         if (scsb_debug & 0x02000000) {
6419                                 cmn_err(CE_NOTE,
6420                                     "del_event_proc: %d; evc_proc_count=%d",
6421                                     pid, evc_proc_count);
6422                         }
6423                         proc_unref(this_proc);
6424                         return (0);
6425                 }
6426                 if (++cnt >= evc_proc_count)
6427                         break;
6428         }
6429         return (1);
6430 }
6431 
6432 /*
6433  * Can be called from an application interface
6434  * to rewind the pointers and counters, and zero the table
6435  * return:
6436  */
6437 /* ARGSUSED */
6438 static void
6439 rew_event_proc(scsb_state_t *scsb)
6440 {
6441         int     i = 0;
6442         if (scsb_debug & 0x02000001) {
6443                 cmn_err(CE_NOTE, "rew_event_proc: evc_proc_count=%d",
6444                     evc_proc_count);
6445         }
6446         for (; i < EVC_PROCS_MAX; ++i) {
6447                 if (evc_procs[i] != NULL) {
6448                         proc_unref(evc_procs[i]);
6449                         evc_procs[i] = NULL;
6450                 }
6451         }
6452         evc_proc_count = 0;
6453 }
6454 
6455 /* ARGSUSED */
6456 static int
6457 event_proc_count(scsb_state_t *scsb)
6458 {
6459         return (evc_proc_count);
6460 }
6461 
6462 /*
6463  * return:
6464  *      1 = pid was found
6465  *      0 = pid was not found, or table was empty
6466  */
6467 static int
6468 find_evc_proc(pid_t pid)
6469 {
6470         int     i = 0;
6471         int     cnt = 0;
6472         if (evc_proc_count == 0)
6473                 return (0);
6474         for (; i < EVC_PROCS_MAX; ++i) {
6475                 if (evc_procs[i] == NULL)
6476                         continue;
6477                 if (pid == ((struct pid *)evc_procs[i])->pid_id)
6478                         return (1);
6479                 if (++cnt >= evc_proc_count)
6480                         break;
6481         }
6482         return (0);
6483 }
6484 
6485 /*
6486  * called from update_ks_state() to compare evc_proc_count with
6487  * evc_requests, also mainted by this same function
6488  * This function could check the current process id, since this will be a user
6489  * context call, and only bump evc_requests if the calling process is
6490  * registered for event code delivery.
6491  * return:
6492  *      EVC_NO_EVENT_CODE       : no event_code on fifo
6493  *      EVC_NO_CURR_PROC        : current process not in table,
6494  *                                but have an event_code
6495  *      EVC_NEW_EVENT_CODE      : return_evc is new ks_state->event_code
6496  *      EVC_OR_EVENT_CODE       : OR return_evc with ks_state->event_code
6497  *      EVC_FAILURE             : unrecoverable error condition.
6498  */
6499 static int
6500 check_event_procs(uint32_t *return_evc)
6501 {
6502         void            *curr_proc;
6503         pid_t           curr_pid = 0;
6504         int             return_val = 0;
6505         static int      evc_requests = 0;
6506         /*
6507          * get current process handle, and check the event_procs table
6508          */
6509         if (evc_proc_count == 0) {
6510                 *return_evc = del_event_code();
6511                 return_val = EVC_NO_CURR_PROC;
6512         } else {
6513                 curr_proc = proc_ref();
6514                 curr_pid = ((struct pid *)curr_proc)->pid_id;
6515                 proc_unref(curr_proc);
6516                 if (!find_evc_proc(curr_pid)) {
6517                         *return_evc = get_event_code();
6518                         return_val = EVC_NO_CURR_PROC;
6519                 } else if (++evc_requests >= evc_proc_count) {
6520                         evc_requests = 0;
6521                         *return_evc = del_event_code();
6522                         return_val = EVC_NEW_EVENT_CODE;
6523                 } else {
6524                         *return_evc = get_event_code();
6525                 }
6526                 if (!return_val)
6527                         return_val = EVC_OR_EVENT_CODE;
6528         }
6529         if (scsb_debug & 0x02000000) {
6530                 cmn_err(CE_NOTE, "check_event_procs: pid=%d, evc=0x%x, "
6531                     "requests=%d, returning 0x%x", curr_pid,
6532                     *return_evc, evc_requests, return_val);
6533         }
6534         return (return_val);
6535 }
6536 
6537 static int
6538 scsb_queue_put(queue_t *rq, int count, uint32_t *data, char *caller)
6539 {
6540         mblk_t          *mp;
6541         if (scsb_debug & 0x4001) {
6542                 cmn_err(CE_NOTE, "scsb_queue_put(0x%p, %d, 0x%x, %s)",
6543                     (void *)rq, count, *data, caller);
6544         }
6545         mp = allocb(sizeof (uint32_t) * count, BPRI_HI);
6546         if (mp == NULL) {
6547                 cmn_err(CE_WARN, "%s: allocb failed",
6548                     caller);
6549                 return (B_FALSE);
6550         }
6551         while (count--) {
6552                 *((uint32_t *)mp->b_wptr) = *data;
6553                 mp->b_wptr += sizeof (*data);
6554                 ++data;
6555         }
6556         putnext(rq, mp);
6557         return (B_TRUE);
6558 }
6559 
6560 /* CLONE */
6561 static int
6562 scsb_queue_ops(scsb_state_t     *scsb,
6563                 int             op,
6564                 int             oparg,
6565                 void            *opdata,
6566                 char            *caller)
6567 {
6568         clone_dev_t     *clptr;
6569         int             clone, find_open, find_available, retval = QOP_FAILED;
6570 
6571         switch (op) {
6572         case QPUT_INT32:
6573                 if (scsb->scsb_opens && scsb->scsb_rq != NULL &&
6574                     scsb_queue_put(scsb->scsb_rq, oparg,
6575                     (uint32_t *)opdata, caller) == B_FALSE) {
6576                         return (QOP_FAILED);
6577                 }
6578         /*FALLTHROUGH*/ /* to look for opened clones */
6579         case QPROCSOFF:
6580                 retval = QOP_OK;
6581         /*FALLTHROUGH*/
6582         case QFIRST_OPEN:
6583         case QFIND_QUEUE:
6584                 find_open = 1;
6585                 find_available = 0;
6586                 break;
6587         case QFIRST_AVAILABLE:
6588                 find_available = 1;
6589                 find_open = 0;
6590                 break;
6591         }
6592         for (clone = SCSB_CLONES_FIRST; clone < SCSB_CLONES_MAX; clone++) {
6593                 clptr = &scsb->clone_devs[clone];
6594                 if (find_open && clptr->cl_flags & SCSB_OPEN) {
6595                         if (clptr->cl_rq == NULL) {
6596                                 cmn_err(CE_WARN, "%s: Clone %d has no queue",
6597                                     caller, clptr->cl_minor);
6598                                 return (QOP_FAILED);
6599                         }
6600                         switch (op) {
6601                         case QPROCSOFF:
6602                                 qprocsoff(clptr->cl_rq);
6603                                 break;
6604                         case QPUT_INT32:
6605                                 if (scsb_queue_put(clptr->cl_rq, oparg,
6606                                     (uint32_t *)opdata, caller)
6607                                     == B_FALSE) {
6608                                         retval = QOP_FAILED;
6609                                 }
6610                                 break;
6611                         case QFIRST_OPEN:
6612                                 return (clone);
6613                         case QFIND_QUEUE:
6614                                 if (clptr->cl_rq == (queue_t *)opdata) {
6615                                         return (clone);
6616                                 }
6617                                 break;
6618                         }
6619                 } else if (find_available && clptr->cl_flags == 0) {
6620                         switch (op) {
6621                         case QFIRST_AVAILABLE:
6622                                 return (clone);
6623                         }
6624                 }
6625         }
6626         return (retval);
6627 }
6628 
6629 /*
6630  * Find out if a bit is set for the FRU type and unit number in the register
6631  * set defined by the register base table index, base.
6632  * Returns TRUE if bit is set, or FALSE.
6633  */
6634 static int
6635 scsb_fru_op(scsb_state_t *scsb, scsb_utype_t fru_type, int unit, int base,
6636                                                                         int op)
6637 {
6638         int             rc;
6639         uchar_t         reg;
6640         int             tmp, idx, code, offset;
6641 
6642 #if 0
6643                 reg = SCSB_REG_ADDR(i);
6644                 ac_mask = 1 << FRU_OFFSET(SCTRL_EVENT_ALARM, SCTRL_RESET_BASE);
6645                 ac_val = scsb->scsb_data_reg[index+1] & ac_mask;
6646 #endif
6647         /* get the event code based on which we get the reg and bit offsets */
6648         code   = FRU_UNIT_TO_EVCODE(fru_type, unit);
6649         /* get the bit offset in the 8bit register corresponding to the event */
6650         offset = FRU_OFFSET(code, base);
6651         /* register offset from the base register, based on the event code */
6652         if ((fru_type == ALARM) && (base == SCTRL_RESET_BASE))
6653                 tmp = ALARM_RESET_REG_INDEX(code, base);
6654         else
6655                 tmp = FRU_REG_INDEX(code, base);
6656         /* get the global offset of the register in the parent address space */
6657         reg    = SCSB_REG_ADDR(tmp);
6658         /* get the global index of the register in this SCSB's address space */
6659         idx    = SCSB_REG_INDEX(reg);
6660         DEBUG4("scsb_fru_op(start): code=%x, offset=%x, tmp=%x, reg=%x\n",
6661             code, offset, tmp, reg);
6662         switch (op) {
6663                 case SCSB_FRU_OP_GET_REG:
6664                         rc = reg;
6665                         break;
6666                 case SCSB_FRU_OP_GET_BITVAL:
6667                         rc = (scsb->scsb_data_reg[idx] & (1 << offset))
6668                             >> offset;
6669                         break;
6670                 case SCSB_FRU_OP_GET_REGDATA:
6671                         rc = scsb->scsb_data_reg[idx];
6672                         break;
6673                 case SCSB_FRU_OP_SET_REGBIT:
6674                         rc = (1 << offset) & 0xff;
6675                         break;
6676                 default:
6677                         break;
6678         }
6679         DEBUG4("scsb_fru_op: unit=%x, base=%x, op=%d, rc=%x\n", unit, base,
6680             op, rc);
6681         return (rc);
6682 }
6683 
6684 /*
6685  * All HSC related functions can fail, but an attempt is made to atleast
6686  * return the right shadow state  on get-state function when SCB is removed.
6687  */
6688 int
6689 scsb_get_slot_state(scsb_state_t *scsb, int pslotnum, int *rstate)
6690 {
6691         int             slotnum, val = 0, rc;
6692 
6693         /*
6694          * When SCB is removed, we could be called with the lock held.
6695          * We call check_config_status anyway since it is a read-only operation
6696          * and HSC could be invoking this function at interrupt context.
6697          * If scsb is already in the doing interrupt postprocess, wait..
6698          */
6699 
6700         rc = scsb_check_config_status(scsb);
6701 
6702         /* check if error is because SCB is removed */
6703         if ((rc != EAGAIN) && (rc != DDI_SUCCESS))
6704                 return (DDI_FAILURE);
6705         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
6706         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_SYSCFG_BASE,
6707             SCSB_FRU_OP_GET_BITVAL);
6708         if (! val) {
6709                 *rstate = HPC_SLOT_EMPTY;
6710                 return (0);
6711         }
6712         /*
6713          * now, lets determine if it is connected or disconnected.
6714          * If reset is asserted, then the slot is disconnected.
6715          */
6716         rc = scsb_reset_slot(scsb, pslotnum, SCSB_GET_SLOT_RESET_STATUS);
6717         /* check if error is because SCB is removed */
6718         if ((rc != EAGAIN) && (rc != DDI_SUCCESS))
6719                 return (DDI_FAILURE);
6720         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
6721             SCSB_FRU_OP_GET_BITVAL);
6722         if (val)
6723                 *rstate = HPC_SLOT_DISCONNECTED;
6724         else {
6725                 if (scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
6726                     SCSB_FRU_OP_GET_BITVAL)) {
6727                         *rstate = HPC_SLOT_CONNECTED;
6728                 } else {
6729                         cmn_err(CE_WARN, "%s#%d: Reset Not Asserted on "
6730                             "Healthy# Failed slot %d!",
6731                             ddi_driver_name(scsb->scsb_dev),
6732                             ddi_get_instance(scsb->scsb_dev), slotnum);
6733                         *rstate = HPC_SLOT_DISCONNECTED;
6734                 }
6735         }
6736         return (0);
6737 }
6738 
6739 int
6740 scsb_reset_slot(scsb_state_t *scsb, int pslotnum, int reset_flag)
6741 {
6742         int             slotnum, error, val, alarm_card = 0;
6743         i2c_transfer_t  *i2cxferp;
6744         uchar_t         reg;
6745         int             index, condition_exists = 0, ac_val;
6746 
6747         if (scsb_debug & 0x8001)
6748                 cmn_err(CE_NOTE, "scsb_reset_slot(%d), flag %x", pslotnum,
6749                     reset_flag);
6750         if (scsb->scsb_state & SCSB_FROZEN)
6751                 return (EAGAIN);
6752         if ((i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle,
6753             I2C_NOSLEEP)) == NULL) {
6754                 return (ENOMEM);
6755         }
6756         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
6757 
6758         if (scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) {
6759                 DEBUG0("alarm card  reset/unreset op:\n");
6760                 alarm_card = 1;
6761         }
6762         reg = SCSB_REG_ADDR(SCTRL_RESET_BASE);
6763         index = SCSB_REG_INDEX(reg);
6764 
6765         mutex_enter(&scsb->scsb_mutex);
6766         i2cxferp->i2c_flags = I2C_WR_RD;
6767         i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS;
6768         i2cxferp->i2c_wbuf[0] = reg;
6769         i2cxferp->i2c_wlen = 1;
6770         scsb->scsb_kstat_flag = B_TRUE;      /* we did an i2c transaction */
6771         if ((error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) == 0) {
6772                 scsb->scsb_i2c_errcnt = 0;
6773                 /*
6774                  * XXX: following statements assume 2 reset registers,
6775                  * which is the case for our current SCB revisions.
6776                  */
6777                 scsb->scsb_data_reg[index]   = i2cxferp->i2c_rbuf[0];
6778                 scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1];
6779         } else {
6780                 scsb->scsb_i2c_errcnt++;
6781                 if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
6782                         scsb->scsb_err_flag = B_TRUE; /* latch until kstat */
6783                 if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
6784                         if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
6785                                 mutex_exit(&scsb->scsb_mutex);
6786                                 scsb_freeze(scsb);
6787                                 mutex_enter(&scsb->scsb_mutex);
6788                 }
6789                 cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error"
6790                     " reading Reset regs\n",
6791                     ddi_driver_name(scsb->scsb_dev),
6792                     ddi_get_instance(scsb->scsb_dev));
6793                 error = DDI_FAILURE;
6794         }
6795 
6796         DEBUG2("pre-reset regs = %x,%x\n", scsb->scsb_data_reg[index],
6797             scsb->scsb_data_reg[index+1]);
6798         if ((reset_flag == SCSB_GET_SLOT_RESET_STATUS) || (error)) {
6799                 mutex_exit(&scsb->scsb_mutex);
6800                 scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6801                 return (error);
6802         }
6803 
6804         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
6805             SCSB_FRU_OP_GET_BITVAL);
6806         if (alarm_card) {
6807                 ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE,
6808                     SCSB_FRU_OP_GET_BITVAL);
6809         }
6810         if (val && (reset_flag == SCSB_RESET_SLOT)) {
6811                 if (alarm_card) {
6812                         if (ac_val) {
6813                                 condition_exists = 1;
6814                                 DEBUG0("Alarm_RST# already active.\n");
6815                         }
6816 #ifndef lint
6817                         else
6818                                 DEBUG1("Alarm_RST# not active! "
6819                                     "Slot%d_RST# active!\n", pslotnum);
6820 #endif
6821                 } else {
6822                         condition_exists = 1;
6823                         DEBUG1("Slot%d_RST# already active!\n", pslotnum);
6824                 }
6825         }
6826         else
6827                 if ((val == 0) && (reset_flag == SCSB_UNRESET_SLOT)) {
6828                         if (alarm_card) {
6829                                 if (!ac_val) {
6830                                         DEBUG0("Alarm_RST# not active.\n");
6831                                         condition_exists = 1;
6832                                 }
6833 #ifndef lint
6834                                 else
6835                                         DEBUG1("Alarm_RST# active"
6836                                             " Slot%d_RST# not active!\n",
6837                                             pslotnum);
6838 #endif
6839                         } else {
6840                                 condition_exists = 1;
6841                                 DEBUG1("Slot%d_RST# already not active!\n",
6842                                     pslotnum);
6843                         }
6844                 }
6845 
6846         if (! condition_exists) {
6847                 i2cxferp->i2c_flags = I2C_WR;
6848                 i2cxferp->i2c_wlen = 2;
6849                 i2cxferp->i2c_wbuf[0] = scsb_fru_op(scsb, SLOT, slotnum,
6850                     SCTRL_RESET_BASE, SCSB_FRU_OP_GET_REG);
6851                 if (reset_flag == SCSB_RESET_SLOT) {
6852                         i2cxferp->i2c_wbuf[1] =
6853                             scsb_fru_op(scsb, SLOT, slotnum,
6854                             SCTRL_RESET_BASE,
6855                             SCSB_FRU_OP_GET_REGDATA) |
6856                             scsb_fru_op(scsb, SLOT, slotnum,
6857                             SCTRL_RESET_BASE,
6858                             SCSB_FRU_OP_SET_REGBIT);
6859 #ifdef  DEBUG           /* dont reset Alarm Card line unless in debug mode */
6860                         if (alarm_card)
6861                                 i2cxferp->i2c_wbuf[1] |=
6862                                     scsb_fru_op(scsb, ALARM, 1,
6863                                     SCTRL_RESET_BASE,
6864                                     SCSB_FRU_OP_SET_REGBIT);
6865 #endif
6866                 } else {
6867                         i2cxferp->i2c_wbuf[1] =
6868                             scsb_fru_op(scsb, SLOT, slotnum,
6869                             SCTRL_RESET_BASE,
6870                             SCSB_FRU_OP_GET_REGDATA) &
6871                             ~(scsb_fru_op(scsb, SLOT, slotnum,
6872                             SCTRL_RESET_BASE,
6873                             SCSB_FRU_OP_SET_REGBIT));
6874 #ifdef  DEBUG           /* dont Unreset Alarm Card line unless in debug mode */
6875                         if (alarm_card)
6876                                 i2cxferp->i2c_wbuf[1] &=
6877                                     scsb_fru_op(scsb, ALARM, 1,
6878                                     SCTRL_RESET_BASE,
6879                                     SCSB_FRU_OP_SET_REGBIT);
6880 #endif
6881                 }
6882 
6883                 if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
6884                         scsb->scsb_i2c_errcnt++;
6885                         if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
6886                                 scsb->scsb_err_flag = B_TRUE; /* latch error */
6887                         mutex_exit(&scsb->scsb_mutex);
6888                         if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
6889                                 if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
6890                                         scsb_freeze(scsb);
6891                         }
6892                         cmn_err(CE_WARN, "%s#%d: reset_slot: error writing to"
6893                             " Reset regs (op=%d, data=%x)\n",
6894                             ddi_driver_name(scsb->scsb_dev),
6895                             ddi_get_instance(scsb->scsb_dev),
6896                             reset_flag, i2cxferp->i2c_wbuf[1]);
6897                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6898                         return (DDI_FAILURE);
6899                 }
6900 
6901                 scsb->scsb_i2c_errcnt = 0;
6902                 /* now read back and update our scsb structure */
6903                 i2cxferp->i2c_flags = I2C_WR_RD;
6904                 i2cxferp->i2c_rlen = SCTRL_RESET_NUMREGS;
6905                 i2cxferp->i2c_wbuf[0] = reg;
6906                 i2cxferp->i2c_wlen = 1;
6907                 if ((error = nct_i2c_transfer(scsb->scsb_phandle,
6908                     i2cxferp)) == 0) {
6909                         scsb->scsb_i2c_errcnt = 0;
6910                         scsb->scsb_data_reg[index]   = i2cxferp->i2c_rbuf[0];
6911                         scsb->scsb_data_reg[index+1] = i2cxferp->i2c_rbuf[1];
6912                 } else {
6913                         scsb->scsb_i2c_errcnt++;
6914                         if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
6915                                 scsb->scsb_err_flag = B_TRUE; /* latch error */
6916                         mutex_exit(&scsb->scsb_mutex);
6917                         if (!(scsb->scsb_state & SCSB_SSB_PRESENT)) {
6918                                 if (scsb->scsb_i2c_errcnt >= scsb_freeze_count)
6919                                         scsb_freeze(scsb);
6920                         }
6921                         cmn_err(CE_WARN, "%s#%d: scsb_reset_slot: error"
6922                             " reading Reset regs (post reset)\n",
6923                             ddi_driver_name(scsb->scsb_dev),
6924                             ddi_get_instance(scsb->scsb_dev));
6925                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6926                         return (DDI_FAILURE);
6927                 }
6928                 /* XXX: P1.5 */
6929                 DEBUG2("post-reset regs = %x,%x\n", scsb->scsb_data_reg[index],
6930                     scsb->scsb_data_reg[index+1]);
6931                 val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_RESET_BASE,
6932                     SCSB_FRU_OP_GET_BITVAL);
6933 #ifdef  DEBUG
6934                 if (alarm_card)
6935                         ac_val = scsb_fru_op(scsb, ALARM, 1, SCTRL_RESET_BASE,
6936                             SCSB_FRU_OP_GET_BITVAL);
6937 #endif
6938                 if (val && (reset_flag == SCSB_UNRESET_SLOT)) {
6939                         cmn_err(CE_WARN, "Cannot UnReset Slot %d (reg=%x)\n",
6940                             pslotnum,
6941                             scsb_fru_op(scsb, SLOT, slotnum,
6942                             SCTRL_RESET_BASE,
6943                             SCSB_FRU_OP_GET_REGDATA));
6944 #ifdef  DEBUG
6945                         if (alarm_card) {
6946                                 if (ac_val)
6947                                         cmn_err(CE_WARN, "Cannot Unreset "
6948                                             "Alarm_RST#.\n");
6949                         }
6950 #endif
6951                 }
6952                 else
6953                         if ((val == 0) && (reset_flag == SCSB_RESET_SLOT)) {
6954                                 cmn_err(CE_WARN, "Cannot Reset Slot %d, "
6955                                     "reg=%x\n", pslotnum,
6956                                     scsb_fru_op(scsb, SLOT, slotnum,
6957                                     SCTRL_RESET_BASE,
6958                                     SCSB_FRU_OP_GET_REGDATA));
6959 #ifdef  DEBUG
6960                                 if (alarm_card) {
6961                                         if (!ac_val)
6962                                                 cmn_err(CE_WARN, "Cannot reset "
6963                                                     "Alarm_RST#.\n");
6964                                 }
6965 #endif
6966                         }
6967         }
6968 
6969         mutex_exit(&scsb->scsb_mutex);
6970         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
6971 
6972         return (error);
6973 }
6974 
6975 int
6976 scsb_connect_slot(scsb_state_t *scsb, int pslotnum, int healthy)
6977 {
6978         int slotnum, count = 0, val;
6979         int slot_flag = 0;
6980 
6981         /*
6982          * If Power needs to be handled, it should be done here.
6983          * Since there is no power handling for now, lets disable
6984          * reset, wait for healthy to come on and then call it
6985          * connected.
6986          * If HLTHY# does not come on (in how long is the question)
6987          * then we stay disconnected.
6988          */
6989         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
6990 
6991         /*
6992          * P1.5 doesnt require polling healthy as we get an
6993          * interrupt. So we could just update our state as disconnected
6994          * and return waiting for the healthy# interrupt. To make it
6995          * more efficient, lets poll for healthy# a short while since we are
6996          * in the interrupt context anyway. If we dont get a healthy# we
6997          * return, and then wait for the interrupt. Probably the warning
6998          * message needs to be removed then. Need a PROM check flag here.
6999          */
7000         while ((healthy == B_FALSE) && (count < scsb_healthy_poll_count)) {
7001                 if (scsb_read_bhealthy(scsb) != 0)
7002                         return (DDI_FAILURE);
7003                 val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
7004                     SCSB_FRU_OP_GET_BITVAL);
7005                 if (val) {
7006                         healthy = B_TRUE;
7007                         break;
7008                 }
7009                 count++;
7010                 drv_usecwait(100);      /* cant delay(9f) in intr context */
7011         }
7012 
7013         if (healthy == B_FALSE && count == scsb_healthy_poll_count) {
7014                 if (scsb_debug & 0x00004000)
7015                         cmn_err(CE_WARN, "%s#%d: no HEALTHY# signal on"
7016                             " slot %d", ddi_driver_name(scsb->scsb_dev),
7017                             ddi_get_instance(scsb->scsb_dev), pslotnum);
7018         }
7019 
7020         if ((scsb_is_alarm_card_slot(scsb, pslotnum) == B_TRUE) &&
7021             (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES))
7022                 slot_flag = ALARM_CARD_ON_SLOT;
7023         return (hsc_slot_occupancy(pslotnum, 1, slot_flag, healthy));
7024 }
7025 
7026 int
7027 scsb_disconnect_slot(scsb_state_t *scsb, int occupied, int slotnum)
7028 {
7029         int slot_flag = 0;
7030 
7031         /* Reset is must at extraction. Move on even if failure. */
7032         if (scsb_reset_slot(scsb, slotnum, SCSB_RESET_SLOT) != 0) {
7033                 /*
7034                  * If board is still in slot, which means there is a manual
7035                  * disconnection in progress, return failure.
7036                  * Otherwise, a board was removed anyway; so we need to
7037                  * update the status and move on.
7038                  */
7039                 if (occupied == B_TRUE)
7040                         return (DDI_FAILURE);
7041         }
7042         /*
7043          * the following bug needs to be fixed.
7044          * When this function is called from scsb_intr, scsb_state already
7045          * clears the 'AC card present' bit.
7046          * However, hsc module doesn't depend on slot_flag during removal.
7047          */
7048         if ((scsb_is_alarm_card_slot(scsb, slotnum) == B_TRUE) &&
7049             (scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES))
7050                 slot_flag = ALARM_CARD_ON_SLOT;
7051         return (hsc_slot_occupancy(slotnum, occupied, slot_flag, B_FALSE));
7052 }
7053 
7054 static int
7055 scsb_is_alarm_card_slot(scsb_state_t *scsb, int slotnum)
7056 {
7057         return ((scsb->ac_slotnum == slotnum)? B_TRUE:B_FALSE);
7058 }
7059 
7060 /*
7061  * Invoked both by the hsc and the scsb module to exchanges necessary
7062  * information regarding the alarm card.
7063  * scsb calls this function to unconfigure the alarm card while the
7064  * hsc calls this function at different times to check busy status,
7065  * and during post hotswap insert operation so that the user process
7066  * if one waiting can configure the alarm card.
7067  */
7068 int
7069 scsb_hsc_ac_op(scsb_state_t *scsb, int pslotnum, int op)
7070 {
7071         int             rc = B_FALSE;
7072         uint32_t        event_code;
7073 
7074         if (!(scsb->scsb_hsc_state & SCSB_HSC_INIT &&
7075             scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES)) {
7076                 cmn_err(CE_WARN,
7077                     "scsb: HSC not initialized or AC not present!");
7078                 return (rc);
7079         }
7080         switch (op) {
7081                 /* hsc -> scsb */
7082                 case SCSB_HSC_AC_BUSY:
7083                         if (scsb->scsb_hsc_state & SCSB_ALARM_CARD_IN_USE)
7084                                 rc = B_TRUE;
7085                         break;
7086 
7087                 /* API -> scsb */
7088                 /*
7089                  * NOTE: this could be called multiple times from envmond if
7090                  * the daemon is reinitialized with SIGHUP, or stopped and
7091                  * restarted.
7092                  */
7093                 case SCSB_HSC_AC_SET_BUSY:
7094                         DEBUG0("AC SET BUSY\n");
7095                         if (scsb_debug & 0x00010000) {
7096                                 cmn_err(CE_NOTE,
7097                                     "scsb_hsc_ac_op(SCSB_HSC_AC_SET_BUSY)");
7098                         }
7099                         scsb->scsb_hsc_state |= SCSB_ALARM_CARD_IN_USE;
7100                         rc = B_TRUE;
7101                         break;
7102 
7103                 /* hsc -> scsb */
7104                 case SCSB_HSC_AC_CONFIGURED:
7105                         DEBUG0("AC configured\n");
7106                         if (scsb_debug & 0x00010000) {
7107                                 cmn_err(CE_NOTE,
7108                                 "scsb_hsc_ac_op(SCSB_HSC_AC_CONFIGURED)");
7109                         }
7110                         /*
7111                          * wakeup anyone waiting on AC to be configured
7112                          * Send the ALARM_CARD_CONFIGURE Event to all scsb
7113                          * open streams.
7114                          */
7115                         event_code = SCTRL_EVENT_ALARM_INSERTION;
7116                         (void) scsb_queue_ops(scsb, QPUT_INT32, 1,
7117                             &event_code, "scsb_hsc_ac_op");
7118                         rc = B_TRUE;
7119                         break;
7120 
7121                 /* hsc -> scsb */
7122                 case SCSB_HSC_AC_REMOVAL_ALERT:
7123                         DEBUG0("AC removal alert\n");
7124                         if (scsb_debug & 0x00010000) {
7125                                 cmn_err(CE_NOTE,
7126                                 "scsb_hsc_ac_op(SCSB_HSC_AC_REMOVAL_ALERT)");
7127                         }
7128                         /*
7129                          * Inform (envmond)alarmcard.so that it should save
7130                          * the AC configuration, stop the
7131                          * heartbeat, and shutdown the RSC link.
7132                          */
7133                         event_code = SCTRL_EVENT_ALARM_REMOVAL;
7134                         (void) scsb_queue_ops(scsb, QPUT_INT32, 1,
7135                             &event_code, "scsb_hsc_ac_op");
7136                         rc = B_TRUE;
7137                         break;
7138 
7139                 /* API -> scsb -> hsc */
7140                 case SCSB_HSC_AC_UNCONFIGURE:
7141                         DEBUG0("AC unconfigure\n");
7142                         if (scsb_debug & 0x00010000) {
7143                                 cmn_err(CE_NOTE,
7144                                     "scsb_hsc_ac_op(SCSB_HSC_AC_UNCONFIG"
7145                                     "URE), AC NOT BUSY");
7146                         }
7147                         /*
7148                          * send notification back to HSC to
7149                          * unconfigure the AC, now that the env monitor
7150                          * has given permission to do so.
7151                          */
7152                         scsb->scsb_hsc_state &= ~SCSB_ALARM_CARD_IN_USE;
7153                         hsc_ac_op((int)scsb->scsb_instance, pslotnum,
7154                             SCSB_HSC_AC_UNCONFIGURE, NULL);
7155                         rc = B_TRUE;
7156                         break;
7157                 default:
7158                         break;
7159         }
7160 
7161         return (rc);
7162 }
7163 
7164 static void
7165 scsb_healthy_intr(scsb_state_t *scsb, int pslotnum)
7166 {
7167         int val, slotnum;
7168         int healthy = B_FALSE;
7169 
7170         DEBUG1("Healthy Intr on slot %d\n", pslotnum);
7171         /*
7172          * The interrupt source register can have the healthy
7173          * bit set for non-existing slot, e.g slot 7 on Tonga.
7174          * It can also be seen on the Tonga CPU slot. So we make
7175          * sure we have a valid slot before proceeding.
7176          */
7177         if (scsb->scsb_state & SCSB_IS_TONGA) {
7178                 if (pslotnum > TG_MAX_SLOTS || pslotnum == SC_TG_CPU_SLOT) {
7179                         if (scsb_debug & 0x08000000)
7180                                 cmn_err(CE_NOTE, "Healthy interrupt bit set for"
7181                                     " slot %d", pslotnum);
7182                 return;
7183                 }
7184         } else {
7185                 if (pslotnum > MC_MAX_SLOTS || pslotnum == SC_MC_CPU_SLOT ||
7186                     (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
7187                     pslotnum == SC_MC_CTC_SLOT)) {
7188                         if (scsb_debug & 0x08000000)
7189                                 cmn_err(CE_NOTE, "Healthy interrupt bit set for"
7190                                     " slot %d", pslotnum);
7191                 return;
7192                 }
7193         }
7194 
7195         /*
7196          * The board healthy registers are already read before entering
7197          * this routine
7198          */
7199         slotnum = tonga_psl_to_ssl(scsb, pslotnum);
7200 
7201         /*
7202          * P1.5. Following works since slots 1 through 8 are in the same reg
7203          */
7204         val = scsb_fru_op(scsb, SLOT, slotnum, SCTRL_BHLTHY_BASE,
7205             SCSB_FRU_OP_GET_BITVAL);
7206         if (val)
7207                 healthy = B_TRUE;
7208         (void) scsb_hsc_board_healthy(pslotnum, healthy);
7209 }
7210 
7211 /*
7212  * This function will try to read from scsb irrespective of whether
7213  * SSB is present or SCB is frozen, to get the health kstat information.
7214  */
7215 static int
7216 scsb_blind_read(scsb_state_t *scsb, int op, uchar_t reg, int len,
7217                                 uchar_t *rwbuf, int i2c_alloc)
7218 {
7219         i2c_transfer_t  *i2cxferp;
7220         int             i, rlen, wlen, error = 0;
7221 
7222         if (scsb_debug & 0x0800) {
7223                 cmn_err(CE_NOTE, "scsb_rdwr_register(scsb,%s,%x,%x,buf):",
7224                     (op == I2C_WR) ? "write" : "read",  reg, len);
7225         }
7226 
7227         if (i2c_alloc) {
7228                 i2cxferp = scsb_alloc_i2ctx(scsb->scsb_phandle, I2C_NOSLEEP);
7229                 if (i2cxferp == NULL) {
7230                         if (scsb_debug & 0x0042)
7231                                 cmn_err(CE_WARN, "scsb_rdwr_register: "
7232                                     "i2ctx allocation failure");
7233                         return (ENOMEM);
7234                 }
7235         } else {
7236                 i2cxferp = scsb->scsb_i2ctp;
7237         }
7238         switch (op) {
7239         case I2C_WR:
7240                 wlen = len + 1; /* add the address */
7241                 rlen = 0;
7242                 i2cxferp->i2c_wbuf[0] = reg;
7243                 for (i = 0; i < len; ++i) {
7244                                 i2cxferp->i2c_wbuf[1 + i] = rwbuf[i];
7245                         if (scsb_debug & 0x0080)
7246                                 cmn_err(CE_NOTE,
7247                                 "scsb_rdwr_register: writing rwbuf[%d]=0x%x",
7248                                     i, rwbuf[i]);
7249                 }
7250                 break;
7251         case I2C_WR_RD:
7252                 wlen = 1;       /* for the address */
7253                 rlen = len;
7254                 i2cxferp->i2c_wbuf[0] = reg;
7255                 break;
7256         default:
7257                 if (i2c_alloc)
7258                         scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
7259                 return (EINVAL);
7260         }
7261         /* select the register address */
7262         i2cxferp->i2c_flags = op;
7263         i2cxferp->i2c_rlen = rlen;
7264         i2cxferp->i2c_wlen = wlen;
7265         i2cxferp->i2c_wbuf[0] = reg;
7266         scsb->scsb_kstat_flag = B_TRUE;      /* we did a i2c transaction */
7267         if (error = nct_i2c_transfer(scsb->scsb_phandle, i2cxferp)) {
7268                 error = EIO;
7269         } else if (rlen) {
7270                 /* copy to rwbuf[] */
7271                 for (i = 0; i < len; ++i) {
7272                         rwbuf[i] = i2cxferp->i2c_rbuf[i];
7273                         if (scsb_debug & 0x0080)
7274                                 cmn_err(CE_NOTE,
7275                                 "scsb_rdwr_register: read rwbuf[%d]=0x%x",
7276                                     i, rwbuf[i]);
7277                 }
7278         }
7279         if (i2c_alloc)
7280                 scsb_free_i2ctx(scsb->scsb_phandle, i2cxferp);
7281         if (error) {
7282                 scsb->scsb_i2c_errcnt++;
7283                 if (scsb->scsb_i2c_errcnt > scsb_err_threshold)
7284                         scsb->scsb_err_flag = B_TRUE; /* latch error */
7285         } else {
7286                 scsb->scsb_i2c_errcnt = 0;
7287         }
7288 
7289         return (error);
7290 }
7291 
7292 /*
7293  * This function will quiesce the PSM_INT line by masking the
7294  * global PSM_INT and writing 1 to SCB_INIT ( for P1.5 and later )
7295  * This effectively translates to writing 0x20 to 0xE1 register.
7296  */
7297 static int
7298 scsb_quiesce_psmint(scsb_state_t *scsb)
7299 {
7300         register int    i;
7301         uchar_t reg, wdata = 0;
7302         uchar_t tmp_reg, intr_addr, clr_bits = 0;
7303         int error, iid, intr_idx, offset;
7304 
7305         /*
7306          * For P1.5, set the SCB_INIT bit in the System Command register,
7307          * and disable global PSM_INT. Before this we need to read the
7308          * interrupt source register corresponding to INIT_SCB and
7309          * clear if set.
7310          */
7311         if (IS_SCB_P15) {
7312                 /*
7313                  * Read INTSRC6 and write back 0x20 in case INIT_SCB is set
7314                  */
7315                 intr_addr = SCSB_REG_ADDR(SCTRL_INTSRC_BASE);
7316                 tmp_reg = SCSB_REG_ADDR(SCTRL_INTSRC_SCB_P15);
7317                 iid = SCSB_REG_INDEX(intr_addr);
7318                 intr_idx = SCSB_REG_INDEX(tmp_reg) - iid;
7319                 offset = FRU_OFFSET(SCTRL_EVENT_SCB, SCTRL_INTPTR_BASE);
7320                 clr_bits = 1 << offset;
7321 
7322                 error = scsb_rdwr_register(scsb, I2C_WR_RD, tmp_reg,
7323                     1, &scb_intr_regs[intr_idx], 0);
7324                 /*
7325                  * Now mask the global PSM_INT and write INIT_SCB in case
7326                  * this is an INIT_SCB interrupt
7327                  */
7328                 wdata = 1 << SYS_OFFSET(SCTRL_SYS_SCB_INIT);
7329                 i = SYS_REG_INDEX(SCTRL_SYS_SCB_INIT, SCTRL_SYS_CMD_BASE);
7330                 reg = SCSB_REG_ADDR(i);
7331                 error = scsb_rdwr_register(scsb, I2C_WR, reg, 1,
7332                     &wdata, 0);
7333 
7334                 if (scb_intr_regs[intr_idx] & clr_bits) {
7335                         /*
7336                          * There is an SCB_INIT interrupt, which we must clear
7337                          * first to keep SCB_INIT from keeping PSM_INT asserted.
7338                          */
7339                         error = scsb_rdwr_register(scsb, I2C_WR, tmp_reg,
7340                             1, &clr_bits, 0);
7341                 }
7342 
7343                 if (error) {
7344                         cmn_err(CE_WARN, "scsb%d:scsb_quiesce_psmint: "
7345                             " I2C TRANSFER Failed", scsb->scsb_instance);
7346                         if (scsb_debug & 0x0006) {
7347                                 cmn_err(CE_NOTE, "scsb_attach: "
7348                                     " failed to set SCB_INIT");
7349                         }
7350                 }
7351                 scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED;
7352         } else { /* P1.0 or earlier */
7353                 /*
7354                  * read the interrupt source registers, and then
7355                  * write them back.
7356                  */
7357                 /* read the interrupt register from scsb */
7358                 if (error = scsb_rdwr_register(scsb, I2C_WR_RD, intr_addr,
7359                     SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) {
7360                         cmn_err(CE_WARN, "scsb_intr: "
7361                             " Failed read of interrupt registers.");
7362                         scsb->scsb_state &= ~SCSB_IN_INTR;
7363                 }
7364 
7365                 /*
7366                  * Write to the interrupt source registers to stop scsb
7367                  * from interrupting.
7368                  */
7369                 if (error = scsb_rdwr_register(scsb, I2C_WR, intr_addr,
7370                     SCTRL_INTR_NUMREGS, scb_intr_regs, 0)) {
7371                         cmn_err(CE_WARN, "scsb_intr: Failed write to interrupt"
7372                             " registers.");
7373                         scsb->scsb_state &= ~SCSB_IN_INTR;
7374                 }
7375 
7376         }
7377 
7378         if (error)
7379                 return (DDI_FAILURE);
7380         else
7381                 return (DDI_SUCCESS);
7382 }
7383 
7384 /*
7385  * Enables or disables the global PSM_INT interrupt for P1.5, depending
7386  * on the flag, flag = 0 => disable, else enable.
7387  */
7388 static int
7389 scsb_toggle_psmint(scsb_state_t *scsb, int enable)
7390 {
7391         int i;
7392         uchar_t reg, on = 0, rmask = 0x0, off = 0;
7393 
7394         if (enable == B_TRUE) {
7395                 on = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
7396         } else {
7397                 off = 1 << SYS_OFFSET(SCTRL_SYS_PSM_INT_ENABLE);
7398         }
7399 
7400         i = SYS_REG_INDEX(SCTRL_SYS_PSM_INT_ENABLE, SCTRL_SYS_CMD_BASE);
7401         reg = SCSB_REG_ADDR(i);
7402         if (scsb_write_mask(scsb, reg, rmask, on, off)) {
7403                 cmn_err(CE_WARN, "scsb_toggle_psmint: Cannot turn %s PSM_INT",
7404                     enable == 1 ? "on" : "off");
7405                 return (DDI_FAILURE);
7406         }
7407         if (enable == 0) {
7408                 scsb->scsb_state &= ~SCSB_PSM_INT_ENABLED;
7409         } else {
7410                 scsb->scsb_state |= SCSB_PSM_INT_ENABLED;
7411         }
7412 
7413         return (DDI_SUCCESS);
7414 }
7415 
7416 /*
7417  * This routine is to be used by all the drivers using this i2c bus
7418  * to synchronize their transfer operations.
7419  */
7420 int
7421 nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran)
7422 {
7423         int retval, initmux = nct_mutex_init;
7424 
7425         /*
7426          * If scsb interrupt mutex is initialized, also hold the
7427          * interrupt mutex to let the i2c_transfer() to complete
7428          */
7429 
7430         if (initmux & MUTEX_INIT) {
7431                 mutex_enter(scb_intr_mutex);
7432         }
7433 
7434         retval = i2c_transfer(i2c_hdl, i2c_tran);
7435 
7436         if (initmux & MUTEX_INIT) {
7437                 mutex_exit(scb_intr_mutex);
7438         }
7439 
7440         return (retval);
7441 }