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  * MonteCarlo HotSwap Controller functionality
  29  */
  30 
  31 #include        <sys/types.h>
  32 #include        <sys/stropts.h>
  33 #include        <sys/stream.h>
  34 #include        <sys/strsun.h>
  35 #include        <sys/kmem.h>
  36 #include        <sys/cmn_err.h>
  37 #include        <sys/errno.h>
  38 #include        <sys/cpuvar.h>
  39 #include        <sys/open.h>
  40 #include        <sys/stat.h>
  41 #include        <sys/conf.h>
  42 #include        <sys/ddi.h>
  43 #include        <sys/sunddi.h>
  44 #include        <sys/modctl.h>
  45 #include        <sys/promif.h>
  46 #include        <sys/hotplug/hpcsvc.h>
  47 
  48 #include        <sys/hscimpl.h>
  49 #include        <sys/hsc.h>
  50 
  51 #include        <sys/mct_topology.h>
  52 #include        <sys/scsbioctl.h>
  53 #include        <sys/scsb.h>
  54 
  55 #define HOTSWAP_MODE_PROP       "hotswap-mode"
  56 #define ALARM_CARD_ON_SLOT      1
  57 #define SCSB_HSC_FORCE_REMOVE   1       /* force remove enum intr handler */
  58 
  59 /* TUNABLE PARAMETERS. Some are Debug Only. Please take care when using. */
  60 
  61 /*
  62  * Set this flag to 1, to enable full hotswap mode at boot time.
  63  * Since HPS is threaded, it is not recommended that we set this flag
  64  * to 1 because enabling full hotswap interrupt can invoke the ENUM
  65  * event handler accessing the slot data structure which may have not
  66  * been initialized in the hotplug framework since the HPS may not yet
  67  * have called the slot registration function with the bus nexus.
  68  */
  69 static int      scsb_hsc_enable_fhs = 0;
  70 
  71 /*
  72  * Every time  a slot is registered with the hotswap framework, the
  73  * framework calls back. This variable keeps a count on how many
  74  * callbacks are done.
  75  */
  76 static int scsb_hsc_numReg = 0;
  77 /*
  78  * When this flag is set, the board is taken offline (put in reset) after
  79  * a unconfigure operation, in Basic Hotswap mode.
  80  */
  81 static int      scsb_hsc_bhs_slot_reset = 1;
  82 /*
  83  * When this flag is set, we take the board to reset after unconfigure
  84  * operation when operating in full hotswap mode.
  85  */
  86 static int      scsb_hsc_fhs_slot_reset = 1;
  87 /*
  88  * Implementation of this counter will work only on Montecarlo since
  89  * the ENUM# Interrupt line is not shared with other interrupts.
  90  * When the hardware routing changes, then there may be need to remove
  91  * or change this functionality.
  92  * This functionality is provided so that a bad or non friendly full hotswap
  93  * board does not hang the system in full hotswap mode. Atleast the
  94  * intent is that! Eventually Solaris kernel will provide similar support
  95  * for recovering from a stuck interrupt line. Till then, lets do this.
  96  */
  97 static int      scsb_hsc_max_intr_count = 8;
  98 /*
  99  * Since the hardware does not support enabling/disabling ENUM#, the
 100  * following flag can be used for imitating that behaviour.
 101  * Currently we can set this flag and use the remove op to remove the
 102  * interrupt handler from the system. Care must be taken when using this
 103  * function since trying to remove the interrupt handler when the interrupts
 104  * are pending may hang the system permanently.
 105  * Since the hardware does not support this functionality, we adopt this
 106  * approach for debugs.
 107  */
 108 static int      scsb_hsc_enum_switch = 0;
 109 
 110 /*
 111  * When the board loses Healthy# at runtime (with the board being configured),
 112  * cPCI specs states that a Reset has to be asserted immediately.
 113  * We dont do this currently, until satellite processor support is given
 114  * and the implications of such a act is fully understood.
 115  * To adopt the cPCI specs recommendation, set this flag to 1.
 116  */
 117 static  int     scsb_hsc_healthy_reset = 0;
 118 
 119 /*
 120  * According to PCI 2.2 specification, once a board comes out of PCI_RST#,
 121  * it may take upto 2^25 clock cycles to respond to config cycles. For
 122  * montecarlo using a 33MHz cPCI bus, it's around 1.024 s. The variable
 123  * will specify the time in ms to wait before attempting config access.
 124  */
 125 static  int scsb_connect_delay = 1025;
 126 
 127 /*
 128  * slot map property for MC should be
 129  *
 130  *      hsc-slot-map="/pci@1f,0/pci@1/pci@1","15","2",
 131  *               "/pci@1f,0/pci@1/pci@1","14","3",
 132  *               "/pci@1f,0/pci@1/pci@1","13","4",
 133  *               "/pci@1f,0/pci@1/pci@1","12","5"
 134  *               "/pci@1f,0/pci@1/pci@1","11","6"
 135  *               "/pci@1f,0/pci@1/pci@1","10","7"
 136  *               "/pci@1f,0/pci@1/pci@1","8","8";
 137  *
 138  * slot map property for Tonga should be
 139  *      hsc-slot-map="/pci@1f,0/pci@1/pci@1","8","1"
 140  *              "/pci@1f,0/pci@1/pci@1", "15", "2"
 141  *              "/pci@1f,0/pci@1/pci@1", "14", "4"
 142  *              "/pci@1f,0/pci@1/pci@1", "13", "5"
 143  *
 144  * Please note that the CPU slot number is 3 for Tonga.
 145  */
 146 
 147 /*
 148  * Services we require from the SCSB
 149  */
 150 extern int      scsb_get_slot_state(void *, int, int *);
 151 extern int      scsb_read_bhealthy(scsb_state_t *scsb);
 152 extern int      scsb_read_slot_health(scsb_state_t *scsb, int pslotnum);
 153 extern int      scsb_connect_slot(void *, int, int);
 154 extern int      scsb_disconnect_slot(void *, int, int);
 155 
 156 static void     *hsc_state;
 157 
 158 static uint_t   hsc_enum_intr(char *);
 159 static hsc_slot_t *hsc_get_slot_info(hsc_state_t *, int);
 160 static int      scsb_enable_enum(hsc_state_t *);
 161 static int      scsb_disable_enum(hsc_state_t *, int);
 162 static int      atoi(const char *);
 163 static int      isdigit(int);
 164 static hsc_slot_t *hsc_find_slot(int);
 165 static void     hsc_led_op(hsc_slot_t *, int, hpc_led_t, hpc_led_state_t);
 166 static int      hsc_led_state(hsc_slot_t *, int, hpc_led_info_t *);
 167 static int      scsb_hsc_disable_slot(hsc_slot_t *);
 168 static int      scsb_hsc_enable_slot(hsc_slot_t *);
 169 #ifndef lint
 170 static int hsc_clear_all_enum(hsc_state_t *);
 171 #endif
 172 static int      hsc_slot_register(hsc_state_t *, char *, uint16_t, uint_t,
 173                                         boolean_t);
 174 static int      hsc_slot_unregister(int);
 175 static int      scsb_hsc_init_slot_state(hsc_state_t *, hsc_slot_t *);
 176 static int      hsc_slot_autoconnect(hsc_slot_t *);
 177 
 178 static hpc_slot_ops_t   *hsc_slotops;
 179 static hsc_slot_t       *hsc_slot_list;         /* linked list of slots */
 180 
 181 /*
 182  * This mutex protects the following variables:
 183  *      hsc_slot_list
 184  */
 185 static kmutex_t         hsc_mutex;
 186 
 187 
 188 /* ARGSUSED */
 189 static int
 190 hsc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
 191 {
 192         hsc_slot_t *hsp = (hsc_slot_t *)ops_arg;
 193         int rc, rstate;
 194         hsc_state_t     *hsc;
 195 
 196         DEBUG2("hsc_connect: slot %d, healthy %d", hsp->hs_slot_number,
 197                                                 hsp->hs_board_healthy);
 198 
 199         if (!(hsp->hs_flags & (HSC_ENABLED|HSC_SLOT_ENABLED)))
 200                 return (HPC_ERR_FAILED);
 201         /* if SCB hotswapped, do not allow connect operations */
 202         if (hsp->hs_flags & HSC_SCB_HOTSWAPPED)
 203                 return (HPC_ERR_FAILED);
 204         /*
 205          * if previous occupant stayed configured, do not allow another
 206          * occupant to be connected.
 207          * This behaviour is an indication that the slot state
 208          * is not clean.
 209          */
 210         if (hsp->hs_flags & HSC_SLOT_BAD_STATE) {
 211                 /*
 212                  * In the current implementation, we turn both fault
 213                  * and active LEDs to ON state in this situation.
 214                  */
 215                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
 216                                                         HPC_LED_ON);
 217                 return (HPC_ERR_FAILED);
 218         }
 219         /*
 220          * Get the actual status from the i2c bus
 221          */
 222         rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number,
 223                                                                 &rstate);
 224         if (rc != DDI_SUCCESS)
 225                 return (HPC_ERR_FAILED);
 226 
 227         hsp->hs_slot_state = rstate;
 228         if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
 229 #ifdef DEBUG
 230                 cmn_err(CE_CONT,
 231                         "?hsc_connect: slot %d is empty\n",
 232                         hsp->hs_slot_number);
 233 #endif
 234                 return (HPC_ERR_FAILED);
 235         }
 236 
 237         if (hsp->hs_slot_state == HPC_SLOT_CONNECTED)
 238                 return (HPC_SUCCESS);
 239 
 240         rc = HPC_SUCCESS;
 241         /*
 242          * call scsb to connect the slot. This also makes sure board is healthy
 243          */
 244         if (scsb_connect_slot(hsp->hs_hpchandle, hsp->hs_slot_number,
 245                                 hsp->hs_board_healthy) != DDI_SUCCESS) {
 246                 DEBUG1("hsc_connect: slot %d connection failed",
 247                                 hsp->hs_slot_number);
 248                 rc = HPC_ERR_FAILED;
 249         } else {
 250                 if (hsp->hs_slot_state != HPC_SLOT_CONNECTED) {
 251                         if (hsp->hs_board_healthy == B_FALSE) {
 252                                 cmn_err(CE_NOTE, "HEALTHY# not asserted on "
 253                                         " slot %d", hsp->hs_slot_number);
 254                                 return (HPC_ERR_FAILED);
 255                         }
 256                         hsc = hsp->hsc;
 257                         hsc->hsp_last = hsp;
 258                         if (scsb_reset_slot(hsp->hs_hpchandle,
 259                                 hsp->hs_slot_number, SCSB_UNRESET_SLOT) != 0) {
 260 
 261                                 return (HPC_ERR_FAILED);
 262                         }
 263                         /*
 264                          * Unresetting a board may have caused an interrupt
 265                          * burst in case of non friendly boards. So it is
 266                          * important to make sure that the ISR has not
 267                          * put this board back to disconnect state.
 268                          */
 269                         delay(1);
 270                         if (hsp->hs_flags & HSC_ENUM_FAILED) {
 271                                 hsp->hs_flags &= ~HSC_ENUM_FAILED;
 272                                 return (HPC_ERR_FAILED);
 273                         }
 274                         DEBUG1("hsc_connect: slot %d connected",
 275                                                 hsp->hs_slot_number);
 276                         rc = HPC_SUCCESS;
 277                         hsp->hs_slot_state = HPC_SLOT_CONNECTED;
 278                         (void) hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
 279                                 HPC_FAULT_LED, HPC_LED_OFF);
 280                 }
 281         }
 282 
 283         /*
 284          * PCI 2.2 specs recommend that the probe software wait
 285          * for upto 2^25 PCI clock cycles after deassertion of
 286          * PCI_RST# before the board is able to respond to config
 287          * cycles. So, before we return, we wait for ~1 sec.
 288          */
 289         delay(drv_usectohz(scsb_connect_delay * 1000));
 290         return (rc);
 291 }
 292 
 293 
 294 /* ARGSUSED */
 295 static int
 296 hsc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
 297 {
 298         hsc_slot_t              *hsp = (hsc_slot_t *)ops_arg;
 299         hsc_state_t             *hsc;
 300 #ifdef  DEBUG
 301         static const char       func[] = "hsc_disconnect";
 302 #endif
 303 
 304         DEBUG1("hsc_disconnect: slot %d", hsp->hs_slot_number);
 305 
 306         if (hsp->hs_board_configured) {
 307 #ifdef  DEBUG
 308                 cmn_err(CE_NOTE,
 309                         "%s: cannot disconnect configured board in slot %d",
 310                         func, hsp->hs_slot_number);
 311 #endif
 312                 return (HPC_ERR_FAILED);
 313         }
 314 
 315         if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
 316 #ifdef  DEBUG
 317                 cmn_err(CE_NOTE, "%s: slot %d is empty",
 318                         func, hsp->hs_slot_number);
 319 #endif
 320                 return (HPC_SUCCESS);
 321         }
 322 
 323         if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
 324                 /*
 325                  * if already disconnected, just return success
 326                  * Duplicate disconnect messages should not be failed!
 327                  */
 328                 return (HPC_SUCCESS);
 329         }
 330         /* if SCB hotswapped, do not allow disconnect operations */
 331         if (hsp->hs_flags & HSC_SCB_HOTSWAPPED)
 332                 return (HPC_ERR_FAILED);
 333 
 334         /* call scsb to disconnect the slot */
 335         if (scsb_disconnect_slot(hsp->hs_hpchandle, B_TRUE, hsp->hs_slot_number)
 336                         != DDI_SUCCESS)
 337                 return (HPC_ERR_FAILED);
 338         hsc = hsp->hsc;
 339         if (hsc->hsp_last == hsp)
 340                 hsc->hsp_last = NULL;
 341 
 342         return (HPC_SUCCESS);
 343 }
 344 
 345 
 346 /*
 347  * In the cPCI world, this operation is not applicable.
 348  * However, we use this function to enable full hotswap mode in debug mode.
 349  */
 350 /* ARGSUSED */
 351 static int
 352 hsc_insert(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
 353 {
 354         hsc_slot_t              *hsp = (hsc_slot_t *)ops_arg;
 355 
 356         if (scsb_hsc_enum_switch &&
 357                         (scsb_enable_enum(hsp->hsc) == DDI_SUCCESS)) {
 358                 return (HPC_SUCCESS);
 359         }
 360         return (HPC_ERR_NOTSUPPORTED);
 361 }
 362 
 363 
 364 /*
 365  * In the cPCI world, this operation is not applicable.
 366  * However, we use this function to disable full hotswap mode in debug mode.
 367  */
 368 /* ARGSUSED */
 369 static int
 370 hsc_remove(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
 371 {
 372         hsc_slot_t              *hsp = (hsc_slot_t *)ops_arg;
 373 
 374         if (scsb_hsc_enum_switch &&
 375                         (scsb_disable_enum(hsp->hsc, SCSB_HSC_FORCE_REMOVE)
 376                                         == DDI_SUCCESS)) {
 377                 hsp->hs_flags &= ~HSC_ENUM_FAILED;
 378                 return (HPC_SUCCESS);
 379         }
 380         return (HPC_ERR_NOTSUPPORTED);
 381 }
 382 
 383 static void
 384 hsc_led_op(hsc_slot_t *hsp, int cmd, hpc_led_t led, hpc_led_state_t led_state)
 385 {
 386         hpc_led_info_t  ledinfo;
 387 
 388         ledinfo.led = led;
 389         ledinfo.state = led_state;
 390         (void) hsc_led_state(hsp, cmd, &ledinfo);
 391 }
 392 
 393 static int
 394 hsc_led_state(hsc_slot_t *hsp, int cmd, hpc_led_info_t *hlip)
 395 {
 396         hpc_led_state_t *hlsp;
 397         scsb_uinfo_t    sunit;
 398         int             res;
 399 
 400         DEBUG3("hsc_led_state: slot %d, led %x, state %x",
 401                 hsp->hs_slot_number, hlip->led, hlip->state);
 402 
 403         sunit.unit_type = SLOT;
 404         sunit.unit_number = hsp->hs_slot_number;
 405         /*
 406          * We ignore operations on LEDs that we don't support
 407          */
 408         switch (hlip->led) {
 409                 case HPC_FAULT_LED:
 410                         sunit.led_type = NOK;
 411                         hlsp = &hsp->hs_fault_led_state;
 412                         break;
 413                 case HPC_ACTIVE_LED:
 414                         sunit.led_type = OK;
 415                         hlsp = &hsp->hs_active_led_state;
 416                         break;
 417                 default:
 418                         return (HPC_ERR_NOTSUPPORTED);
 419         }
 420 
 421         switch (hlip->state) {
 422                 case HPC_LED_BLINK:
 423                         sunit.unit_state = BLINK;
 424                         if (hlip->led != HPC_ACTIVE_LED)
 425                                 return (HPC_ERR_NOTSUPPORTED);
 426                         break;
 427                 case HPC_LED_ON:
 428                         sunit.unit_state = ON;
 429                         break;
 430                 case HPC_LED_OFF:
 431                         sunit.unit_state = OFF;
 432                         break;
 433                 default:
 434                         break;
 435         }
 436 
 437         switch (cmd) {
 438         case HPC_CTRL_SET_LED_STATE:
 439                 res = scsb_led_set(hsp->hs_hpchandle, &sunit, sunit.led_type);
 440                 if (res != 0)
 441                         return (HPC_ERR_FAILED);
 442                 *hlsp = (hpc_led_state_t)sunit.unit_state;
 443                 break;
 444 
 445         case HPC_CTRL_GET_LED_STATE:
 446                 res = scsb_led_get(hsp->hs_hpchandle, &sunit, sunit.led_type);
 447                 if (res)
 448                         return (HPC_ERR_FAILED);
 449                 /* hlip->state = sunit.unit_state; */
 450                 break;
 451 
 452         default:
 453                 return (HPC_ERR_INVALID);
 454         }
 455 
 456         return (HPC_SUCCESS);
 457 
 458 }
 459 
 460 
 461 static int
 462 hsc_get_slot_state(hsc_slot_t *hsp, hpc_slot_state_t *hssp)
 463 {
 464         int rstate = 0;
 465         int rc;
 466 #ifdef  DEBUG
 467         int orstate;    /* original rstate */
 468 #endif
 469 
 470         DEBUG1("hsc_get_slot_state: slot %d", hsp->hs_slot_number);
 471         rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number,
 472                                                                 &rstate);
 473         if (rc != DDI_SUCCESS)
 474                 return (HPC_ERR_FAILED);
 475 #ifdef  DEBUG
 476         orstate = hsp->hs_slot_state;
 477 #endif
 478         hsp->hs_slot_state = rstate;
 479         switch (hsp->hs_slot_state) {
 480         case HPC_SLOT_EMPTY:
 481                 DEBUG0("empty");
 482                 break;
 483         case HPC_SLOT_CONNECTED:
 484                 DEBUG0("connected");
 485                 break;
 486         case HPC_SLOT_DISCONNECTED:
 487                 DEBUG0("disconnected");
 488                 break;
 489         }
 490 
 491         *hssp = hsp->hs_slot_state;
 492 
 493         /* doing get-state above may have caused a freeze operation */
 494         if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) &&
 495                         (rstate == HPC_SLOT_DISCONNECTED)) {
 496                 /* freeze puts disconnected boards to connected state */
 497                 *hssp = HPC_SLOT_CONNECTED;
 498 #if 0
 499                 /* in FHS, deassertion of reset may have configured the board */
 500                 if (hsp->hs_board_configured == B_TRUE) {
 501                         hsp->hs_slot_state = *hssp;
 502                 }
 503 #endif
 504         }
 505 #ifdef  DEBUG
 506         /* a SCB hotswap may have forced a state change on the receptacle */
 507         if (orstate != *hssp) {
 508                 cmn_err(CE_NOTE, "hsc_get_state: slot%d state change due"
 509                         " to SCB hotswap!", hsp->hs_slot_number);
 510         }
 511 #endif
 512         return (HPC_SUCCESS);
 513 }
 514 
 515 
 516 static int
 517 hsc_set_config_state(hsc_slot_t *hsp, int cmd)
 518 {
 519         hsc_state_t     *hsc = hsp->hsc;
 520 
 521         DEBUG1("hsc_set_config_state: slot %d", hsp->hs_slot_number);
 522 
 523         switch (cmd) {
 524         case HPC_CTRL_DEV_CONFIGURED:
 525                 /*
 526                  * Closing of the Ejector switch in configured/busy state can
 527                  * cause duplicate CONFIGURED messages to come down.
 528                  * Make sure our LED states are fine.
 529                  */
 530                 if (hsp->hs_board_configured == B_TRUE) {
 531                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
 532                                                                 HPC_LED_ON);
 533                         break;
 534                 }
 535                 hsp->hs_board_configured = B_TRUE;
 536                 hsp->hs_board_configuring = B_FALSE;
 537                 if ((hsc->state & HSC_ATTACHED) == HSC_ATTACHED &&
 538                         hsp->hs_flags & HSC_ALARM_CARD_PRES)
 539                         (void) scsb_hsc_ac_op(hsp->hs_hpchandle,
 540                                 hsp->hs_slot_number, SCSB_HSC_AC_CONFIGURED);
 541                 /* LED must be OFF on the occupant. */
 542                 (void) hpc_slot_event_notify(hsp->hs_slot_handle,
 543                                         HPC_EVENT_SLOT_BLUE_LED_OFF, 0);
 544                 if (hsp->hs_flags & HSC_AUTOCFG)
 545                         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
 546                                         HPC_EVENT_ENABLE_ENUM, 0);
 547                 else
 548                         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
 549                                         HPC_EVENT_DISABLE_ENUM, 0);
 550                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
 551                                                                 HPC_LED_ON);
 552                 if (hsc->hsp_last == hsp)
 553                         hsc->hsp_last = NULL;
 554                 break;
 555         case HPC_CTRL_DEV_UNCONFIGURED:
 556                 hsp->hs_board_configured = B_FALSE;
 557                 hsp->hs_board_unconfiguring = B_FALSE;
 558                 hsp->hs_flags &= ~HSC_SLOT_BAD_STATE;
 559                 if (hsp->hs_flags & HSC_ALARM_CARD_PRES)
 560                         (void) scsb_hsc_ac_op(hsp->hs_hpchandle,
 561                                 hsp->hs_slot_number, SCSB_HSC_AC_UNCONFIGURED);
 562                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
 563                                                         HPC_LED_BLINK);
 564                 if (((hsc->state & HSC_ENUM_ENABLED) &&
 565                         scsb_hsc_fhs_slot_reset) ||
 566                 (((hsc->state & HSC_ENUM_ENABLED) != HSC_ENUM_ENABLED) &&
 567                                 scsb_hsc_bhs_slot_reset) ||
 568                                 ((hsp->hs_flags & HSC_AUTOCFG) !=
 569                                         HSC_AUTOCFG)) {
 570                         if (scsb_reset_slot(hsp->hs_hpchandle,
 571                                 hsp->hs_slot_number, SCSB_RESET_SLOT) == 0) {
 572 
 573                                 hsp->hs_slot_state = HPC_SLOT_DISCONNECTED;
 574                                 hsp->hs_board_healthy = B_FALSE;
 575                                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
 576                                         HPC_FAULT_LED, HPC_LED_ON);
 577                         }
 578                 }
 579                 break;
 580         case HPC_CTRL_DEV_CONFIG_FAILURE:
 581                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
 582                                                         HPC_LED_BLINK);
 583                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
 584                                 HPC_FAULT_LED, HPC_LED_ON);
 585                 break;
 586         case HPC_CTRL_DEV_UNCONFIG_FAILURE:
 587                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
 588                                                         HPC_LED_ON);
 589                 break;
 590         case HPC_CTRL_DEV_CONFIG_START:
 591         case HPC_CTRL_DEV_UNCONFIG_START:
 592                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
 593                                         HPC_LED_OFF);
 594                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
 595                                         HPC_LED_BLINK);
 596                 break;
 597         default:
 598                 return (HPC_ERR_INVALID);
 599         }
 600 
 601         if (cmd != HPC_CTRL_DEV_CONFIG_START &&
 602                 cmd != HPC_CTRL_DEV_UNCONFIG_START &&
 603                 hsc->regDone == B_FALSE &&
 604                         scsb_hsc_numReg < hsc->n_registered_occupants) {
 605                 scsb_hsc_numReg++;
 606 
 607                 /*
 608                  * If the callback is invoked for all registered slots,
 609                  * enable ENUM.
 610                  */
 611                 if (((hsc->state & HSC_ATTACHED) == HSC_ATTACHED) &&
 612                         (scsb_hsc_numReg == hsc->n_registered_occupants)) {
 613                         hsc->regDone = B_TRUE;
 614                         if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) {
 615 #ifdef DEBUG
 616                                 cmn_err(CE_CONT, "%s%d: Enabling full hotswap"
 617                                         ":%d non-empty slots\n",
 618                                         ddi_driver_name(hsc->dip),
 619                                         ddi_get_instance(hsc->dip),
 620                                         hsc->n_registered_occupants);
 621 #endif
 622                                 if (scsb_enable_enum(hsc) != DDI_SUCCESS) {
 623                                         cmn_err(CE_WARN, "%s#%d: Cannot enable "
 624                                                 "Full Hotswap",
 625                                                 ddi_driver_name(hsc->dip),
 626                                                 ddi_get_instance(hsc->dip));
 627 
 628                                         return (HPC_ERR_FAILED);
 629                                 }
 630                         }
 631                 }
 632         }
 633 
 634         return (HPC_SUCCESS);
 635 }
 636 
 637 
 638 /*ARGSUSED*/
 639 static int
 640 hsc_get_board_type(hsc_slot_t *hsp, hpc_board_type_t *hbtp)
 641 {
 642         *hbtp = hsp->hs_board_type;
 643         return (HPC_SUCCESS);
 644 }
 645 
 646 
 647 /* ARGSUSED */
 648 static int
 649 hsc_autoconfig(hsc_slot_t *hsp, int cmd)
 650 {
 651         int res = HPC_SUCCESS, enum_disable = B_TRUE, i;
 652         char slotautocfg_prop[18];
 653         hsc_state_t *hsc;
 654 
 655         DEBUG1("hsc_autoconfig: slot %d", hsp->hs_slot_number);
 656         (void) sprintf(slotautocfg_prop, "slot%d-autoconfig",
 657             hsp->hs_slot_number);
 658 
 659         if (cmd == HPC_CTRL_ENABLE_AUTOCFG) {
 660                 hsp->hs_flags |= HSC_AUTOCFG;
 661                 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
 662                                 slotautocfg_prop, "enabled");
 663                 if ((res = scsb_enable_enum(hsp->hsc)) == DDI_SUCCESS) {
 664                         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
 665                                         HPC_EVENT_ENABLE_ENUM, 0);
 666                 }
 667         } else {
 668                 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
 669                     slotautocfg_prop, "disabled");
 670                 hsp->hs_flags &= ~HSC_AUTOCFG;
 671                 hsc = hsp->hsc;
 672                 if (hsc->state & HSC_ATTACHED) {
 673                         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
 674                                                 HPC_EVENT_DISABLE_ENUM, 0);
 675                         for (i = 0; i < hsc->slot_table_size; i++) {
 676                                 hsc_slot_t      *thsp;
 677                                 int slotnum;
 678 
 679                                 slotnum = hsc->slot_table_prop[i].pslotnum;
 680                                 thsp = hsc_find_slot(slotnum);
 681                                 if (thsp == NULL) {
 682                                         cmn_err(CE_WARN, "%s#%d: hsc_autocfg:"
 683                                                 "No Slot Info for slot %d",
 684                                                 ddi_driver_name(hsc->dip),
 685                                                 ddi_get_instance(hsc->dip),
 686                                                 slotnum);
 687                                         continue;
 688                                 }
 689                                 if (thsp->hs_flags & HSC_AUTOCFG) {
 690                                         enum_disable = B_FALSE;
 691                                         break;
 692                                 }
 693                         }
 694                         if (enum_disable == B_TRUE)
 695                                 (void) scsb_disable_enum(hsc,
 696                                     SCSB_HSC_FORCE_REMOVE);
 697                 }
 698         }
 699         return (res);
 700 }
 701 
 702 
 703 /*
 704  * This function is invoked to enable/disable a slot
 705  */
 706 /* ARGSUSED */
 707 #ifndef lint
 708 static int
 709 hsc_slot_enable(hsc_slot_t *hsp, boolean_t enabled)
 710 {
 711         scsb_uinfo_t    sunit;
 712         int             res;
 713 
 714         DEBUG1("hsc_slot_enable: slot %d", hsp->hs_slot_number);
 715 
 716         sunit.unit_type = SLOT;
 717         sunit.unit_number = hsp->hs_slot_number;
 718         if (enabled)
 719                 sunit.unit_state = ON;
 720         else
 721                 sunit.unit_state = OFF;
 722 
 723         res = scsb_reset_unit(hsp->hs_hpchandle, &sunit);
 724         if (res == 0)
 725                 return (HPC_SUCCESS);
 726         else if (res == EINVAL)
 727                 return (HPC_ERR_INVALID);
 728         else
 729                 return (HPC_ERR_FAILED);
 730 }
 731 #endif
 732 
 733 
 734 /*ARGSUSED*/
 735 static int
 736 hsc_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, caddr_t arg)
 737 {
 738         hsc_slot_t *hsp = (hsc_slot_t *)ops_arg;
 739         int rc = HPC_SUCCESS;
 740 
 741         DEBUG2("hsc_control: slot %d, op=%x\n", hsp->hs_slot_number, request);
 742 
 743         switch (request) {
 744         case HPC_CTRL_GET_LED_STATE:
 745                 return (hsc_led_state(hsp,
 746                         HPC_CTRL_GET_LED_STATE, (hpc_led_info_t *)arg));
 747 
 748         case HPC_CTRL_SET_LED_STATE:
 749                 return (hsc_led_state(hsp,
 750                         HPC_CTRL_SET_LED_STATE, (hpc_led_info_t *)arg));
 751 
 752         case HPC_CTRL_GET_SLOT_STATE:
 753                 return (hsc_get_slot_state(hsp, (hpc_slot_state_t *)arg));
 754 
 755         case HPC_CTRL_DEV_CONFIGURED:
 756                 return (hsc_set_config_state(hsp, HPC_CTRL_DEV_CONFIGURED));
 757 
 758         case HPC_CTRL_DEV_UNCONFIGURED:
 759                 return (hsc_set_config_state(hsp, HPC_CTRL_DEV_UNCONFIGURED));
 760 
 761         case HPC_CTRL_DEV_CONFIG_FAILURE:
 762                 return (hsc_set_config_state(hsp, HPC_CTRL_DEV_CONFIG_FAILURE));
 763 
 764         case HPC_CTRL_DEV_UNCONFIG_FAILURE:
 765                 return (hsc_set_config_state(hsp,
 766                                 HPC_CTRL_DEV_UNCONFIG_FAILURE));
 767 
 768         case HPC_CTRL_DEV_CONFIG_START:
 769         case HPC_CTRL_DEV_UNCONFIG_START:
 770                 return (hsc_set_config_state(hsp, request));
 771 
 772         case HPC_CTRL_GET_BOARD_TYPE:
 773                 return (hsc_get_board_type(hsp, (hpc_board_type_t *)arg));
 774 
 775         case HPC_CTRL_DISABLE_AUTOCFG:
 776                 return (hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG));
 777 
 778         case HPC_CTRL_ENABLE_AUTOCFG:
 779                 return (hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG));
 780 
 781         case HPC_CTRL_DISABLE_SLOT:
 782                 /*
 783                  * No hardware support for disabling the slot.
 784                  * Just imitate a disable_autoconfig operation for now
 785                  */
 786                 if (hsp->hs_board_configured == B_TRUE)
 787                         return (HPC_ERR_FAILED);
 788                 if (scsb_hsc_disable_slot(hsp) != DDI_SUCCESS)
 789                         rc = HPC_ERR_FAILED;
 790                 return (rc);
 791 
 792         case HPC_CTRL_ENABLE_SLOT:
 793                 if (scsb_hsc_enable_slot(hsp) != DDI_SUCCESS)
 794                         rc = HPC_ERR_FAILED;
 795                 return (rc);
 796 
 797         case HPC_CTRL_ENABLE_ENUM:
 798                 return (scsb_enable_enum(hsp->hsc));
 799 
 800         case HPC_CTRL_DISABLE_ENUM:
 801                 return (scsb_disable_enum(hsp->hsc, 0));
 802 
 803         default:
 804                 return (HPC_ERR_INVALID);
 805         }
 806 }
 807 
 808 static int
 809 scsb_hsc_disable_slot(hsc_slot_t *hsp)
 810 {
 811         int rc;
 812         char slot_disable_prop[18];
 813 
 814         DEBUG1("hsc_disable_slot: slot %d", hsp->hs_slot_number);
 815         (void) sprintf(slot_disable_prop, "slot%d-status", hsp->hs_slot_number);
 816 
 817         rc = scsb_reset_slot(hsp->hs_hpchandle, hsp->hs_slot_number,
 818                                         SCSB_RESET_SLOT);
 819         if (rc == DDI_SUCCESS) {
 820                 (void) hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG);
 821                 hsp->hs_flags &= ~HSC_SLOT_ENABLED;
 822                 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
 823                     slot_disable_prop, "disabled");
 824         } else
 825                 rc = DDI_FAILURE;
 826         return (rc);
 827 }
 828 
 829 static int
 830 scsb_hsc_enable_slot(hsc_slot_t *hsp)
 831 {
 832         int rc;
 833         char slot_disable_prop[18];
 834 
 835         DEBUG1("hsc_disable_slot: slot %d", hsp->hs_slot_number);
 836         (void) sprintf(slot_disable_prop, "slot%d-status", hsp->hs_slot_number);
 837 
 838         rc = scsb_reset_slot(hsp->hs_hpchandle, hsp->hs_slot_number,
 839                                         SCSB_UNRESET_SLOT);
 840         if (rc == DDI_SUCCESS) {
 841                 (void) hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG);
 842                 hsp->hs_flags |= HSC_SLOT_ENABLED;
 843                 (void) ddi_prop_remove(DDI_DEV_T_NONE, hsp->hsc->dip,
 844                     slot_disable_prop);
 845         } else
 846                 rc = HPC_ERR_FAILED;
 847         return (rc);
 848 }
 849 
 850 #define NEW(type)       (type *) kmem_zalloc(sizeof (type), KM_SLEEP)
 851 
 852 static hsc_slot_t *
 853 hsc_alloc_slot(
 854                 uint16_t        device_number,
 855                 int             slot_number,
 856                 boolean_t       board_in_slot)
 857 {
 858         hpc_slot_info_t *hsip;
 859         hsc_slot_t      *hsp = NEW(hsc_slot_t);
 860 
 861         DEBUG2("hsc_alloc_slot: slot %d %s", slot_number,
 862                 board_in_slot ? "occupied" : "empty");
 863 
 864         if (hsp == NULL) {
 865                 cmn_err(CE_NOTE,
 866                         "hsc_alloc_slot: allocation failed for slot %d",
 867                         slot_number);
 868                 return (NULL);
 869         }
 870 
 871         hsip = &hsp->hs_info;
 872 
 873         hsip->version                        = HPC_SLOT_INFO_VERSION;
 874         hsip->slot_type                      = HPC_SLOT_TYPE_CPCI;
 875         hsip->pci_dev_num            = device_number;
 876         hsip->pci_slot_capabilities  = 0;
 877         hsip->slot_flags             = HPC_SLOT_CREATE_DEVLINK;
 878         /*
 879          * Note: the name *must* be 'pci' so that the correct cfgadm plug-in
 880          *       library is selected
 881          */
 882         (void) sprintf(hsip->pci_slot_name, "cpci_slot%d", slot_number);
 883 
 884         /*
 885          * We assume that the following LED settings reflect
 886          * the hardware state.
 887          * After we register the slot, we will be invoked by the nexus
 888          * if the slot is occupied, and we will turn on the LED then.
 889          */
 890         hsp->hs_active_led_state     = HPC_LED_OFF;
 891         hsp->hs_fault_led_state              = HPC_LED_OFF;
 892 
 893         hsp->hs_board_configured     = B_FALSE;
 894         hsp->hs_board_healthy                = B_FALSE;
 895         hsp->hs_board_type           = HPC_BOARD_UNKNOWN;
 896 
 897         hsp->hs_flags                        = HSC_ENABLED | HSC_SLOT_ENABLED;
 898         hsp->hs_slot_number          = slot_number;
 899 
 900         /*
 901          * we should just set this to connected,
 902          * as MC slots are always connected.
 903          */
 904         if (board_in_slot)
 905                 hsp->hs_slot_state = HPC_SLOT_CONNECTED;
 906         else
 907                 hsp->hs_slot_state = HPC_SLOT_EMPTY;
 908 
 909         return (hsp);
 910 }
 911 
 912 
 913 static void
 914 hsc_free_slot(hsc_slot_t *hsp)
 915 {
 916         DEBUG0("hsc_free_slot");
 917 
 918         kmem_free(hsp, sizeof (*hsp));
 919 }
 920 
 921 
 922 /*
 923  * This function is invoked to register a slot
 924  */
 925 static int
 926 hsc_slot_register(
 927         hsc_state_t     *hsc,
 928         char            *bus_path,      /* PCI nexus pathname */
 929         uint16_t        device_number,  /* PCI device number */
 930         uint_t          slot_number,    /* physical slot number */
 931         boolean_t       board_in_slot)  /* receptacle status */
 932 {
 933         int             rc = HPC_SUCCESS;
 934         hsc_slot_t      *hsp;
 935 
 936         DEBUG2("hsc_slot_register: slot number %d, device number %d",
 937                 slot_number, device_number);
 938 
 939         hsp = hsc_alloc_slot(device_number, slot_number,
 940                         board_in_slot);
 941 
 942         if (hsp == NULL) {
 943 #ifdef  DEBUG
 944                 cmn_err(CE_NOTE, "hsc_slot_register: hsc_alloc_slot failed");
 945 #endif
 946                 return (HPC_ERR_FAILED);
 947         }
 948 
 949         hsp->hs_hpchandle = hsc->scsb_handle; /* handle for call backs */
 950         hsp->hsc = hsc;
 951 
 952         rc = scsb_hsc_init_slot_state(hsc, hsp);
 953         if (rc != DDI_SUCCESS)
 954                 return (HPC_ERR_FAILED);
 955 
 956         /* slot autoconfiguration by default. */
 957         if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL)
 958                 (void) hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG);
 959         else
 960                 (void) hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG);
 961 
 962         /*
 963          * Append to our list
 964          */
 965         mutex_enter(&hsc_mutex);
 966         hsp->hs_next = hsc_slot_list;
 967         hsc_slot_list = hsp;
 968         mutex_exit(&hsc_mutex);
 969 
 970         rc = hpc_slot_register(hsc->dip,
 971                         bus_path,
 972                         &hsp->hs_info,
 973                         &hsp->hs_slot_handle,    /* return value */
 974                         hsc_slotops,
 975                         (caddr_t)hsp,
 976                         0);
 977 
 978         if (rc != HPC_SUCCESS) {
 979                 cmn_err(CE_WARN, "%s#%d: failed to register slot %s:%d",
 980                         ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip),
 981                         bus_path, device_number);
 982                 hsc_free_slot(hsp);
 983                 return (rc);
 984         }
 985 
 986         DEBUG0("hsc_slot_register: hpc_slot_register successful");
 987 
 988         return (rc);
 989 }
 990 
 991 
 992 static int
 993 hsc_slot_unregister(int slot_number)
 994 {
 995         hsc_slot_t      *hsp, *prev;
 996 
 997         DEBUG1("hsc_slot_unregister: slot number %d", slot_number);
 998 
 999         mutex_enter(&hsc_mutex);
1000         hsp = prev = NULL;
1001         for (hsp = hsc_slot_list; hsp != NULL; hsp = hsp->hs_next) {
1002                 if (hsp->hs_slot_number == slot_number) {
1003                         if (prev == NULL) /* first entry */
1004                                 hsc_slot_list = hsc_slot_list->hs_next;
1005                         else
1006                                 prev->hs_next = hsp->hs_next;
1007                         hsp->hs_next = NULL;
1008                         break;
1009                 }
1010                 prev = hsp;
1011         }
1012         mutex_exit(&hsc_mutex);
1013 
1014         if (hsp != NULL) {
1015                 (void) hpc_slot_unregister(&hsp->hs_slot_handle);
1016                 if ((hsp->hsc->state & HSC_ATTACHED) != HSC_ATTACHED &&
1017                                 hsp->hs_slot_state != HPC_SLOT_EMPTY) {
1018                         hsp->hsc->n_registered_occupants--;
1019                 }
1020                 hsc_free_slot(hsp);
1021                 return (0);
1022         }
1023         return (1);
1024 }
1025 
1026 static int
1027 scsb_hsc_init_slot_state(hsc_state_t *hsc, hsc_slot_t *hsp)
1028 {
1029         int rc, rstate;
1030         int slot_number = hsp->hs_slot_number;
1031         scsb_state_t    *scsb = (scsb_state_t *)hsc->scsb_handle;
1032 
1033         rc = scsb_get_slot_state(hsc->scsb_handle, slot_number, &rstate);
1034         if (rc != DDI_SUCCESS)
1035                 return (DDI_FAILURE);
1036 
1037         /*
1038          * Set the healthy status for this slot
1039          */
1040         hsp->hs_board_healthy = scsb_read_slot_health(scsb, slot_number);
1041         hsp->hs_slot_state = rstate;
1042         switch (rstate) {
1043                 case HPC_SLOT_EMPTY:
1044                         /*
1045                          * this will clear any state differences between
1046                          * SCB Freeze operations.
1047                          */
1048                         hsp->hs_slot_state = HPC_SLOT_EMPTY;
1049                         /* slot empty. */
1050                         (void) scsb_reset_slot(hsc->scsb_handle, slot_number,
1051                             SCSB_RESET_SLOT);
1052                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1053                             HPC_LED_OFF);
1054                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1055                             HPC_LED_OFF);
1056                         break;
1057                 case HPC_SLOT_DISCONNECTED:
1058                         /*
1059                          * this will clear any state differences between
1060                          * SCB Freeze operations.
1061                          */
1062                         hsp->hs_slot_state = HPC_SLOT_DISCONNECTED;
1063                         /* check recovery from SCB freeze */
1064                         if (hsp->hs_board_configured != B_TRUE) {
1065                                 /*
1066                                  * Force a disconnect just in case there are
1067                                  * differences between healthy and reset states.
1068                                  */
1069                                 (void) scsb_reset_slot(hsc->scsb_handle,
1070                                     slot_number, SCSB_RESET_SLOT);
1071                                 /*
1072                                  * Slot in reset. OBP has not probed this
1073                                  * device. Hence it is ok to remove this board.
1074                                  */
1075                                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1076                                                 HPC_ACTIVE_LED, HPC_LED_BLINK);
1077                                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1078                                                 HPC_FAULT_LED, HPC_LED_ON);
1079                                 break;
1080                         }
1081                         /*FALLTHROUGH*/
1082                 case HPC_SLOT_CONNECTED:
1083                         /*
1084                          * this will clear any state differences between
1085                          * SCB Freeze operations.
1086                          */
1087                         hsp->hs_slot_state = HPC_SLOT_CONNECTED;
1088                         /*
1089                          * OBP should have probed this device, unless
1090                          * it was plugged in during the boot operation
1091                          * before the driver was loaded. In any case,
1092                          * no assumption is made and hence we take
1093                          * the conservative approach by keeping fault
1094                          * led off so board removal is not allowed.
1095                          */
1096                         if (hsp->hs_board_configured == B_TRUE)
1097                                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1098                                         HPC_ACTIVE_LED, HPC_LED_ON);
1099                         else
1100                                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1101                                         HPC_ACTIVE_LED, HPC_LED_BLINK);
1102                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1103                                                         HPC_LED_OFF);
1104                         /*
1105                          * Netra ct alarm card hotswap support
1106                          */
1107                         if (slot_number == scsb->ac_slotnum &&
1108                                 scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES) {
1109                                 hsp->hs_flags |= HSC_ALARM_CARD_PRES;
1110                                 DEBUG0("Xscsb_hsc_init_slot_state: "
1111                                                 "set HSC_ALARM_CARD_PRES");
1112                         }
1113                         break;
1114                 default:
1115                         break;
1116         }
1117         return (rc);
1118 }
1119 
1120 static hsc_slot_t *
1121 hsc_get_slot_info(hsc_state_t *hsc, int pci_devno)
1122 {
1123         int i;
1124 
1125         for (i = 0; i < hsc->slot_table_size; i++) {
1126 
1127                 if (hsc->slot_table_prop[i].pci_devno == pci_devno)
1128                         return ((hsc_slot_t *)hsc_find_slot(
1129                                 hsc->slot_table_prop[i].pslotnum));
1130         }
1131         return (NULL);
1132 }
1133 
1134 static hsc_slot_t *
1135 hsc_find_slot(int slot_number)
1136 {
1137         hsc_slot_t      *hsp;
1138 
1139         mutex_enter(&hsc_mutex);
1140         for (hsp = hsc_slot_list; hsp != NULL; hsp = hsp->hs_next) {
1141                 if (hsp->hs_slot_number == slot_number)
1142                         break;
1143         }
1144         mutex_exit(&hsc_mutex);
1145         return (hsp);
1146 }
1147 
1148 
1149 /*
1150  * This function is invoked by the SCSB when an interrupt
1151  * happens to indicate that a board has been inserted-in/removed-from
1152  * the specified slot.
1153  */
1154 int
1155 hsc_slot_occupancy(int slot_number, boolean_t occupied, int flags, int healthy)
1156 {
1157         static const char       func[]  = "hsc_slot_occupancy";
1158         hsc_slot_t              *hsp;
1159         int                     rc = DDI_SUCCESS;
1160 
1161         DEBUG4("hsc_slot_occupancy: slot %d %s, ac=%d, healthy=%d",
1162                         slot_number, occupied ? "occupied" : "not occupied",
1163                         (flags == ALARM_CARD_ON_SLOT) ? 1:0, healthy);
1164 
1165         hsp = hsc_find_slot(slot_number);
1166 
1167         if (hsp == NULL) {
1168                 cmn_err(CE_NOTE,
1169                         "%s: cannot map slot number %d to a hsc_slot_t",
1170                         func, slot_number);
1171                 return (DDI_FAILURE);
1172         }
1173 
1174         hsp->hs_board_healthy = healthy;
1175         if (occupied) {
1176                 /*
1177                  * A board was just inserted. We are disconnected at this point.
1178                  */
1179                 if (hsp->hs_slot_state == HPC_SLOT_EMPTY)
1180                         hsp->hs_board_type = HPC_BOARD_CPCI_HS;
1181                 hsp->hs_slot_state = HPC_SLOT_DISCONNECTED;
1182                 if (flags == ALARM_CARD_ON_SLOT) {
1183                         hsp->hs_flags |= HSC_ALARM_CARD_PRES;
1184                         DEBUG0("Xhsc_slot_occupancy: set HSC_ALARM_CARD_PRES");
1185                 }
1186                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1187                                                 HPC_LED_ON);
1188                 /*
1189                  * if previous occupant stayed configured, do not allow another
1190                  * occupant to be connected.
1191                  * So as soon as the board is plugged in, we turn both LEDs On.
1192                  * This behaviour is an indication that the slot state
1193                  * is not clean.
1194                  */
1195                 if (hsp->hs_flags & HSC_SLOT_BAD_STATE) {
1196                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1197                                                                 HPC_LED_ON);
1198                         return (DDI_SUCCESS);
1199                 }
1200 
1201                 /* Do not allow connect if slot is disabled */
1202                 if ((hsp->hs_flags & HSC_SLOT_ENABLED) != HSC_SLOT_ENABLED)
1203                         return (DDI_SUCCESS);
1204                 /* if no healthy, we stay disconnected. */
1205                 if (healthy == B_FALSE) {
1206                         return (DDI_SUCCESS);
1207                 }
1208                 rc = hsc_slot_autoconnect(hsp);
1209                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1210                                                                 HPC_LED_BLINK);
1211         } else {
1212                 /*
1213                  * A board was just removed
1214                  */
1215                 hsp->hs_slot_state = HPC_SLOT_EMPTY;
1216                 hsp->hs_board_type = HPC_BOARD_UNKNOWN;
1217                 hsp->hs_flags &= ~HSC_ENUM_FAILED;
1218                 if (hsp->hs_flags & HSC_ALARM_CARD_PRES) {
1219                         hsp->hs_flags &= ~HSC_ALARM_CARD_PRES;
1220                         DEBUG0("Xhsc_slot_occupancy:clear HSC_ALARM_CARD_PRES");
1221                 }
1222                 if (hsp->hs_board_configured == B_TRUE) {
1223                         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
1224                                         HPC_EVENT_SLOT_NOT_HEALTHY, 0);
1225                         cmn_err(CE_WARN, "%s#%d: ALERT! Surprise Removal "
1226                                 " on Slot %d, Occupant Online!!",
1227                                         ddi_driver_name(hsp->hsc->dip),
1228                                         ddi_get_instance(hsp->hsc->dip),
1229                                         slot_number);
1230                         cmn_err(CE_WARN, "%s#%d: ALERT! System now in "
1231                                 " Inconsistent State! Slot disabled. Halt!",
1232                                         ddi_driver_name(hsp->hsc->dip),
1233                                         ddi_get_instance(hsp->hsc->dip));
1234                         /* Slot in reset and disabled */
1235                         (void) scsb_hsc_disable_slot(hsp);
1236                         hsp->hs_flags |= HSC_SLOT_BAD_STATE;
1237                         /* the following works for P1.0 only. */
1238                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1239                                                 HPC_LED_ON);
1240                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1241                                                                 HPC_LED_ON);
1242                 } else {
1243                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1244                                                 HPC_LED_OFF);
1245                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1246                                                                 HPC_LED_OFF);
1247                 }
1248         }
1249         return (rc);
1250 }
1251 
1252 
1253 /*
1254  * This function is invoked by the SCSB when the health status of
1255  * a board changes.
1256  */
1257 /*ARGSUSED*/
1258 int
1259 scsb_hsc_board_healthy(int slot_number, boolean_t healthy)
1260 {
1261         hsc_slot_t              *hsp;
1262         hsc_state_t             *hsc;
1263 
1264         DEBUG2("hsc_board_healthy: slot %d = %d\n", slot_number, healthy);
1265 
1266         hsp = hsc_find_slot(slot_number);
1267         if (hsp == NULL) {
1268                 cmn_err(CE_NOTE, "hsc_board_healthy: No Slot Info.");
1269                 return (DDI_FAILURE);
1270         }
1271 
1272         hsc = hsp->hsc;
1273         if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
1274 #ifdef  DEBUG
1275                 cmn_err(CE_NOTE, "%s#%d: Healthy# %s on "
1276                         "empty slot %d", ddi_driver_name(hsc->dip),
1277                         ddi_get_instance(hsc->dip),
1278                         healthy == B_TRUE ? "On" : "Off", slot_number);
1279 #endif
1280                 return (DDI_FAILURE);
1281         }
1282         if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
1283                 DEBUG2("healthy %s on disconnected slot %d\n",
1284                         healthy == B_TRUE ? "On":"Off", slot_number);
1285                 /*
1286                  * Connect the slot if board healthy and in autoconfig mode.
1287                  */
1288                 hsp->hs_board_healthy = healthy;
1289                 if (healthy == B_TRUE)
1290                         return (hsc_slot_autoconnect(hsp));
1291         }
1292 
1293         /*
1294          * the board is connected. The result could be seviour depending
1295          * on the occupant state.
1296          */
1297         if (healthy == B_TRUE) {
1298                 if (hsp->hs_board_healthy != B_TRUE) {
1299                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1300                                         HPC_LED_OFF);
1301                         /* Regained HEALTHY# at Run Time...!!! */
1302                         cmn_err(CE_NOTE, "%s#%d: slot %d Occupant "
1303                                 "%s, Regained HEALTHY#!",
1304                                 ddi_driver_name(hsc->dip),
1305                                 ddi_get_instance(hsc->dip), slot_number,
1306                                 hsp->hs_board_configured == B_TRUE ?
1307                                                 "configured" : "Unconfigured");
1308                         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
1309                                 HPC_EVENT_SLOT_HEALTHY_OK, 0);
1310                 }
1311         } else {
1312                 if (hsp->hs_board_configured == B_TRUE) {
1313                         /* Lost HEALTHY# at Run Time...Serious Condition. */
1314                         cmn_err(CE_WARN, "%s#%d: ALERT! Lost HEALTHY#"
1315                                 " on Slot %d, Occupant %s",
1316                                 ddi_driver_name(hsc->dip),
1317                                 ddi_get_instance(hsc->dip), slot_number,
1318                                         hsp->hs_board_configured == B_TRUE ?
1319                                                 "Online!!!" : "Offline");
1320                         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
1321                                         HPC_EVENT_SLOT_NOT_HEALTHY, 0);
1322                 }
1323                 if ((hsp->hs_board_configured != B_TRUE) ||
1324                                                 scsb_hsc_healthy_reset) {
1325                         if (scsb_reset_slot(hsp->hs_hpchandle,
1326                                         slot_number, SCSB_RESET_SLOT) == 0) {
1327                                 /* signal Ok to remove board. */
1328                                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1329                                         HPC_FAULT_LED, HPC_LED_ON);
1330                                 cmn_err(CE_WARN, "%s#%d: Slot %d "
1331                                         "successfully taken offline",
1332                                         ddi_driver_name(hsc->dip),
1333                                         ddi_get_instance(hsc->dip),
1334                                         slot_number);
1335                         }
1336                 }
1337         }
1338         hsp->hs_board_healthy = healthy;
1339         return (DDI_SUCCESS);
1340 }
1341 
1342 static int
1343 hsc_slot_autoconnect(hsc_slot_t *hsp)
1344 {
1345         hsc_state_t *hsc = hsp->hsc;
1346         int rc = DDI_SUCCESS;
1347         /*
1348          * Keep slot in reset unless autoconfiguration is enabled
1349          * Ie. for Basic Hotswap mode, we stay disconnected at
1350          * insertion. For full hotswap mode, we automatically
1351          * go into connected state at insertion, so that occupant
1352          * autoconfiguration is possible.
1353          */
1354         if (((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) &&
1355                         (hsp->hs_flags & HSC_AUTOCFG)) {
1356                 /* this statement must be here before unreset. */
1357                 hsc->hsp_last = hsp;
1358                 if ((rc = scsb_reset_slot(hsp->hs_hpchandle,
1359                         hsp->hs_slot_number, SCSB_UNRESET_SLOT)) == 0) {
1360 
1361                         hsp->hs_slot_state = HPC_SLOT_CONNECTED;
1362                         hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1363                                         HPC_FAULT_LED, HPC_LED_OFF);
1364                 } else {
1365                         hsc->hsp_last = NULL;
1366                         rc = DDI_FAILURE;
1367                 }
1368         }
1369         return (rc);
1370 }
1371 
1372 /*
1373  * The SCSB code should invoke this function from its _init() function.
1374  */
1375 int
1376 hsc_init()
1377 {
1378         int rc;
1379 
1380         rc = ddi_soft_state_init(&hsc_state, sizeof (hsc_state_t), 1);
1381         if (rc != 0)
1382                 return (rc);
1383 
1384         hsc_slotops = hpc_alloc_slot_ops(KM_SLEEP);
1385 
1386         hsc_slotops->hpc_version     = HPC_SLOT_OPS_VERSION;
1387         hsc_slotops->hpc_op_connect  = hsc_connect;
1388         hsc_slotops->hpc_op_disconnect       = hsc_disconnect;
1389         hsc_slotops->hpc_op_insert   = hsc_insert;
1390         hsc_slotops->hpc_op_remove   = hsc_remove;
1391         hsc_slotops->hpc_op_control  = hsc_control;
1392 
1393         return (DDI_SUCCESS);
1394 }
1395 
1396 
1397 /*
1398  * The SCSB code should invoke this function from its _fini() function.
1399  */
1400 int
1401 hsc_fini()
1402 {
1403         if (hsc_slotops != NULL) {
1404                 hpc_free_slot_ops(hsc_slotops);
1405                 hsc_slotops = NULL;
1406         }
1407         ddi_soft_state_fini(&hsc_state);
1408         return (DDI_SUCCESS);
1409 }
1410 
1411 static int
1412 scsb_enable_enum(hsc_state_t *hsc)
1413 {
1414         DEBUG0("hsc: Enable ENUM#\n");
1415 
1416         if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED)
1417                 return (DDI_SUCCESS);
1418         if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1419                 return (DDI_FAILURE);
1420 
1421         if (ddi_add_intr(hsc->dip, 1, NULL, NULL,
1422                         hsc_enum_intr, (caddr_t)hsc) != DDI_SUCCESS) {
1423                 cmn_err(CE_WARN, "%s#%d: failed ENUM# interrupt registration",
1424                         ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
1425                 return (DDI_FAILURE);
1426         }
1427         cmn_err(CE_CONT, "?%s%d: Successfully Upgraded to "
1428                         "Full Hotswap Mode\n", ddi_driver_name(hsc->dip),
1429                         ddi_get_instance(hsc->dip));
1430         hsc->state |= HSC_ENUM_ENABLED;
1431         (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip,
1432             HOTSWAP_MODE_PROP, "full");
1433         return (DDI_SUCCESS);
1434 
1435 }
1436 
1437 /*ARGSUSED*/
1438 static int
1439 scsb_disable_enum(hsc_state_t *hsc, int op)
1440 {
1441 
1442         DEBUG0("hsc: Disable ENUM#\n");
1443         if (op == SCSB_HSC_FORCE_REMOVE) {
1444                 /*
1445                  * Clear all pending interrupts before unregistering
1446                  * the interrupt. Otherwise the system will hang.
1447                  *
1448                  * Due to the hang problem, we'll not turn off or disable
1449                  * interrupts because if there's a non-friendly full hotswap
1450                  * device out there, the ENUM# will be kept asserted and
1451                  * hence hsc_clear_all_enum() can never deassert ENUM#.
1452                  * So the system will hang.
1453                  */
1454                 if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) {
1455                         /* hsc_clear_all_enum(hsc); */
1456                         ddi_remove_intr(hsc->dip, 1, NULL);
1457                         hsc->state &= ~HSC_ENUM_ENABLED;
1458                         cmn_err(CE_CONT, "?%s%d: Successfully Downgraded to "
1459                                 "Basic Hotswap Mode\n",
1460                                 ddi_driver_name(hsc->dip),
1461                                 ddi_get_instance(hsc->dip));
1462                 }
1463                 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip,
1464                     HOTSWAP_MODE_PROP, "basic");
1465                 return (DDI_SUCCESS);
1466         } else
1467                 /* No programming interface for disabling ENUM# on MC/Tonga */
1468                 return (HPC_ERR_NOTSUPPORTED);
1469 }
1470 
1471 #ifndef lint
1472 static int
1473 hsc_clear_all_enum(hsc_state_t *hsc)
1474 {
1475         int i, rc;
1476         hsc_slot_t *hsp;
1477 
1478         for (i = 0; i < hsc->slot_table_size; i++) {
1479 
1480                 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1481                 if (hsp == NULL)
1482                         continue;
1483                 rc = hpc_slot_event_notify(hsp->hs_slot_handle,
1484                                         HPC_EVENT_CLEAR_ENUM,
1485                                                 HPC_EVENT_SYNCHRONOUS);
1486                 if (rc == HPC_EVENT_UNCLAIMED)
1487                         break;  /* no pending interrupts across the bus */
1488                 DEBUG1("Pending Intr on slot %d\n",
1489                         hsc->slot_table_prop[i].pslotnum);
1490         }
1491         return (0);
1492 }
1493 #endif
1494 
1495 int
1496 scsb_hsc_attach(dev_info_t *dip, void *scsb_handle, int instance)
1497 {
1498         int i, n, prop_len;
1499         int prom_prop = 0;      /* default: OS property gives slot-table */
1500         int rc;
1501         char *hotswap_model;
1502         hsc_state_t     *hsc;
1503         scsb_state_t    *scsb = (scsb_state_t *)scsb_handle;
1504         caddr_t hpc_slot_table_data, s;
1505         int hpc_slot_table_size;
1506         hsc_prom_slot_table_t   *hpstp;
1507         int rstate;
1508 
1509         DEBUG0("hsc_attach: enter\n");
1510         /*
1511          * To get the slot information,
1512          * The OBP defines the 'slot-table' property. But the OS
1513          * can override it with 'hsc-slot-map' property
1514          * through the .conf file.
1515          * Since the formats are different, 2 different property names
1516          * are chosen.
1517          * The OBP property format is
1518          * <phandle>,<pci-devno>,<phys-slotno>,<ga-bits>
1519          * The OS property format is (ga-bits is not used however)
1520          * <busnexus-path>,<pci-devno>,<phys-slotno>,<ga-bits>
1521          */
1522         rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1523                 "hsc-slot-map", (caddr_t)&hpc_slot_table_data,
1524                 &hpc_slot_table_size);
1525         if (rc != DDI_PROP_SUCCESS)  {
1526                 prom_prop = 1;
1527                 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1528                         "slot-table", (caddr_t)&hpc_slot_table_data,
1529                         &hpc_slot_table_size);
1530                 if (rc != DDI_PROP_SUCCESS) {
1531                         cmn_err(CE_WARN, "%s#%d: 'slot-table' property "
1532                                 "missing!", ddi_driver_name(dip),
1533                                                 ddi_get_instance(dip));
1534                         return (DDI_FAILURE);
1535                 }
1536         }
1537         rc = ddi_soft_state_zalloc(hsc_state, instance);
1538         if (rc != DDI_SUCCESS)
1539                 return (DDI_FAILURE);
1540 
1541         hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1542         hsc->scsb_handle = scsb_handle;
1543         hsc->dip = dip;
1544         hsc->instance = instance;
1545         hsc->n_registered_occupants = 0;
1546         hsc->regDone = B_FALSE;
1547         /* hsc->slot_info = hsc_slot_list; */
1548 
1549         /*
1550          * Check whether the system should be in basic or full
1551          * hotswap mode. The PROM property always says full, so
1552          * look at the .conf file property whether this is "full"
1553          */
1554         if (scsb_hsc_enable_fhs) {
1555                 hsc->hotswap_mode = HSC_HOTSWAP_MODE_FULL;
1556         } else {
1557                 hsc->hotswap_mode = HSC_HOTSWAP_MODE_BASIC;
1558         }
1559 
1560         rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1561                 "default-hotswap-mode", (caddr_t)&hotswap_model, &prop_len);
1562 
1563         if (rc == DDI_PROP_SUCCESS) {
1564                 if (strcmp(hotswap_model, "full") == 0) {
1565                         hsc->hotswap_mode = HSC_HOTSWAP_MODE_FULL;
1566                 } else if (strcmp(hotswap_model, "basic") == 0) {
1567                         hsc->hotswap_mode = HSC_HOTSWAP_MODE_BASIC;
1568                 }
1569 
1570                 kmem_free(hotswap_model, prop_len);
1571         }
1572 
1573         /*
1574          * Determine the size of the slot table from the property and
1575          * allocate the slot table arrary..Decoding is different for
1576          * OS and PROM property.
1577          */
1578         if (!prom_prop) {       /* OS .conf property */
1579                 for (i = 0, n = 0; i < hpc_slot_table_size; i++) {
1580                         if (hpc_slot_table_data[i] == 0) {
1581                                 n++;
1582                         }
1583                 }
1584 
1585                 /* There should be four elements per entry */
1586                 if (n % 4) {
1587                         cmn_err(CE_WARN, "%s#%d: bad format for "
1588                                 "slot-table(%d)", ddi_driver_name(dip),
1589                                                 ddi_get_instance(dip), n);
1590                         kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1591                         ddi_soft_state_free(hsc_state, instance);
1592                         return (DDI_FAILURE);
1593                 }
1594 
1595                 hsc->slot_table_size = n / 4;
1596         } else {
1597                 hsc->slot_table_size = hpc_slot_table_size /
1598                                                 sizeof (hsc_prom_slot_table_t);
1599                 n = hpc_slot_table_size % sizeof (hsc_prom_slot_table_t);
1600                 if (n) {
1601                         cmn_err(CE_WARN, "%s#%d: bad format for "
1602                                 "slot-table(%d)", ddi_driver_name(dip),
1603                                 ddi_get_instance(dip), hpc_slot_table_size);
1604                         kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1605                         ddi_soft_state_free(hsc_state, instance);
1606                         return (DDI_FAILURE);
1607                 }
1608         }
1609 
1610         /*
1611          * Netract800 FTC (formerly known as CFTM) workaround.
1612          * Leave Slot 2 out of the HS table if FTC is present in Slot 2
1613          */
1614         if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES) {
1615                 hsc->slot_table_size -= 1;
1616         }
1617         DEBUG1("hsc_attach: %d hotplug slots on bus\n", hsc->slot_table_size);
1618         /*
1619          * Create enough space for each slot table entry
1620          * based on how many entries in the property
1621          */
1622         hsc->slot_table_prop = (hsc_slot_table_t *)
1623                 kmem_zalloc(hsc->slot_table_size *
1624                         sizeof (hsc_slot_table_t), KM_SLEEP);
1625 
1626         if (!prom_prop) {
1627                 s = hpc_slot_table_data;
1628                 for (i = 0; i < hsc->slot_table_size; i++) {
1629 
1630                         char *nexus, *pcidev, *phys_slotname, *ga;
1631 
1632                         /* Pick off pointer to nexus path or PROM handle */
1633                         nexus = s;
1634                         while (*s != NULL)
1635                                 s++;
1636                         s++;
1637 
1638                         /* Pick off pointer to the pci device number */
1639                         pcidev = s;
1640                         while (*s != NULL)
1641                                 s++;
1642                         s++;
1643 
1644                         /* Pick off physical slot no */
1645                         phys_slotname = s;
1646                         while (*s != NULL)
1647                                 s++;
1648                         s++;
1649 
1650                         /* Pick off GA bits which we dont use for now. */
1651                         ga = s;
1652                         while (*s != NULL)
1653                                 s++;
1654                         s++;
1655 
1656                         if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
1657                                         atoi(phys_slotname) == SC_MC_CTC_SLOT) {
1658                                 --i;
1659                                 continue;
1660                         }
1661                         hsc->slot_table_prop[i].pslotnum = atoi(phys_slotname);
1662                         hsc->slot_table_prop[i].ga = atoi(ga);
1663                         hsc->slot_table_prop[i].pci_devno = atoi(pcidev);
1664                         (void) strcpy(hsc->slot_table_prop[i].nexus, nexus);
1665                 }
1666         } else {
1667                 hpstp = (hsc_prom_slot_table_t *)hpc_slot_table_data;
1668                 for (i = 0; i < hsc->slot_table_size; i++, hpstp++) {
1669                         if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
1670                                         hpstp->pslotnum == SC_MC_CTC_SLOT) {
1671                                 --i;
1672                                 continue;
1673                         }
1674                         hsc->slot_table_prop[i].pslotnum = hpstp->pslotnum;
1675                         hsc->slot_table_prop[i].ga = hpstp->ga;
1676                         hsc->slot_table_prop[i].pci_devno = hpstp->pci_devno;
1677 
1678                         if (prom_phandle_to_path((uint_t)hpstp->phandle,
1679                                 hsc->slot_table_prop[i].nexus,
1680                                 sizeof (hsc->slot_table_prop[i].nexus))
1681                                                 == -1) {
1682                                 cmn_err(CE_WARN, "%s#%d: Cannot get phandle "
1683                                         "to nexus path", ddi_driver_name(dip),
1684                                         ddi_get_instance(dip));
1685                                 kmem_free(hsc->slot_table_prop,
1686                                         (hsc->slot_table_size *
1687                                                 sizeof (hsc_slot_table_t)));
1688                                 kmem_free(hpc_slot_table_data,
1689                                                 hpc_slot_table_size);
1690                                 ddi_soft_state_free(hsc_state, instance);
1691                                 return (DDI_FAILURE);
1692                         }
1693                 }
1694         }
1695 
1696         /* keep healthy register cache uptodate before reading slot state */
1697         if (scsb_read_bhealthy(scsb_handle) != 0) {
1698                 cmn_err(CE_WARN, "%s#%d: hsc_attach: Cannot read "
1699                         "Healthy Registers", ddi_driver_name(dip),
1700                                 ddi_get_instance(dip));
1701                 kmem_free(hsc->slot_table_prop,
1702                         (hsc->slot_table_size *
1703                                 sizeof (hsc_slot_table_t)));
1704                 kmem_free(hpc_slot_table_data,
1705                                 hpc_slot_table_size);
1706                 ddi_soft_state_free(hsc_state, instance);
1707                 return (DDI_FAILURE);
1708         }
1709 
1710         /*
1711          * Before we start registering the slots, calculate how many
1712          * slots are occupied.
1713          */
1714 
1715         for (i = 0; i < hsc->slot_table_size; i++) {
1716                 if (scsb_get_slot_state(scsb_handle,
1717                                 hsc->slot_table_prop[i].pslotnum, &rstate) !=
1718                                 DDI_SUCCESS)
1719                                 return (rc);
1720                 if (rstate != HPC_SLOT_EMPTY)
1721                         hsc->n_registered_occupants++;
1722         }
1723 
1724         mutex_init(&hsc->hsc_mutex, NULL, MUTEX_DRIVER, NULL);
1725         for (i = 0; i < hsc->slot_table_size; i++) {
1726 
1727                 DEBUG2("Registering on nexus [%s] cPCI device [%d]\n",
1728                         hsc->slot_table_prop[i].nexus,
1729                         hsc->slot_table_prop[i].pci_devno);
1730 
1731                 if (hsc_slot_register(hsc, hsc->slot_table_prop[i].nexus,
1732                         hsc->slot_table_prop[i].pci_devno,
1733                         hsc->slot_table_prop[i].pslotnum, B_FALSE) !=
1734                                                                 HPC_SUCCESS) {
1735 
1736                         cmn_err(CE_WARN, "%s#%d: Slot Registration Failure",
1737                                 ddi_driver_name(dip), ddi_get_instance(dip));
1738                         while (i) {
1739                                 i--;
1740                                 n = hsc->slot_table_prop[i].pslotnum;
1741                                 if (hsc_slot_unregister(n) != 0) {
1742                                         cmn_err(CE_WARN,
1743                                                 "%s#%d: failed to unregister"
1744                                                 " slot %d",
1745                                                 ddi_driver_name(dip),
1746                                                 ddi_get_instance(dip), n);
1747 
1748                                 }
1749                         }
1750                         mutex_destroy(&hsc->hsc_mutex);
1751                         kmem_free(hsc->slot_table_prop, (hsc->slot_table_size *
1752                                         sizeof (hsc_slot_table_t)));
1753                         kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1754                         ddi_soft_state_free(hsc_state, instance);
1755                         return (DDI_FAILURE);
1756                 }
1757         }
1758 
1759         hsc->hsp_last = NULL;
1760         hsc->hsc_intr_counter = 0;
1761         kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1762         (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip,
1763             HOTSWAP_MODE_PROP, "basic");
1764         hsc->state |= (HSC_ATTACHED|HSC_SCB_CONNECTED);
1765 
1766         /*
1767          * We enable full hotswap right here if all the slots are empty.
1768          */
1769         if ((hsc->regDone == B_FALSE && hsc->n_registered_occupants == 0) ||
1770                         scsb_hsc_numReg == hsc->n_registered_occupants) {
1771                 hsc->regDone = B_TRUE;
1772                 if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) {
1773                         if (scsb_enable_enum(hsc) != DDI_SUCCESS) {
1774                                 cmn_err(CE_WARN, "%s#%d: Cannot enable "
1775                                         "Full Hotswap", ddi_driver_name(dip),
1776                                         ddi_get_instance(dip));
1777                         }
1778                 }
1779         }
1780         return (DDI_SUCCESS);
1781 }
1782 
1783 /*ARGSUSED*/
1784 int
1785 scsb_hsc_detach(dev_info_t *dip, void *scsb_handle, int instance)
1786 {
1787         int i = 0;
1788         hsc_state_t     *hsc;
1789         char slotautocfg_prop[18];
1790 
1791         DEBUG0("hsc_detach: enter\n");
1792         hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1793         if (hsc == NULL) {
1794                 DEBUG2("%s#%d: hsc_detach: Soft state NULL",
1795                                 ddi_driver_name(dip), ddi_get_instance(dip));
1796                 return (DDI_FAILURE);
1797         }
1798 
1799         if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1800                 return (DDI_FAILURE);
1801         /*
1802          * let's unregister the hotpluggable slots with hotplug service.
1803          */
1804         for (i = 0; i < hsc->slot_table_size; i++) {
1805 
1806                 hsc_slot_t      *hsp;
1807 
1808                 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1809                 if (hsp == NULL) {
1810                         cmn_err(CE_WARN, "%s#%d: hsc_detach: No Slot Info",
1811                                 ddi_driver_name(dip), ddi_get_instance(dip));
1812                 } else {
1813                         hpc_led_info_t  aledinfo;       /* active led info. */
1814                         hpc_led_info_t  fledinfo;       /* fault led info. */
1815 
1816                         aledinfo.led = HPC_ACTIVE_LED;
1817                         aledinfo.state = HPC_LED_BLINK;
1818                         fledinfo.led = HPC_FAULT_LED;
1819                         fledinfo.state = HPC_LED_OFF;
1820                         (void) hsc_led_state(hsp, HPC_CTRL_SET_LED_STATE,
1821                                                         &aledinfo);
1822                         (void) hsc_led_state(hsp, HPC_CTRL_SET_LED_STATE,
1823                                                         &fledinfo);
1824                 }
1825                 (void) sprintf(slotautocfg_prop, "slot%d-autoconfig",
1826                     hsp->hs_slot_number);
1827                 (void) ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip,
1828                     slotautocfg_prop);
1829                 if (hsc_slot_unregister(hsc->slot_table_prop[i].pslotnum)
1830                                                 != 0) {
1831                         cmn_err(CE_NOTE, "%s#%d: failed to unregister"
1832                                 " slot %d\n", ddi_driver_name(dip),
1833                                 ddi_get_instance(dip),
1834                                 hsc->slot_table_prop[i].pslotnum);
1835                         return (DDI_FAILURE);
1836                 }
1837         }
1838         kmem_free(hsc->slot_table_prop, (hsc->slot_table_size *
1839                                         sizeof (hsc_slot_table_t)));
1840         if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) {
1841                 ddi_remove_intr(hsc->dip, 1, hsc->enum_iblock);
1842                 hsc->state &= ~HSC_ENUM_ENABLED;
1843         }
1844         mutex_destroy(&hsc->hsc_mutex);
1845         (void) ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP);
1846         hsc->state &= ~(HSC_ATTACHED|HSC_SCB_CONNECTED);
1847         ddi_soft_state_free(hsc_state, instance);
1848         return (DDI_SUCCESS);
1849 }
1850 
1851 /*
1852  * The following function is called when the SCSB is hot extracted from
1853  * the system.
1854  */
1855 int
1856 scsb_hsc_freeze(dev_info_t *dip)
1857 {
1858         hsc_state_t     *hsc;
1859         int instance = ddi_get_instance(dip);
1860         int i;
1861         hsc_slot_t      *hsp;
1862 
1863         hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1864         if (hsc == NULL) {
1865                 DEBUG2("%s#%d: Soft state NULL",
1866                                 ddi_driver_name(dip), ddi_get_instance(dip));
1867                 return (DDI_SUCCESS);
1868         }
1869         if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1870                 return (DDI_SUCCESS);
1871         hsc->state &= ~HSC_SCB_CONNECTED;
1872 
1873         for (i = 0; i < hsc->slot_table_size; i++) {
1874                 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1875 
1876                 if (hsp == NULL) {
1877                         cmn_err(CE_NOTE, "hsc_freeze: "
1878                                 " Cannot map slot number %d to a hsc_slot_t",
1879                                         hsc->slot_table_prop[i].pslotnum);
1880                         continue;
1881                 }
1882                 /*
1883                  * Since reset lines are pulled low, lets mark these
1884                  * slots and not allow a connect operation.
1885                  * Note that we still keep the slot as slot disconnected,
1886                  * although it is connected from the hardware standpoint.
1887                  * As soon as the SCB is plugged back in, we check these
1888                  * states and put the hardware state back to its original
1889                  * state.
1890                  */
1891                 if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
1892                         cmn_err(CE_WARN, "%s#%d: Slot %d Now out of Reset!",
1893                                 ddi_driver_name(hsc->dip),
1894                                 ddi_get_instance(hsc->dip),
1895                                 hsp->hs_slot_number);
1896                 }
1897                 hsp->hs_flags |= HSC_SCB_HOTSWAPPED;
1898         }
1899 
1900         return (DDI_SUCCESS);
1901 }
1902 
1903 /*
1904  * The following function is called when the SCSB is hot inserted from
1905  * the system. We must update the LED status and set the RST# registers
1906  * again.
1907  */
1908 int
1909 scsb_hsc_restore(dev_info_t *dip)
1910 {
1911         int i;
1912         hsc_state_t     *hsc;
1913         hsc_slot_t      *hsp;
1914         int instance = ddi_get_instance(dip);
1915 
1916         hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1917         if (hsc == NULL) {
1918                 DEBUG2("%s#%d: Soft state NULL",
1919                                 ddi_driver_name(dip), ddi_get_instance(dip));
1920                 return (DDI_SUCCESS);
1921         }
1922 
1923         if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1924                 return (DDI_SUCCESS);
1925         hsc->state |= HSC_SCB_CONNECTED;
1926         for (i = 0; i < hsc->slot_table_size; i++) {
1927                 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1928 
1929                 if (hsp == NULL) {
1930                         cmn_err(CE_NOTE, "%s#%d: hsc_restore: "
1931                                 " Cannot map slot number %d to a hsc_slot_t",
1932                                         ddi_driver_name(hsc->dip),
1933                                         ddi_get_instance(hsc->dip),
1934                                         hsc->slot_table_prop[i].pslotnum);
1935                         continue;
1936                 }
1937                 if ((hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) &&
1938                                 (hsp->hs_board_configured == B_FALSE)) {
1939                         if (scsb_reset_slot(hsp->hs_hpchandle,
1940                                         hsp->hs_slot_number,
1941                                         SCSB_RESET_SLOT) != 0) {
1942                                 cmn_err(CE_WARN, "%s#%d: hsc_restore: "
1943                                         " Cannot reset disconnected slot %d",
1944                                                 ddi_driver_name(hsc->dip),
1945                                                 ddi_get_instance(hsc->dip),
1946                                                 hsp->hs_slot_number);
1947                         }
1948                 }
1949 
1950                 if (scsb_hsc_init_slot_state(hsc, hsp) != DDI_SUCCESS) {
1951 
1952                         cmn_err(CE_WARN, "%s#%d: hsc_freeze: Cannot init"
1953                                 " slot%d state",
1954                                 ddi_driver_name(hsc->dip),
1955                                 ddi_get_instance(hsc->dip),
1956                                 hsp->hs_slot_number);
1957                 }
1958                 hsp->hs_flags &= ~HSC_SCB_HOTSWAPPED;
1959         }
1960         return (DDI_SUCCESS);
1961 }
1962 
1963 #ifndef lint
1964 int
1965 scsb_hsc_freeze_check(dev_info_t *dip)
1966 {
1967         hsc_state_t     *hsc;
1968         int instance = ddi_get_instance(dip);
1969 
1970         hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1971         if (hsc == NULL) {
1972                 DEBUG2("%s#%d: Soft state NULL",
1973                                 ddi_driver_name(dip), ddi_get_instance(dip));
1974                 return (DDI_SUCCESS);
1975         }
1976         if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1977                 return (DDI_SUCCESS);
1978         return (DDI_SUCCESS);
1979 }
1980 #endif
1981 
1982 /*
1983  * update info about Alarm Card insert/remove mechanism.
1984  */
1985 void
1986 hsc_ac_op(int instance, int pslotnum, int op, void *arg)
1987 {
1988         hsc_slot_t *hsp;
1989         hsc_state_t     *hsc;
1990 
1991         hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1992         if (hsc == NULL) {
1993                 cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Soft State Info",
1994                         ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
1995                 return;
1996         }
1997 
1998         hsp = hsc_find_slot(pslotnum);
1999         if (hsp == NULL) {
2000                 cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Slot Info",
2001                         ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
2002                 return;
2003         }
2004 
2005         switch (op) {
2006                 case SCSB_HSC_AC_UNCONFIGURE :
2007                         /*
2008                          * If ENUM# is enabled, then action is pending on
2009                          * this slot, just send a event.
2010                          */
2011                         if (hsc->state & HSC_ENUM_ENABLED)
2012                                 (void) hpc_slot_event_notify(
2013                                     hsp->hs_slot_handle,
2014                                     HPC_EVENT_PROCESS_ENUM, 0);
2015                         break;
2016                 case SCSB_HSC_AC_GET_SLOT_INFO :
2017                         *(hsc_slot_t **)arg = hsp;
2018                         break;
2019                 default :
2020                         break;
2021         }
2022 }
2023 
2024 static uint_t
2025 hsc_enum_intr(caddr_t iarg)
2026 {
2027         int rc;
2028         hsc_state_t *hsc = (hsc_state_t *)iarg;
2029         hsc_slot_t *hsp;
2030 
2031         DEBUG0("!E!");
2032         if ((hsc->state & HSC_ATTACHED) == 0)
2033                 return (DDI_INTR_UNCLAIMED);
2034 
2035         hsp = hsc_find_slot(hsc->slot_table_prop[0].pslotnum);
2036         if (hsp == NULL)        /* No slots registered */
2037                 return (DDI_INTR_UNCLAIMED);
2038 
2039         /*
2040          * The following must be done to clear interrupt (synchronous event).
2041          * To process the interrupt, we send an asynchronous event.
2042          */
2043         rc = hpc_slot_event_notify(hsp->hs_slot_handle,
2044                                         HPC_EVENT_CLEAR_ENUM,
2045                                                 HPC_EVENT_SYNCHRONOUS);
2046         if (rc == HPC_EVENT_UNCLAIMED) {
2047                 /*
2048                  * possible support for handling insertion of non friendly
2049                  * full hotswap boards, otherwise the system hangs due
2050                  * to uncleared interrupt bursts.
2051                  */
2052                 DEBUG2("!E>counter %d, last op@slot %lx\n",
2053                                 hsc->hsc_intr_counter, hsc->hsp_last);
2054                 hsc->hsc_intr_counter ++;
2055                 if (hsc->hsc_intr_counter == scsb_hsc_max_intr_count) {
2056                         if (!hsc->hsp_last) {
2057                                 cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: "
2058                                         " No Last Board Insertion Info.",
2059                                         ddi_driver_name(hsc->dip),
2060                                         ddi_get_instance(hsc->dip));
2061                                 hsc->hsc_intr_counter = 0;
2062                                 return (DDI_INTR_UNCLAIMED);
2063                         }
2064                         hsp = hsc->hsp_last;
2065                         cmn_err(CE_WARN, "%s#%d: Bad (non friendly ?) Board "
2066                                 "in Slot %d ? Taking it Offline.",
2067                                 ddi_driver_name(hsc->dip),
2068                                 ddi_get_instance(hsc->dip),
2069                                 hsp->hs_slot_number);
2070                         /*
2071                          * this should put just inserted board back in
2072                          * reset, thus deasserting the ENUM# and the
2073                          * system hang.
2074                          */
2075                         if (scsb_reset_slot(hsp->hs_hpchandle,
2076                                         hsp->hs_slot_number,
2077                                         SCSB_RESET_SLOT) == 0) {
2078                                 /* Enumeration failed on this board */
2079                                 hsp->hs_flags |= HSC_ENUM_FAILED;
2080                                 if (hsp->hs_board_configured == B_TRUE)
2081                                         cmn_err(CE_WARN, "%s#%d: ALERT! System"
2082                                                 " now in Inconsistent State."
2083                                                 " Halt!",
2084                                             ddi_driver_name(hsc->dip),
2085                                             ddi_get_instance(hsc->dip));
2086                                 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
2087                                                 HPC_FAULT_LED, HPC_LED_ON);
2088                         }
2089                         hsc->hsc_intr_counter = 0;
2090                 }
2091                 return (DDI_INTR_UNCLAIMED);
2092         }
2093         hsc->hsc_intr_counter = 0;
2094         /*
2095          * if interrupt success, rc denotes the PCI device number which
2096          * generated the ENUM# interrupt.
2097          */
2098         hsp = hsc_get_slot_info(hsc, rc);
2099         if (hsp == NULL) {
2100                 cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: no slot info for "
2101                         "dev %x", ddi_driver_name(hsc->dip),
2102                         ddi_get_instance(hsc->dip), rc);
2103                 return (DDI_INTR_CLAIMED);      /* interrupt already cleared */
2104         }
2105         /* if this is Alarm Card and if it is busy, dont process event */
2106         if (hsp->hs_flags & HSC_ALARM_CARD_PRES) {
2107                 if (scsb_hsc_ac_op(hsp->hs_hpchandle, hsp->hs_slot_number,
2108                                                 SCSB_HSC_AC_BUSY) == B_TRUE) {
2109                         /*
2110                          * Busy means we need to inform (envmond)alarmcard.so
2111                          * that it should save the AC configuration, stop the
2112                          * heartbeat, and shutdown the RSC link.
2113                          */
2114                         (void) scsb_hsc_ac_op(hsp->hs_hpchandle,
2115                                         hsp->hs_slot_number,
2116                                         SCSB_HSC_AC_REMOVAL_ALERT);
2117                         return (DDI_INTR_CLAIMED);
2118                 }
2119         }
2120         /*
2121          * If SCB was swapped out, dont process ENUM#. We put this slot
2122          * back in reset after SCB is inserted.
2123          */
2124         if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) &&
2125                         (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED))
2126                 return (DDI_INTR_CLAIMED);
2127 
2128         (void) hpc_slot_event_notify(hsp->hs_slot_handle,
2129             HPC_EVENT_PROCESS_ENUM, 0);
2130         return (DDI_INTR_CLAIMED);
2131 }
2132 /*
2133  * A routine to convert a number (represented as a string) to
2134  * the integer value it represents.
2135  */
2136 
2137 static int
2138 isdigit(int ch)
2139 {
2140         return (ch >= '0' && ch <= '9');
2141 }
2142 
2143 #define isspace(c)      ((c) == ' ' || (c) == '\t' || (c) == '\n')
2144 #define bad(val)        (val == NULL || !isdigit(*val))
2145 
2146 static int
2147 atoi(const char *p)
2148 {
2149         int n;
2150         int c, neg = 0;
2151 
2152         if (!isdigit(c = *p)) {
2153                 while (isspace(c))
2154                         c = *++p;
2155                 switch (c) {
2156                         case '-':
2157                                 neg++;
2158                                 /* FALLTHROUGH */
2159                         case '+':
2160                         c = *++p;
2161                 }
2162                 if (!isdigit(c))
2163                         return (0);
2164         }
2165         for (n = '0' - c; isdigit(c = *++p); ) {
2166                 n *= 10; /* two steps to avoid unnecessary overflow */
2167                 n += '0' - c; /* accum neg to avoid surprises at MAX */
2168         }
2169         return (neg ? n : -n);
2170 }