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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * **********************************************************************
  28  * Extension module for PCI nexus drivers to support PCI Hot Plug feature.
  29  *
  30  * DESCRIPTION:
  31  *    This module basically implements "devctl" and Attachment Point device
  32  *    nodes for hot plug operations. The cb_ops functions needed for access
  33  *    to these device nodes are also implemented. For hotplug operations
  34  *    on Attachment Points it interacts with the hotplug services (HPS)
  35  *    framework. A pci nexus driver would simply call pcihp_init() in its
  36  *    attach() function and pcihp_uninit() call in its detach() function.
  37  * **********************************************************************
  38  */
  39 
  40 #include <sys/conf.h>
  41 #include <sys/kmem.h>
  42 #include <sys/debug.h>
  43 #include <sys/modctl.h>
  44 #include <sys/autoconf.h>
  45 #include <sys/ddi.h>
  46 #include <sys/sunddi.h>
  47 #include <sys/sunndi.h>
  48 #include <sys/ddi_impldefs.h>
  49 #include <sys/ndi_impldefs.h>
  50 #include <sys/ddipropdefs.h>
  51 #include <sys/open.h>
  52 #include <sys/file.h>
  53 #include <sys/stat.h>
  54 #include <sys/pci.h>
  55 #include <sys/pci_impl.h>
  56 #include <sys/devctl.h>
  57 #include <sys/hotplug/hpcsvc.h>
  58 #include <sys/hotplug/pci/pcicfg.h>
  59 #include <sys/hotplug/pci/pcihp.h>
  60 #include <sys/sysevent.h>
  61 #include <sys/sysevent/eventdefs.h>
  62 #include <sys/sysevent/dr.h>
  63 #include <sys/fs/dv_node.h>
  64 
  65 /*
  66  * NOTE:
  67  * This module depends on PCI Configurator module (misc/pcicfg),
  68  * Hot Plug Services framework module (misc/hpcsvc) and Bus Resource
  69  * Allocator module (misc/busra).
  70  */
  71 
  72 /*
  73  * ************************************************************************
  74  * *** Implementation specific data structures/definitions.             ***
  75  * ************************************************************************
  76  */
  77 
  78 /* soft state */
  79 typedef enum { PCIHP_SOFT_STATE_CLOSED, PCIHP_SOFT_STATE_OPEN,
  80                 PCIHP_SOFT_STATE_OPEN_EXCL } pcihp_soft_state_t;
  81 
  82 #define PCI_MAX_DEVS    32      /* max. number of devices on a pci bus */
  83 
  84 /* the following correspond to sysevent defined subclasses */
  85 #define PCIHP_DR_AP_STATE_CHANGE        0
  86 #define PCIHP_DR_REQ                    1
  87 
  88 /*  pcihp_get_soft_state() command argument */
  89 #define PCIHP_DR_NOOP                   0
  90 #define PCIHP_DR_BUS_CONFIGURE          1
  91 #define PCIHP_DR_BUS_UNCONFIGURE        2
  92 #define PCIHP_DR_SLOT_ENTER             4
  93 #define PCIHP_DR_SLOT_EXIT              8
  94 
  95 /*  hot plug bus state */
  96 enum { PCIHP_BUS_INITIALIZING, PCIHP_BUS_UNCONFIGURED,
  97                 PCIHP_BUS_CONFIGURED };
  98 
  99 /*
 100  * Soft state structure associated with each hot plug pci bus instance.
 101  */
 102 typedef struct pcihp {
 103         struct pcihp            *nextp;
 104 
 105         /* devinfo pointer to the pci bus node */
 106         dev_info_t              *dip;
 107 
 108         /* soft state flags: PCIHP_SOFT_STATE_* */
 109         pcihp_soft_state_t      soft_state;
 110 
 111         /* global mutex to serialize exclusive access to the bus */
 112         kmutex_t                mutex;
 113 
 114         /* slot information structure */
 115         struct pcihp_slotinfo {
 116                 hpc_slot_t      slot_hdl;       /* HPS slot handle */
 117                 ap_rstate_t     rstate;         /* state of Receptacle */
 118                 ap_ostate_t     ostate;         /* state of the Occupant */
 119                 ap_condition_t  condition;      /* condition of the occupant */
 120                 time32_t        last_change;    /* XXX needed? */
 121                 uint32_t        event_mask;     /* last event mask registered */
 122                 char            *name;          /* slot logical name */
 123                 uint_t          slot_flags;
 124                 uint16_t        slot_type;      /* slot type: pci or cpci */
 125                 uint16_t        slot_capabilities; /* 64bit, etc. */
 126                 int             hs_csr_location; /* Location of HS_CSR */
 127                 kmutex_t        slot_mutex;     /* mutex to serialize hotplug */
 128                                                 /* operations on the slot */
 129         } slotinfo[PCI_MAX_DEVS];
 130 
 131         /* misc. bus attributes */
 132         uint_t                  bus_flags;
 133         uint_t                  bus_state;
 134         uint_t                  slots_active;
 135 } pcihp_t;
 136 
 137 /*
 138  * Bit definitions for slot_flags field:
 139  *
 140  *      PCIHP_SLOT_AUTO_CFG_EN  This flags is set if nexus can do auto
 141  *                              configuration of hot plugged card on this slot
 142  *                              if the hardware reports the hot plug events.
 143  *
 144  *      PCIHP_SLOT_DISABLED     Slot is disabled for hotplug operations.
 145  *
 146  *      PCIHP_SLOT_NOT_HEALTHY  HEALTHY# signal is not OK on this slot.
 147  */
 148 #define PCIHP_SLOT_AUTO_CFG_EN          0x1
 149 #define PCIHP_SLOT_DISABLED             0x2
 150 #define PCIHP_SLOT_NOT_HEALTHY          0x4
 151 #define PCIHP_SLOT_DEV_NON_HOTPLUG      0x8
 152 #define PCIHP_SLOT_ENUM_INS_PENDING     0x10
 153 #define PCIHP_SLOT_ENUM_EXT_PENDING     0x20
 154 
 155 /*
 156  * Bit definitions for bus_flags field:
 157  *
 158  *      PCIHP_BUS_66MHZ Bus is running at 66Mhz.
 159  */
 160 #define PCIHP_BUS_66MHZ         0x1
 161 #define PCIHP_BUS_ENUM_RADIAL   0x2
 162 
 163 #define PCIHP_DEVICES_STR               "/devices"
 164 
 165 /*
 166  * control structure for tree walk during configure/unconfigure operation.
 167  */
 168 struct pcihp_config_ctrl {
 169         int     pci_dev;        /* PCI device number for the slot */
 170         uint_t  flags;          /* control flags (see below) */
 171         int     op;             /* operation: PCIHP_ONLINE or PCIHP_OFFLINE */
 172         int     rv;             /* return error code */
 173         dev_info_t *dip;        /* dip at which the (first) error occurred */
 174         hpc_occupant_info_t *occupant;
 175 };
 176 
 177 /*
 178  * control flags for configure/unconfigure operations on the tree.
 179  *
 180  * PCIHP_CFG_CONTINUE   continue the operation ignoring errors
 181  */
 182 #define PCIHP_CFG_CONTINUE      0x1
 183 
 184 #define PCIHP_ONLINE    1
 185 #define PCIHP_OFFLINE   0
 186 
 187 
 188 /* Leaf ops (hotplug controls for target devices) */
 189 static int pcihp_open(dev_t *, int, int, cred_t *);
 190 static int pcihp_close(dev_t, int, int, cred_t *);
 191 static int pcihp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
 192 
 193 #ifdef DEBUG
 194 static int pcihp_debug = 0;
 195 #define PCIHP_DEBUG(args)       if (pcihp_debug >= 1) cmn_err args
 196 #define PCIHP_DEBUG2(args)      if (pcihp_debug >= 2) cmn_err args
 197 #else
 198 #define PCIHP_DEBUG(args)
 199 #define PCIHP_DEBUG2(args)
 200 #endif
 201 
 202 /*
 203  * We process ENUM# event one device at a time ie. as soon as we detect
 204  * that a device has the right ENUM# conditions, we return. If the following
 205  * variable is set to non-zero, we scan all the devices on the bus
 206  * for ENUM# conditions.
 207  */
 208 static int pcihp_enum_scan_all = 0;
 209 /*
 210  * If HSC driver cannot determine the board type (for example: it may not
 211  * be possible to differentiate between a Basic Hotswap, Non Hotswap or
 212  * Non-friendly Full hotswap board), the default board type is assigned
 213  * to be as defined by the following variable.
 214  */
 215 static int pcihp_cpci_board_type = HPC_BOARD_CPCI_NON_HS;
 216 static int pcihp_cpci_led_blink = 30;
 217 /*
 218  * It was noted that the blue LED when written on/off would cause INS/EXT
 219  * bit to be set causing an extra interrupt. Although the cPCI specifications
 220  * does not imply this, this behavior is seen with some FHS silicons.
 221  * Also, handling the INS/EXT bit would control the LED being On/Off.
 222  * Until the behavior is confirmed, this flag could be used to enable or
 223  * disable handling the LED.
 224  * 0 means the silicons handles the LED behavior via the INS/EXT bit.
 225  * 1 means the software must explicitly do the LED behavior.
 226  */
 227 static int pcihp_cpci_blue_led = 1;
 228 
 229 /* static functions */
 230 static pcihp_t *pcihp_create_soft_state(dev_info_t *dip);
 231 static void pcihp_destroy_soft_state(dev_info_t *dip);
 232 static pcihp_t *pcihp_get_soft_state(dev_info_t *dip, int cmd, int *rv);
 233 static int pcihp_configure_ap(pcihp_t *pcihp_p, int pci_dev);
 234 static int pcihp_unconfigure_ap(pcihp_t *pcihp_p, int pci_dev);
 235 static int pcihp_new_slot_state(dev_info_t *, hpc_slot_t,
 236         hpc_slot_info_t *, int);
 237 static int pcihp_configure(dev_info_t *, void *);
 238 static bool_t pcihp_check_status(dev_info_t *);
 239 static int pcihp_event_handler(caddr_t, uint_t);
 240 static dev_info_t *pcihp_devi_find(dev_info_t *dip, uint_t dev, uint_t func);
 241 static int pcihp_match_dev(dev_info_t *dip, void *hdl);
 242 static int pcihp_get_hs_csr(struct pcihp_slotinfo *, ddi_acc_handle_t,
 243         uint8_t *);
 244 static void pcihp_set_hs_csr(struct pcihp_slotinfo *, ddi_acc_handle_t,
 245         uint8_t *);
 246 static int pcihp_get_hs_csr_location(ddi_acc_handle_t);
 247 static int pcihp_handle_enum(pcihp_t *, int, int, int);
 248 static void pcihp_hs_csr_op(pcihp_t *, int, int);
 249 static int pcihp_enum_slot(pcihp_t *, struct pcihp_slotinfo *, int, int, int);
 250 static int pcihp_handle_enum_extraction(pcihp_t *, int, int, int);
 251 static int pcihp_handle_enum_insertion(pcihp_t *, int, int, int);
 252 static int pcihp_add_dummy_reg_property(dev_info_t *, uint_t, uint_t, uint_t);
 253 static int pcihp_config_setup(dev_info_t **, ddi_acc_handle_t *,
 254                         dev_info_t **, int, pcihp_t *);
 255 static void pcihp_config_teardown(ddi_acc_handle_t *,
 256                         dev_info_t **, int, pcihp_t *);
 257 static int pcihp_get_board_type(struct pcihp_slotinfo *);
 258 /* sysevent function */
 259 static void pcihp_gen_sysevent(char *, int, int, dev_info_t *, int);
 260 
 261 static int pcihp_list_occupants(dev_info_t *, void *);
 262 static int pcihp_indirect_map(dev_info_t *dip);
 263 
 264 #if 0
 265 static void pcihp_probe_slot_state(dev_info_t *, int, hpc_slot_state_t *);
 266 #endif
 267 
 268 int pcihp_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
 269     int flags, char *name, caddr_t valuep, int *lengthp);
 270 
 271 struct cb_ops pcihp_cb_ops = {
 272         pcihp_open,                     /* open */
 273         pcihp_close,                    /* close */
 274         nodev,                          /* strategy */
 275         nodev,                          /* print */
 276         nodev,                          /* dump */
 277         nodev,                          /* read */
 278         nodev,                          /* write */
 279         pcihp_ioctl,                    /* ioctl */
 280         nodev,                          /* devmap */
 281         nodev,                          /* mmap */
 282         nodev,                          /* segmap */
 283         nochpoll,                       /* poll */
 284         pcihp_prop_op,                  /* cb_prop_op */
 285         NULL,                           /* streamtab */
 286         D_NEW | D_MP | D_HOTPLUG,       /* Driver compatibility flag */
 287         CB_REV,                         /* rev */
 288         nodev,                          /* int (*cb_aread)() */
 289         nodev                           /* int (*cb_awrite)() */
 290 };
 291 
 292 /*
 293  * local data
 294  */
 295 
 296 int pcihp_autocfg_enabled = 1; /* auto config is enabled by default */
 297 
 298 static kmutex_t pcihp_mutex; /* mutex to protect the following data */
 299 static pcihp_t *pcihp_head = NULL;
 300 
 301 static kmutex_t pcihp_open_mutex; /* mutex to protect open/close/uninit */
 302 static int      pci_devlink_flags = 0;
 303 
 304 /*
 305  * Module linkage information for the kernel.
 306  */
 307 extern struct mod_ops mod_miscops;
 308 static struct modlmisc modlmisc = {
 309         &mod_miscops,
 310         "PCI nexus hotplug support",
 311 };
 312 
 313 static struct modlinkage modlinkage = {
 314         MODREV_1,
 315         { &modlmisc, NULL }
 316 };
 317 
 318 int
 319 _init(void)
 320 {
 321         int error;
 322 
 323         mutex_init(&pcihp_mutex, NULL, MUTEX_DRIVER, NULL);
 324         mutex_init(&pcihp_open_mutex, NULL, MUTEX_DRIVER, NULL);
 325         if ((error = mod_install(&modlinkage)) != 0) {
 326                 mutex_destroy(&pcihp_open_mutex);
 327                 mutex_destroy(&pcihp_mutex);
 328         }
 329 
 330         return (error);
 331 }
 332 
 333 int
 334 _fini(void)
 335 {
 336         return (EBUSY);
 337 }
 338 
 339 int
 340 _info(struct modinfo *modinfop)
 341 {
 342         return (mod_info(&modlinkage, modinfop));
 343 }
 344 
 345 static  pcihp_t *
 346 pcihp_create_soft_state(
 347         dev_info_t *dip)
 348 {
 349         pcihp_t *pcihp_p;
 350 
 351         pcihp_p = kmem_zalloc(sizeof (struct pcihp), KM_SLEEP);
 352 
 353         pcihp_p->dip = dip;
 354         mutex_init(&pcihp_p->mutex, NULL, MUTEX_DRIVER, NULL);
 355 
 356         mutex_enter(&pcihp_mutex);
 357         pcihp_p->nextp = pcihp_head;
 358         pcihp_head = pcihp_p;
 359         pcihp_p->bus_state = PCIHP_BUS_INITIALIZING;
 360         pcihp_p->slots_active = 0;
 361         mutex_exit(&pcihp_mutex);
 362 
 363         return (pcihp_p);
 364 }
 365 
 366 static  void
 367 pcihp_destroy_soft_state(
 368         dev_info_t *dip)
 369 {
 370         pcihp_t *p;
 371         pcihp_t **pp;
 372 
 373         mutex_enter(&pcihp_mutex);
 374         pp = &pcihp_head;
 375         while ((p = *pp) != NULL) {
 376                 if (p->dip == dip) {
 377                         *pp = p->nextp;
 378                         kmem_free(p, sizeof (struct pcihp));
 379                         break;
 380                 }
 381                 pp = &(p->nextp);
 382         }
 383         mutex_exit(&pcihp_mutex);
 384 }
 385 
 386 /*
 387  * This function should be imported by client nexus drivers as their
 388  * devo_getinfo() entry point.
 389  */
 390 
 391 /* ARGSUSED */
 392 int
 393 pcihp_info(
 394         dev_info_t      *dip,
 395         ddi_info_cmd_t  cmd,
 396         void            *arg,
 397         void            **result)
 398 {
 399         pcihp_t         *pcihp_p;
 400         major_t         major;
 401         minor_t         minor;
 402         int             instance;
 403 
 404         major = getmajor((dev_t)arg);
 405         minor = getminor((dev_t)arg);
 406         instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
 407 
 408         switch (cmd) {
 409         default:
 410                 return (DDI_FAILURE);
 411 
 412         case DDI_INFO_DEVT2INSTANCE:
 413                 *result = (void *)(intptr_t)instance;
 414                 return (DDI_SUCCESS);
 415 
 416         case DDI_INFO_DEVT2DEVINFO:
 417                 mutex_enter(&pcihp_mutex);
 418                 pcihp_p = pcihp_head;
 419                 while (pcihp_p != NULL) {
 420                         if (ddi_driver_major(pcihp_p->dip) ==
 421                             major && ddi_get_instance(pcihp_p->dip) ==
 422                             instance) {
 423                                 *result = (void *)pcihp_p->dip;
 424                                 mutex_exit(&pcihp_mutex);
 425                                 return (DDI_SUCCESS);
 426                         }
 427                         pcihp_p = pcihp_p->nextp;
 428                 }
 429                 mutex_exit(&pcihp_mutex);
 430                 return (DDI_FAILURE);
 431         }
 432 }
 433 
 434 /*
 435  * This function retrieves the hot plug soft state and performs the
 436  * following primitive commands while the soft state is locked:
 437  * mark the bus unconfigured, increment slot activity, decrement
 438  * slot activity and noop.
 439  */
 440 
 441 /* ARGSUSED */
 442 static  pcihp_t *
 443 pcihp_get_soft_state(
 444         dev_info_t      *dip, int cmd, int *rv)
 445 {
 446         pcihp_t         *pcihp_p;
 447 
 448         *rv = PCIHP_SUCCESS;
 449         mutex_enter(&pcihp_mutex);
 450         pcihp_p = pcihp_head;
 451         while (pcihp_p != NULL) {
 452                 if (pcihp_p->dip == dip) {
 453                         switch (cmd) {
 454                         case PCIHP_DR_BUS_UNCONFIGURE:
 455                                 if (pcihp_p->slots_active == 0)
 456                                         pcihp_p->bus_state =
 457                                             PCIHP_BUS_UNCONFIGURED;
 458                                 else
 459                                         *rv = PCIHP_FAILURE;
 460                                 break;
 461                         case PCIHP_DR_SLOT_ENTER:
 462                                 if (pcihp_p->bus_state ==
 463                                     PCIHP_BUS_UNCONFIGURED)
 464                                         *rv = PCIHP_FAILURE;
 465                                 else
 466                                         pcihp_p->slots_active++;
 467                                 break;
 468                         case PCIHP_DR_SLOT_EXIT:
 469                                 ASSERT(pcihp_p->slots_active > 0);
 470                                 if (pcihp_p->slots_active == 0)
 471                                         cmn_err(CE_PANIC,
 472                                             "pcihp (%s%d): mismatched slot"
 473                                             " activity",
 474                                             ddi_driver_name(dip),
 475                                             ddi_get_instance(dip));
 476                                 else
 477                                         pcihp_p->slots_active--;
 478                                 break;
 479                         case PCIHP_DR_NOOP:
 480                                 break;
 481                         default:
 482                                 *rv = PCIHP_FAILURE;
 483                                 break;
 484                         }
 485                         mutex_exit(&pcihp_mutex);
 486                         return (pcihp_p);
 487                 }
 488                 pcihp_p = pcihp_p->nextp;
 489         }
 490         mutex_exit(&pcihp_mutex);
 491 
 492         return (NULL);
 493 }
 494 
 495 /* ARGSUSED3 */
 496 static int
 497 pcihp_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 498 {
 499         dev_info_t *self;
 500         pcihp_t *pcihp_p;
 501         minor_t minor;
 502         int pci_dev;
 503         int rv;
 504 
 505         /*
 506          * Make sure the open is for the right file type.
 507          */
 508         if (otyp != OTYP_CHR)
 509                 return (EINVAL);
 510 
 511         mutex_enter(&pcihp_open_mutex);
 512         /*
 513          * Get the soft state structure.
 514          */
 515         if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)*devp,
 516             (void **)&self) != DDI_SUCCESS) {
 517                 mutex_exit(&pcihp_open_mutex);
 518                 return (ENXIO);
 519         }
 520 
 521         pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_NOOP, &rv);
 522         ASSERT(pcihp_p != NULL);
 523 
 524         mutex_enter(&pcihp_p->mutex);
 525 
 526         /*
 527          * If the pci_dev is valid then the minor device is an
 528          * AP. Otherwise it is ":devctl" minor device.
 529          */
 530         minor = getminor(*devp);
 531         pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor);
 532         if (pci_dev < PCI_MAX_DEVS) {
 533                 struct pcihp_slotinfo *slotinfop;
 534 
 535                 slotinfop = &pcihp_p->slotinfo[pci_dev];
 536                 if (slotinfop->slot_hdl == NULL) {
 537                         mutex_exit(&pcihp_p->mutex);
 538                         mutex_exit(&pcihp_open_mutex);
 539                         return (ENXIO);
 540                 }
 541         }
 542 
 543         /*
 544          * Handle the open by tracking the device state.
 545          *
 546          * Note: Needs review w.r.t exclusive access to AP or the bus.
 547          * Currently in the pci plug-in we don't use EXCL open at all
 548          * so the code below implements EXCL access on the bus.
 549          */
 550 
 551         /* enforce exclusive access to the bus */
 552         if ((pcihp_p->soft_state == PCIHP_SOFT_STATE_OPEN_EXCL) ||
 553             ((flags & FEXCL) &&
 554             (pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED))) {
 555                 mutex_exit(&pcihp_p->mutex);
 556                 mutex_exit(&pcihp_open_mutex);
 557                 return (EBUSY);
 558         }
 559 
 560         if (flags & FEXCL)
 561                 pcihp_p->soft_state = PCIHP_SOFT_STATE_OPEN_EXCL;
 562         else
 563                 pcihp_p->soft_state = PCIHP_SOFT_STATE_OPEN;
 564 
 565         mutex_exit(&pcihp_p->mutex);
 566         mutex_exit(&pcihp_open_mutex);
 567 
 568         return (0);
 569 }
 570 
 571 /* ARGSUSED */
 572 static int
 573 pcihp_close(dev_t dev, int flags, int otyp, cred_t *credp)
 574 {
 575         dev_info_t *self;
 576         pcihp_t *pcihp_p;
 577         int rv;
 578 
 579         if (otyp != OTYP_CHR)
 580                 return (EINVAL);
 581 
 582         mutex_enter(&pcihp_open_mutex);
 583 
 584         if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)dev,
 585             (void **)&self) != DDI_SUCCESS) {
 586                 mutex_exit(&pcihp_open_mutex);
 587                 return (ENXIO);
 588         }
 589 
 590         pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_NOOP, &rv);
 591         ASSERT(pcihp_p != NULL);
 592 
 593         mutex_enter(&pcihp_p->mutex);
 594         pcihp_p->soft_state = PCIHP_SOFT_STATE_CLOSED;
 595         mutex_exit(&pcihp_p->mutex);
 596 
 597         mutex_exit(&pcihp_open_mutex);
 598 
 599         return (0);
 600 }
 601 
 602 static int
 603 pcihp_list_occupants(dev_info_t *dip, void *hdl)
 604 {
 605         int pci_dev;
 606         struct pcihp_config_ctrl *ctrl = (struct pcihp_config_ctrl *)hdl;
 607         pci_regspec_t *pci_rp;
 608         int length;
 609         major_t major;
 610 
 611         /*
 612          * Get the PCI device number information from the devinfo
 613          * node. Since the node may not have the address field
 614          * setup (this is done in the DDI_INITCHILD of the parent)
 615          * we look up the 'reg' property to decode that information.
 616          */
 617         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
 618             DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
 619             (uint_t *)&length) != DDI_PROP_SUCCESS) {
 620                 ctrl->rv = DDI_FAILURE;
 621                 ctrl->dip = dip;
 622                 return (DDI_WALK_TERMINATE);
 623         }
 624 
 625         /* get the pci device id information */
 626         pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
 627 
 628         /*
 629          * free the memory allocated by ddi_prop_lookup_int_array
 630          */
 631         ddi_prop_free(pci_rp);
 632 
 633         /*
 634          * Match the node for the device number of the slot.
 635          */
 636         if (pci_dev == ctrl->pci_dev) { /* node is a match */
 637 
 638                 major = ddi_driver_major(dip);
 639 
 640                 /*
 641                  * If the node is not yet attached, then don't list it
 642                  * as an occupant. This is valid, since nothing can be
 643                  * consuming it until it is attached, and cfgadm will
 644                  * ask for the property explicitly which will cause it
 645                  * to be re-freshed right before checking with rcm.
 646                  */
 647                 if ((major == -1) || !i_ddi_devi_attached(dip))
 648                         return (DDI_WALK_PRUNECHILD);
 649 
 650                 /*
 651                  * If we have used all our occupants then print mesage
 652                  * and terminate walk.
 653                  */
 654                 if (ctrl->occupant->i >= HPC_MAX_OCCUPANTS) {
 655                         cmn_err(CE_WARN,
 656                             "pcihp (%s%d): unable to list all occupants",
 657                             ddi_driver_name(ddi_get_parent(dip)),
 658                             ddi_get_instance(ddi_get_parent(dip)));
 659                         return (DDI_WALK_TERMINATE);
 660                 }
 661 
 662                 /*
 663                  * No need to hold the dip as ddi_walk_devs
 664                  * has already arranged that for us.
 665                  */
 666                 ctrl->occupant->id[ctrl->occupant->i] =
 667                     kmem_alloc(sizeof (char[MAXPATHLEN]), KM_SLEEP);
 668                 (void) ddi_pathname(dip,
 669                     (char *)ctrl->occupant->id[ctrl->occupant->i]);
 670                 ctrl->occupant->i++;
 671         }
 672 
 673         /*
 674          * continue the walk to the next sibling to look for a match
 675          * or to find other nodes if this card is a multi-function card.
 676          */
 677         return (DDI_WALK_PRUNECHILD);
 678 }
 679 
 680 static void
 681 pcihp_create_occupant_props_nolock(dev_info_t *self, dev_t dev, int pci_dev)
 682 {
 683         struct pcihp_config_ctrl ctrl;
 684         hpc_occupant_info_t *occupant;
 685         int i;
 686 
 687         occupant = kmem_alloc(sizeof (hpc_occupant_info_t), KM_SLEEP);
 688         occupant->i = 0;
 689 
 690         ctrl.flags = 0;
 691         ctrl.dip = NULL;
 692         ctrl.rv = NDI_SUCCESS;
 693         ctrl.pci_dev = pci_dev;
 694         ctrl.op = 55; /* should define DRYRUN */
 695         ctrl.occupant = occupant;
 696 
 697         ddi_walk_devs(ddi_get_child(self), pcihp_list_occupants,
 698             (void *)&ctrl);
 699 
 700         if (occupant->i == 0) {
 701                 /* no occupants right now, need to create stub property */
 702                 char *c[] = { "" };
 703                 (void) ddi_prop_update_string_array(dev, self, "pci-occupant",
 704                     c, 1);
 705         } else {
 706                 (void) ddi_prop_update_string_array(dev, self, "pci-occupant",
 707                     occupant->id, occupant->i);
 708         }
 709         for (i = 0; i < occupant->i; i++) {
 710                 kmem_free(occupant->id[i], sizeof (char[MAXPATHLEN]));
 711         }
 712 
 713         kmem_free(occupant, sizeof (hpc_occupant_info_t));
 714 }
 715 
 716 static void
 717 pcihp_create_occupant_props(dev_info_t *self, dev_t dev, int pci_dev)
 718 {
 719         int circular;
 720 
 721         ndi_devi_enter(self, &circular);
 722         pcihp_create_occupant_props_nolock(self, dev, pci_dev);
 723         ndi_devi_exit(self, circular);
 724 }
 725 
 726 static void
 727 pcihp_delete_occupant_props(dev_info_t *dip, dev_t dev)
 728 {
 729         if (ddi_prop_remove(dev, dip, "pci-occupant")
 730             != DDI_PROP_SUCCESS)
 731                 return; /* add error handling */
 732 
 733 }
 734 
 735 /*
 736  * pcihp_ioctl: devctl hotplug controls
 737  */
 738 /* ARGSUSED */
 739 static int
 740 pcihp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
 741         int *rvalp)
 742 {
 743         pcihp_t *pcihp_p;
 744         dev_info_t *self;
 745         struct devctl_iocdata *dcp;
 746         uint_t bus_state;
 747         int rv = 0;
 748         int pci_dev;
 749         struct pcihp_slotinfo *slotinfop;
 750         hpc_slot_state_t rstate;
 751         devctl_ap_state_t ap_state;
 752         struct hpc_control_data hpc_ctrldata;
 753         struct hpc_led_info led_info;
 754         time_t time;
 755         int state_locking;
 756         int state_unlocking;
 757         int rval;
 758         char *pathname = NULL;
 759 
 760         /*
 761          * read devctl ioctl data before soft state retrieval
 762          */
 763         if ((cmd != DEVCTL_AP_CONTROL) &&
 764             ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
 765                 return (EFAULT);
 766 
 767         if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)dev,
 768             (void **)&self) != DDI_SUCCESS) {
 769                 if (cmd != DEVCTL_AP_CONTROL)
 770                         ndi_dc_freehdl(dcp);
 771                 return (ENXIO);
 772         }
 773 
 774         switch (cmd) {
 775         case DEVCTL_AP_INSERT:
 776         case DEVCTL_AP_REMOVE:
 777         case DEVCTL_AP_CONNECT:
 778         case DEVCTL_AP_DISCONNECT:
 779         case DEVCTL_AP_CONFIGURE:
 780         case DEVCTL_AP_UNCONFIGURE:
 781         case DEVCTL_AP_GETSTATE:
 782         case DEVCTL_AP_CONTROL:
 783                 state_locking = PCIHP_DR_SLOT_ENTER;
 784                 state_unlocking = PCIHP_DR_SLOT_EXIT;
 785                 break;
 786         default:
 787                 state_locking = PCIHP_DR_NOOP;
 788                 state_unlocking = PCIHP_DR_NOOP;
 789                 break;
 790         }
 791 
 792         pcihp_p = pcihp_get_soft_state(self, state_locking, &rval);
 793         ASSERT(pcihp_p != NULL);
 794 
 795         if (rval == PCIHP_FAILURE) {
 796                 (void) ddi_pathname(pcihp_p->dip, pathname);
 797                 PCIHP_DEBUG((CE_WARN, "Hot Plug bus %s instance is unconfigured"
 798                     " while slot activity is requested\n", pathname));
 799                 if (cmd != DEVCTL_AP_CONTROL)
 800                         ndi_dc_freehdl(dcp);
 801                 return (EBUSY);
 802         }
 803 
 804         /*
 805          * For attachment points the lower 8 bits of the minor number is the
 806          * PCI device number.
 807          */
 808         pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
 809 
 810         /*
 811          * We can use the generic implementation for these ioctls
 812          */
 813         switch (cmd) {
 814         case DEVCTL_DEVICE_GETSTATE:
 815         case DEVCTL_DEVICE_ONLINE:
 816         case DEVCTL_DEVICE_OFFLINE:
 817         case DEVCTL_BUS_GETSTATE:
 818                 rv = ndi_devctl_ioctl(self, cmd, arg, mode, 0);
 819                 ndi_dc_freehdl(dcp);
 820                 return (rv);
 821         default:
 822                 break;
 823         }
 824 
 825         switch (cmd) {
 826 
 827         case DEVCTL_DEVICE_RESET:
 828                 rv = ENOTSUP;
 829                 break;
 830 
 831         case DEVCTL_BUS_QUIESCE:
 832                 if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
 833                         if (bus_state == BUS_QUIESCED)
 834                                 break;
 835                 (void) ndi_set_bus_state(self, BUS_QUIESCED);
 836                 break;
 837 
 838         case DEVCTL_BUS_UNQUIESCE:
 839                 if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
 840                         if (bus_state == BUS_ACTIVE)
 841                                 break;
 842                 (void) ndi_set_bus_state(self, BUS_ACTIVE);
 843                 break;
 844 
 845         case DEVCTL_BUS_RESET:
 846                 rv = ENOTSUP;
 847                 break;
 848 
 849         case DEVCTL_BUS_RESETALL:
 850                 rv = ENOTSUP;
 851                 break;
 852 
 853         case DEVCTL_AP_CONNECT:
 854         case DEVCTL_AP_DISCONNECT:
 855                 /*
 856                  * CONNECT(DISCONNECT) the hot plug slot to(from) the bus.
 857                  *
 858                  * For cPCI slots this operation is a nop so the HPC
 859                  * driver may return success if it is a valid operation.
 860                  */
 861         case DEVCTL_AP_INSERT:
 862         case DEVCTL_AP_REMOVE:
 863                 /*
 864                  * Prepare the slot for INSERT/REMOVE operation.
 865                  */
 866 
 867                 /*
 868                  * check for valid request:
 869                  *      1. It is a hotplug slot.
 870                  *      2. The slot has no occupant that is in
 871                  *         the 'configured' state.
 872                  */
 873                 if (pci_dev >= PCI_MAX_DEVS) {
 874                         rv = ENXIO;
 875                         break;
 876                 }
 877                 slotinfop = &pcihp_p->slotinfo[pci_dev];
 878 
 879                 mutex_enter(&slotinfop->slot_mutex);
 880 
 881                 if ((slotinfop->slot_hdl == NULL) ||
 882                     (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
 883                         rv = ENXIO;
 884                         mutex_exit(&slotinfop->slot_mutex);
 885                         break;
 886                 }
 887 
 888                 /* the slot occupant must be in the UNCONFIGURED state */
 889                 if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
 890                         rv = EINVAL;
 891                         mutex_exit(&slotinfop->slot_mutex);
 892                         break;
 893                 }
 894                 /*
 895                  * Call the HPC driver to perform the operation on the slot.
 896                  */
 897 
 898                 switch (cmd) {
 899                 case DEVCTL_AP_INSERT:
 900                         rv = hpc_nexus_insert(slotinfop->slot_hdl, NULL, 0);
 901                         break;
 902                 case DEVCTL_AP_REMOVE:
 903                         rv = hpc_nexus_remove(slotinfop->slot_hdl, NULL, 0);
 904                         break;
 905                 case DEVCTL_AP_CONNECT:
 906                         rv = hpc_nexus_connect(slotinfop->slot_hdl, NULL, 0);
 907                         if (rv == HPC_SUCCESS) {
 908                                 slotinfop->rstate = AP_RSTATE_CONNECTED;
 909 
 910                                 if (drv_getparm(TIME, (void *)&time) !=
 911                                     DDI_SUCCESS)
 912                                         slotinfop->last_change = (time_t)-1;
 913                                 else
 914                                         slotinfop->last_change = (time32_t)time;
 915 
 916                                 slotinfop = &pcihp_p->slotinfo[pci_dev];
 917                                 pcihp_gen_sysevent(slotinfop->name,
 918                                     PCIHP_DR_AP_STATE_CHANGE,
 919                                     SE_NO_HINT, pcihp_p->dip,
 920                                     KM_SLEEP);
 921                         }
 922                         break;
 923                 case DEVCTL_AP_DISCONNECT:
 924                         rv = hpc_nexus_disconnect(slotinfop->slot_hdl, NULL, 0);
 925                         if (rv == HPC_SUCCESS) {
 926                                 slotinfop->rstate = AP_RSTATE_DISCONNECTED;
 927 
 928                                 if (drv_getparm(TIME, (void *)&time) !=
 929                                     DDI_SUCCESS)
 930                                         slotinfop->last_change = (time_t)-1;
 931                                 else
 932                                         slotinfop->last_change = (time32_t)time;
 933 
 934                                 slotinfop = &pcihp_p->slotinfo[pci_dev];
 935                                 pcihp_gen_sysevent(slotinfop->name,
 936                                     PCIHP_DR_AP_STATE_CHANGE,
 937                                     SE_NO_HINT, pcihp_p->dip,
 938                                     KM_SLEEP);
 939                         }
 940                         break;
 941                 }
 942                 mutex_exit(&slotinfop->slot_mutex);
 943 
 944                 switch (rv) {
 945                 case HPC_ERR_INVALID:
 946                         rv = ENXIO;
 947                         break;
 948                 case HPC_ERR_NOTSUPPORTED:
 949                         rv = ENOTSUP;
 950                         break;
 951                 case HPC_ERR_FAILED:
 952                         rv = EIO;
 953                         break;
 954                 }
 955 
 956                 break;
 957 
 958         case DEVCTL_AP_CONFIGURE:
 959                 /*
 960                  * **************************************
 961                  * CONFIGURE the occupant in the slot.
 962                  * **************************************
 963                  */
 964                 slotinfop = &pcihp_p->slotinfo[pci_dev];
 965 
 966                 mutex_enter(&slotinfop->slot_mutex);
 967 
 968                 rv = pcihp_configure_ap(pcihp_p, pci_dev);
 969                 if (rv == HPC_SUCCESS) {
 970                         pcihp_gen_sysevent(slotinfop->name,
 971                             PCIHP_DR_AP_STATE_CHANGE,
 972                             SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
 973                         pcihp_create_occupant_props(self, dev, pci_dev);
 974                 }
 975                 mutex_exit(&slotinfop->slot_mutex);
 976 
 977                 break;
 978 
 979         case DEVCTL_AP_UNCONFIGURE:
 980                 /*
 981                  * **************************************
 982                  * UNCONFIGURE the occupant in the slot.
 983                  * **************************************
 984                  */
 985                 slotinfop = &pcihp_p->slotinfo[pci_dev];
 986 
 987                 mutex_enter(&slotinfop->slot_mutex);
 988 
 989                 rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
 990 
 991                 if (rv == HPC_SUCCESS) {
 992                         pcihp_gen_sysevent(slotinfop->name,
 993                             PCIHP_DR_AP_STATE_CHANGE,
 994                             SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
 995                         pcihp_delete_occupant_props(pcihp_p->dip, dev);
 996                 }
 997                 mutex_exit(&slotinfop->slot_mutex);
 998 
 999                 break;
1000 
1001         case DEVCTL_AP_GETSTATE:
1002         {
1003                 int mutex_held;
1004 
1005                 /*
1006                  * return the state of Attachment Point.
1007                  *
1008                  * If the occupant is in UNCONFIGURED state then
1009                  * we should get the receptacle state from the
1010                  * HPC driver because the receptacle state
1011                  * maintained in the nexus may not be accurate.
1012                  */
1013 
1014                 /*
1015                  * check for valid request:
1016                  *      1. It is a hotplug slot.
1017                  */
1018                 slotinfop = &pcihp_p->slotinfo[pci_dev];
1019 
1020                 /* try to acquire the slot mutex */
1021                 mutex_held = mutex_tryenter(&slotinfop->slot_mutex);
1022 
1023                 if (pci_dev >= PCI_MAX_DEVS || slotinfop->slot_hdl == NULL) {
1024                         rv = ENXIO;
1025                         if (mutex_held) {
1026                                 mutex_exit(&slotinfop->slot_mutex);
1027                         }
1028                         break;
1029                 }
1030 
1031                 if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED) {
1032                         if (hpc_nexus_control(slotinfop->slot_hdl,
1033                             HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
1034                                 rv = EIO;
1035                                 if (mutex_held)
1036                                         mutex_exit(&slotinfop->slot_mutex);
1037                                 break;
1038                         }
1039                         slotinfop->rstate = (ap_rstate_t)rstate;
1040                 }
1041 
1042                 ap_state.ap_rstate = slotinfop->rstate;
1043                 ap_state.ap_ostate = slotinfop->ostate;
1044                 ap_state.ap_condition = slotinfop->condition;
1045                 ap_state.ap_last_change = slotinfop->last_change;
1046                 ap_state.ap_error_code = 0; /* XXX */
1047                 if (mutex_held)
1048                         ap_state.ap_in_transition = 0; /* AP is not busy */
1049                 else
1050                         ap_state.ap_in_transition = 1; /* AP is busy */
1051 
1052                 if (mutex_held)
1053                         mutex_exit(&slotinfop->slot_mutex);
1054 
1055                 /* copy the return-AP-state information to the user space */
1056                 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS)
1057                         rv = EFAULT;
1058 
1059                 break;
1060 
1061         }
1062         case DEVCTL_AP_CONTROL:
1063                 /*
1064                  * HPC control functions:
1065                  *      HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT
1066                  *              Changes the state of the slot and preserves
1067                  *              the state across the reboot.
1068                  *      HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG
1069                  *              Enables or disables the auto configuration
1070                  *              of hot plugged occupant if the hardware
1071                  *              supports notification of the hot plug
1072                  *              events.
1073                  *      HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE
1074                  *              Controls the state of an LED.
1075                  *      HPC_CTRL_GET_SLOT_INFO
1076                  *              Get slot information data structure
1077                  *              (hpc_slot_info_t).
1078                  *      HPC_CTRL_GET_BOARD_TYPE
1079                  *              Get board type information (hpc_board_type_t).
1080                  *      HPC_CTRL_GET_CARD_INFO
1081                  *              Get card information (hpc_card_info_t).
1082                  *
1083                  * These control functions are used by the cfgadm plug-in
1084                  * to implement "-x" and "-v" options.
1085                  */
1086 
1087                 /* copy user ioctl data first */
1088                 switch (ddi_model_convert_from(mode & FMODELS)) {
1089                 case DDI_MODEL_ILP32: {
1090                         struct hpc_control32_data hpc_ctrldata32;
1091 
1092                         if (copyin((void *)arg, (void *)&hpc_ctrldata32,
1093                                 sizeof (struct hpc_control32_data)) != 0) {
1094                                 rv = EFAULT;
1095                                 break;
1096                         }
1097                         hpc_ctrldata.cmd = hpc_ctrldata32.cmd;
1098                         hpc_ctrldata.data =
1099                             (void *)(intptr_t)hpc_ctrldata32.data;
1100                         break;
1101                 }
1102                 case DDI_MODEL_NONE:
1103                         if (copyin((void *)arg, (void *)&hpc_ctrldata,
1104                             sizeof (struct hpc_control_data)) != 0) {
1105                                 rv = EFAULT;
1106                         }
1107                         break;
1108                 default:
1109                         rv = EFAULT;
1110                         break;
1111                 }
1112                 if (rv == EFAULT)
1113                         break;
1114                 /*
1115                  * check for valid request:
1116                  *      1. It is a hotplug slot.
1117                  */
1118                 slotinfop = &pcihp_p->slotinfo[pci_dev];
1119 
1120                 mutex_enter(&slotinfop->slot_mutex);
1121 
1122                 if (pci_dev >= PCI_MAX_DEVS || slotinfop->slot_hdl == NULL) {
1123                         rv = ENXIO;
1124                         mutex_exit(&slotinfop->slot_mutex);
1125                         break;
1126                 }
1127 
1128                 switch (hpc_ctrldata.cmd) {
1129 
1130                 case HPC_CTRL_GET_LED_STATE:
1131                         /* copy the led info from the user space */
1132                         if (copyin(hpc_ctrldata.data, (void *)&led_info,
1133                             sizeof (hpc_led_info_t)) != 0) {
1134                                 rv = EFAULT;
1135                                 break;
1136                         }
1137 
1138                         /* get the state of LED information */
1139                         if (hpc_nexus_control(slotinfop->slot_hdl,
1140                             HPC_CTRL_GET_LED_STATE, (caddr_t)&led_info) != 0) {
1141 
1142                                 if (rv != ENOTSUP)
1143                                         rv = EIO;
1144 
1145                                 break;
1146                         }
1147 
1148                         /* copy the led info to the user space */
1149                         if (copyout((void *)&led_info, hpc_ctrldata.data,
1150                             sizeof (hpc_led_info_t)) != 0) {
1151                                 rv = EFAULT;
1152                                 break;
1153                         }
1154 
1155                         break;
1156 
1157                 case HPC_CTRL_SET_LED_STATE:
1158                         /* copy the led info from the user space */
1159                         if (copyin(hpc_ctrldata.data, (void *)&led_info,
1160                             sizeof (hpc_led_info_t)) != 0) {
1161                                 rv = EFAULT;
1162                                 break;
1163                         }
1164 
1165                         /* set the state of an LED */
1166                         rv = hpc_nexus_control(slotinfop->slot_hdl,
1167                             HPC_CTRL_SET_LED_STATE, (caddr_t)&led_info);
1168 
1169                         /*
1170                          * If the Hotswap Controller does not support
1171                          * LED management (as you would find typically
1172                          * in the cPCI industry), then we handle the
1173                          * blue LED on/off/blink operations, just in
1174                          * case it helps slot identification.
1175                          */
1176                         if ((rv == HPC_ERR_NOTSUPPORTED) &&
1177                             (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)) {
1178                                 if (led_info.led != HPC_ATTN_LED)
1179                                         break;
1180 
1181                                 switch (led_info.state) {
1182                                 case HPC_LED_OFF:
1183                                         pcihp_hs_csr_op(pcihp_p,
1184                                             pci_dev,
1185                                             HPC_EVENT_SLOT_BLUE_LED_OFF);
1186                                         rv = 0;
1187                                         break;
1188                                 case HPC_LED_ON:
1189                                         /*
1190                                          * Please note that leaving
1191                                          * LED ON could be dangerous
1192                                          * as it means it is Ok to
1193                                          * remove the board, which
1194                                          * is not what we want to
1195                                          * convey. So it is upto the
1196                                          * user to take care of this
1197                                          * situation and usage.
1198                                          *
1199                                          * Normally, a Blink command
1200                                          * is more appropriate for
1201                                          * identifying a board.
1202                                          */
1203                                         pcihp_hs_csr_op(pcihp_p,
1204                                             pci_dev,
1205                                             HPC_EVENT_SLOT_BLUE_LED_ON);
1206                                         rv = 0;
1207                                         break;
1208                                 case HPC_LED_BLINK:
1209                                 {
1210                                         int bl;
1211 
1212                                         for (bl = 0; bl < 2; bl++) {
1213                                                 pcihp_hs_csr_op(pcihp_p,
1214                                                     pci_dev,
1215                                                     HPC_EVENT_SLOT_BLUE_LED_ON);
1216                                                 delay(pcihp_cpci_led_blink);
1217                                         pcihp_hs_csr_op(pcihp_p,
1218                                             pci_dev,
1219                                             HPC_EVENT_SLOT_BLUE_LED_OFF);
1220                                                 delay(pcihp_cpci_led_blink);
1221                                         }
1222                                         rv = 0;
1223                                         break;
1224                                 }
1225                                 default:
1226                                         break;
1227                                 }
1228                         }
1229 
1230                         if (rv == HPC_ERR_FAILED)
1231                                 rv = EIO;
1232                         break;
1233 
1234                 case HPC_CTRL_ENABLE_SLOT:
1235 
1236                         /*
1237                          * If slot already enabled, do not send a duplicate
1238                          * control message to the HPC driver.
1239                          */
1240                         if ((slotinfop->slot_flags & PCIHP_SLOT_DISABLED) == 0)
1241                                 break;
1242 
1243                         /* tell the HPC driver also */
1244                         if (hpc_nexus_control(slotinfop->slot_hdl,
1245                             HPC_CTRL_ENABLE_SLOT, NULL) != HPC_SUCCESS) {
1246                                 rv = EIO;
1247                                 break;
1248                         }
1249 
1250                         /*
1251                          * Enable the slot for hotplug operations.
1252                          */
1253                         slotinfop->slot_flags &= ~PCIHP_SLOT_DISABLED;
1254 
1255                         slotinfop->condition = AP_COND_UNKNOWN;
1256 
1257                         /* XXX need to preserve this state across reboot? */
1258 
1259                         break;
1260 
1261                 case HPC_CTRL_DISABLE_SLOT:
1262 
1263                         /* Do not disable if occupant configured */
1264                         if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
1265                                 rv = EAGAIN;
1266                                 break;
1267                         }
1268 
1269                         /* tell the HPC driver also */
1270                         if (hpc_nexus_control(slotinfop->slot_hdl,
1271                             HPC_CTRL_DISABLE_SLOT, NULL) != HPC_SUCCESS) {
1272                                 rv = EIO;
1273                                 break;
1274                         }
1275 
1276                         /*
1277                          * Disable the slot for hotplug operations.
1278                          */
1279                         slotinfop->slot_flags |= PCIHP_SLOT_DISABLED;
1280 
1281                         slotinfop->condition = AP_COND_UNUSABLE;
1282 
1283                         /* XXX need to preserve this state across reboot? */
1284 
1285                         break;
1286 
1287                 case HPC_CTRL_ENABLE_AUTOCFG:
1288                         /*
1289                          * Enable auto configuration on this slot.
1290                          */
1291                         slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
1292 
1293                         /* tell the HPC driver also */
1294                         (void) hpc_nexus_control(slotinfop->slot_hdl,
1295                             HPC_CTRL_ENABLE_AUTOCFG, NULL);
1296 
1297                         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
1298                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
1299                                     HPC_EVENT_ENABLE_ENUM);
1300                         break;
1301 
1302                 case HPC_CTRL_DISABLE_AUTOCFG:
1303                         /*
1304                          * Disable auto configuration on this slot.
1305                          */
1306                         slotinfop->slot_flags &= ~PCIHP_SLOT_AUTO_CFG_EN;
1307 
1308                         /* tell the HPC driver also */
1309                         (void) hpc_nexus_control(slotinfop->slot_hdl,
1310                             HPC_CTRL_DISABLE_AUTOCFG, NULL);
1311 
1312                         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
1313                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
1314                                     HPC_EVENT_DISABLE_ENUM);
1315                         break;
1316 
1317                 case HPC_CTRL_GET_BOARD_TYPE:
1318                 {
1319                         hpc_board_type_t board_type;
1320 
1321                         /*
1322                          * Get board type data structure, hpc_board_type_t.
1323                          */
1324                         board_type = pcihp_get_board_type(slotinfop);
1325                         if (board_type == -1) {
1326                                 rv = ENXIO;
1327                                 break;
1328                         }
1329 
1330                         /* copy the board type info to the user space */
1331                         if (copyout((void *)&board_type, hpc_ctrldata.data,
1332                             sizeof (hpc_board_type_t)) != 0) {
1333                                 rv = ENXIO;
1334                                 break;
1335                         }
1336 
1337                         break;
1338                 }
1339 
1340                 case HPC_CTRL_GET_SLOT_INFO:
1341                 {
1342                         hpc_slot_info_t slot_info;
1343 
1344                         /*
1345                          * Get slot information structure, hpc_slot_info_t.
1346                          */
1347                         slot_info.version = HPC_SLOT_INFO_VERSION;
1348                         slot_info.slot_type = slotinfop->slot_type;
1349                         slot_info.pci_slot_capabilities =
1350                             slotinfop->slot_capabilities;
1351                         slot_info.pci_dev_num = (uint16_t)pci_dev;
1352                         (void) strcpy(slot_info.pci_slot_name, slotinfop->name);
1353 
1354                         /* copy the slot info structure to the user space */
1355                         if (copyout((void *)&slot_info, hpc_ctrldata.data,
1356                             sizeof (hpc_slot_info_t)) != 0) {
1357                                 rv = EFAULT;
1358                                 break;
1359                         }
1360 
1361                         break;
1362                 }
1363 
1364                 case HPC_CTRL_GET_CARD_INFO:
1365                 {
1366                         hpc_card_info_t card_info;
1367                         ddi_acc_handle_t handle;
1368                         dev_info_t *cdip;
1369 
1370                         /*
1371                          * Get card information structure, hpc_card_info_t.
1372                          */
1373 
1374                         /* verify that the card is configured */
1375                         if ((slotinfop->ostate != AP_OSTATE_CONFIGURED) ||
1376                             ((cdip = pcihp_devi_find(self,
1377                             pci_dev, 0)) == NULL)) {
1378                                 /*
1379                                  * either the card is not present or
1380                                  * it is not configured.
1381                                  */
1382                                 rv = ENXIO;
1383                                 break;
1384                         }
1385 
1386                         /*
1387                          * If declared failed, don't allow Config operations.
1388                          * Otherwise, if good or failing, it is assumed Ok
1389                          * to get config data.
1390                          */
1391                         if (slotinfop->condition == AP_COND_FAILED) {
1392                                 rv = EIO;
1393                                 break;
1394                         }
1395 
1396                         /* get the information from the PCI config header */
1397                         /* for the function 0.                            */
1398                         if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
1399                                 rv = EIO;
1400                                 break;
1401                         }
1402                         card_info.prog_class = pci_config_get8(handle,
1403                             PCI_CONF_PROGCLASS);
1404                         card_info.base_class = pci_config_get8(handle,
1405                             PCI_CONF_BASCLASS);
1406                         card_info.sub_class = pci_config_get8(handle,
1407                             PCI_CONF_SUBCLASS);
1408                         card_info.header_type = pci_config_get8(handle,
1409                             PCI_CONF_HEADER);
1410                         pci_config_teardown(&handle);
1411 
1412                         /* copy the card info structure to the user space */
1413                         if (copyout((void *)&card_info, hpc_ctrldata.data,
1414                             sizeof (hpc_card_info_t)) != 0) {
1415                                 rv = EFAULT;
1416                                 break;
1417                         }
1418 
1419                         break;
1420                 }
1421 
1422                 default:
1423                         rv = EINVAL;
1424                         break;
1425                 }
1426 
1427                 mutex_exit(&slotinfop->slot_mutex);
1428 
1429                 break;
1430 
1431         default:
1432                 rv = ENOTTY;
1433         }
1434 
1435         if (cmd != DEVCTL_AP_CONTROL)
1436                 ndi_dc_freehdl(dcp);
1437 
1438         (void) pcihp_get_soft_state(self, state_unlocking, &rval);
1439 
1440         return (rv);
1441 }
1442 
1443 /*
1444  * **************************************
1445  * CONFIGURE the occupant in the slot.
1446  * **************************************
1447  */
1448 static int
1449 pcihp_configure_ap(pcihp_t *pcihp_p, int pci_dev)
1450 {
1451         dev_info_t *self = pcihp_p->dip;
1452         int rv = HPC_SUCCESS;
1453         struct pcihp_slotinfo *slotinfop;
1454         hpc_slot_state_t rstate;
1455         struct pcihp_config_ctrl ctrl;
1456         int circular_count;
1457         time_t time;
1458 
1459         /*
1460          * check for valid request:
1461          *      1. It is a hotplug slot.
1462          *      2. The receptacle is in the CONNECTED state.
1463          */
1464         slotinfop = &pcihp_p->slotinfo[pci_dev];
1465 
1466 
1467 
1468         if ((pci_dev >= PCI_MAX_DEVS) || (slotinfop->slot_hdl == NULL) ||
1469             (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
1470 
1471                 return (ENXIO);
1472         }
1473 
1474         /*
1475          * If the occupant is already in (partially?) configured
1476          * state then call the ndi_devi_online() on the device
1477          * subtree(s) for this attachment point.
1478          */
1479 
1480         if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
1481                 ctrl.flags = PCIHP_CFG_CONTINUE;
1482                 ctrl.rv = NDI_SUCCESS;
1483                 ctrl.dip = NULL;
1484                 ctrl.pci_dev = pci_dev;
1485                 ctrl.op = PCIHP_ONLINE;
1486 
1487                 ndi_devi_enter(self, &circular_count);
1488                 ddi_walk_devs(ddi_get_child(self), pcihp_configure,
1489                     (void *)&ctrl);
1490                 ndi_devi_exit(self, circular_count);
1491 
1492                 if (ctrl.rv != NDI_SUCCESS) {
1493                         /*
1494                          * one or more of the devices are not
1495                          * onlined. How is this to be reported?
1496                          */
1497                         cmn_err(CE_WARN,
1498                             "pcihp (%s%d): failed to attach one or"
1499                             " more drivers for the card in the slot %s",
1500                             ddi_driver_name(self), ddi_get_instance(self),
1501                             slotinfop->name);
1502                         /* rv = EFAULT; */
1503                 }
1504                 /* tell HPC driver that the occupant is configured */
1505                 (void) hpc_nexus_control(slotinfop->slot_hdl,
1506                     HPC_CTRL_DEV_CONFIGURED, NULL);
1507 
1508                 if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
1509                         slotinfop->last_change = (time_t)-1;
1510                 else
1511                         slotinfop->last_change = (time32_t)time;
1512 
1513 
1514                 return (rv);
1515         }
1516 
1517         /*
1518          * Occupant is in the UNCONFIGURED state.
1519          */
1520 
1521         /* Check if the receptacle is in the CONNECTED state. */
1522         if (hpc_nexus_control(slotinfop->slot_hdl,
1523             HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
1524 
1525                 return (ENXIO);
1526         }
1527 
1528         if (rstate == HPC_SLOT_EMPTY) {
1529                 /* error. slot is empty */
1530 
1531                 return (ENXIO);
1532         }
1533 
1534         if (rstate != HPC_SLOT_CONNECTED) {
1535                 /* error. either the slot is empty or connect failed */
1536 
1537                 return (ENXIO);
1538         }
1539 
1540         slotinfop->rstate = AP_RSTATE_CONNECTED; /* record rstate */
1541 
1542         /* Turn INS and LED off, and start configuration. */
1543         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1544                 pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_CONFIGURE);
1545                 if (pcihp_cpci_blue_led)
1546                         pcihp_hs_csr_op(pcihp_p, pci_dev,
1547                             HPC_EVENT_SLOT_BLUE_LED_OFF);
1548                 slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_INS_PENDING;
1549         }
1550 
1551         (void) hpc_nexus_control(slotinfop->slot_hdl,
1552             HPC_CTRL_DEV_CONFIG_START, NULL);
1553 
1554         /*
1555          * Call the configurator to configure the card.
1556          */
1557         if (pcicfg_configure(self, pci_dev, PCICFG_ALL_FUNC, 0)
1558             != PCICFG_SUCCESS) {
1559                 if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1560                         if (pcihp_cpci_blue_led)
1561                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
1562                                     HPC_EVENT_SLOT_BLUE_LED_ON);
1563                         pcihp_hs_csr_op(pcihp_p, pci_dev,
1564                             HPC_EVENT_SLOT_UNCONFIGURE);
1565                 }
1566                 /* tell HPC driver occupant configure Error */
1567                 (void) hpc_nexus_control(slotinfop->slot_hdl,
1568                     HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
1569 
1570                 return (EIO);
1571         }
1572 
1573         /* record the occupant state as CONFIGURED */
1574         slotinfop->ostate = AP_OSTATE_CONFIGURED;
1575         slotinfop->condition = AP_COND_OK;
1576 
1577         /* now, online all the devices in the AP */
1578         ctrl.flags = PCIHP_CFG_CONTINUE;
1579         ctrl.rv = NDI_SUCCESS;
1580         ctrl.dip = NULL;
1581         ctrl.pci_dev = pci_dev;
1582         ctrl.op = PCIHP_ONLINE;
1583 
1584         ndi_devi_enter(self, &circular_count);
1585         ddi_walk_devs(ddi_get_child(self), pcihp_configure, (void *)&ctrl);
1586         ndi_devi_exit(self, circular_count);
1587 
1588         if (ctrl.rv != NDI_SUCCESS) {
1589                 /*
1590                  * one or more of the devices are not
1591                  * ONLINE'd. How is this to be
1592                  * reported?
1593                  */
1594                 cmn_err(CE_WARN,
1595                     "pcihp (%s%d): failed to attach one or"
1596                     " more drivers for the card in the slot %s",
1597                     ddi_driver_name(pcihp_p->dip),
1598                     ddi_get_instance(pcihp_p->dip),
1599                     slotinfop->name);
1600                 /* rv = EFAULT; */
1601         }
1602         /* store HS_CSR location.  No events, jut a read operation. */
1603         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
1604                 pcihp_hs_csr_op(pcihp_p, pci_dev, -1);
1605 
1606         /* tell HPC driver that the occupant is configured */
1607         (void) hpc_nexus_control(slotinfop->slot_hdl,
1608             HPC_CTRL_DEV_CONFIGURED, NULL);
1609 
1610 
1611         return (rv);
1612 }
1613 
1614 /*
1615  * **************************************
1616  * UNCONFIGURE the occupant in the slot.
1617  * **************************************
1618  */
1619 static int
1620 pcihp_unconfigure_ap(pcihp_t *pcihp_p, int pci_dev)
1621 {
1622         dev_info_t *self = pcihp_p->dip;
1623         int rv = HPC_SUCCESS;
1624         struct pcihp_slotinfo *slotinfop;
1625         struct pcihp_config_ctrl ctrl;
1626         int circular_count;
1627         time_t time;
1628 
1629         /*
1630          * check for valid request:
1631          *      1. It is a hotplug slot.
1632          *      2. The occupant is in the CONFIGURED state.
1633          */
1634         slotinfop = &pcihp_p->slotinfo[pci_dev];
1635 
1636 
1637 
1638         if ((pci_dev >= PCI_MAX_DEVS) || (slotinfop->slot_hdl == NULL) ||
1639             (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
1640 
1641                 return (ENXIO);
1642         }
1643         /*
1644          * The following may not need to be there, as we should
1645          * support unconfiguring of boards and free resources
1646          * even when the board is not hotswappable. But this is
1647          * the only way, we may be able to tell the system
1648          * administrator that it is not a hotswap board since
1649          * disconnect operation is never called.
1650          * This way we help the system administrator from not
1651          * accidentally removing a non hotswap board and
1652          * possibly destroying it. May be this behavior can
1653          * be a default, and can be enabled or disabled via
1654          * a global flag.
1655          */
1656         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1657                 if (slotinfop->slot_flags & PCIHP_SLOT_DEV_NON_HOTPLUG) {
1658                         /* Operation unsupported if no HS board/slot */
1659                         return (ENOTSUP);
1660                 }
1661         }
1662 
1663         /*
1664          * If the occupant is in the CONFIGURED state then
1665          * call the configurator to unconfigure the slot.
1666          */
1667         if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
1668 
1669                 /*
1670                  * since potential state change is imminent mask
1671                  * enum events to prevent the slot from being re-configured
1672                  */
1673                 pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
1674 
1675                 /*
1676                  * Detach all the drivers for the devices in the
1677                  * slot. Call pcihp_configure() to do this.
1678                  */
1679                 ctrl.flags = 0;
1680                 ctrl.rv = NDI_SUCCESS;
1681                 ctrl.dip = NULL;
1682                 ctrl.pci_dev = pci_dev;
1683                 ctrl.op = PCIHP_OFFLINE;
1684 
1685                 (void) devfs_clean(self, NULL, DV_CLEAN_FORCE);
1686                 ndi_devi_enter(self, &circular_count);
1687                 ddi_walk_devs(ddi_get_child(self), pcihp_configure,
1688                     (void *)&ctrl);
1689                 ndi_devi_exit(self, circular_count);
1690 
1691                 if (ctrl.rv != NDI_SUCCESS) {
1692                         /*
1693                          * Failed to detach one or more drivers
1694                          * Restore the state of drivers which
1695                          * are offlined during this operation.
1696                          */
1697                         ctrl.flags = 0;
1698                         ctrl.rv = NDI_SUCCESS;
1699                         ctrl.dip = NULL;
1700                         ctrl.pci_dev = pci_dev;
1701                         ctrl.op = PCIHP_ONLINE;
1702 
1703                         ndi_devi_enter(self, &circular_count);
1704                         ddi_walk_devs(ddi_get_child(self),
1705                             pcihp_configure, (void *)&ctrl);
1706                         ndi_devi_exit(self, circular_count);
1707 
1708                         /* tell HPC driver that the occupant is Busy */
1709                         (void) hpc_nexus_control(slotinfop->slot_hdl,
1710                             HPC_CTRL_DEV_UNCONFIG_FAILURE, NULL);
1711 
1712                         rv = EBUSY;
1713                 } else {
1714                         (void) hpc_nexus_control(slotinfop->slot_hdl,
1715                             HPC_CTRL_DEV_UNCONFIG_START, NULL);
1716 
1717                         if (pcicfg_unconfigure(self, pci_dev,
1718                             PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
1719                                 /*
1720                                  * Now that resources are freed,
1721                                  * clear EXT and Turn LED ON.
1722                                  */
1723                                 if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1724                                         pcihp_hs_csr_op(pcihp_p, pci_dev,
1725                                             HPC_EVENT_SLOT_UNCONFIGURE);
1726                                         if (pcihp_cpci_blue_led)
1727                                                 pcihp_hs_csr_op(pcihp_p,
1728                                                     pci_dev,
1729                                                     HPC_EVENT_SLOT_BLUE_LED_ON);
1730                                         slotinfop->hs_csr_location = 0;
1731                                         slotinfop->slot_flags &=
1732                                             ~(PCIHP_SLOT_DEV_NON_HOTPLUG|
1733                                             PCIHP_SLOT_ENUM_EXT_PENDING);
1734                                 }
1735                                 slotinfop->ostate = AP_OSTATE_UNCONFIGURED;
1736                                 slotinfop->condition = AP_COND_UNKNOWN;
1737                                 /*
1738                                  * send the notification of state change
1739                                  * to the HPC driver.
1740                                  */
1741                                 (void) hpc_nexus_control(slotinfop->slot_hdl,
1742                                     HPC_CTRL_DEV_UNCONFIGURED,
1743                                     NULL);
1744                         } else {
1745                                 /* tell HPC driver occupant unconfigure Error */
1746                                 (void) hpc_nexus_control(slotinfop->slot_hdl,
1747                                     HPC_CTRL_DEV_UNCONFIG_FAILURE, NULL);
1748 
1749                                 rv = EIO;
1750                         }
1751                 }
1752         }
1753 
1754         if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
1755                 slotinfop->last_change = (time_t)-1;
1756         else
1757                 slotinfop->last_change = (time32_t)time;
1758 
1759 
1760 
1761         /* unmask enum events again */
1762         if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
1763                 pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
1764         }
1765 
1766         return (rv);
1767 }
1768 
1769 /*
1770  * Accessor function to return pointer to the pci hotplug
1771  * cb_ops structure.
1772  */
1773 struct cb_ops *
1774 pcihp_get_cb_ops()
1775 {
1776         return (&pcihp_cb_ops);
1777 }
1778 
1779 /*
1780  * Setup function to initialize hot plug feature. Returns DDI_SUCCESS
1781  * for successful initialization, otherwise it returns DDI_FAILURE.
1782  *
1783  * It is assumed that this this function is called from the attach()
1784  * entry point of the PCI nexus driver.
1785  */
1786 
1787 int
1788 pcihp_init(dev_info_t *dip)
1789 {
1790         pcihp_t *pcihp_p;
1791         int i;
1792         caddr_t enum_data;
1793         int enum_size;
1794         int rv;
1795 
1796         mutex_enter(&pcihp_open_mutex);
1797 
1798         /*
1799          * Make sure that it is not already initialized.
1800          */
1801         if (pcihp_get_soft_state(dip, PCIHP_DR_NOOP, &rv) != NULL) {
1802                 cmn_err(CE_WARN, "%s%d: pcihp instance already initialized!",
1803                     ddi_driver_name(dip), ddi_get_instance(dip));
1804                 goto cleanup;
1805         }
1806 
1807         /*
1808          * Initialize soft state structure for the bus instance.
1809          */
1810         if ((pcihp_p = pcihp_create_soft_state(dip)) == NULL) {
1811                 cmn_err(CE_WARN, "%s%d: can't allocate pcihp structure",
1812                     ddi_driver_name(dip), ddi_get_instance(dip));
1813                 goto cleanup;
1814         }
1815 
1816         pcihp_p->soft_state = PCIHP_SOFT_STATE_CLOSED;
1817         /* XXX if bus is running at 66Mhz then set PCI_BUS_66MHZ bit */
1818         pcihp_p->bus_flags = 0;      /* XXX FIX IT */
1819 
1820         /*
1821          * If a platform wishes to implement Radial ENUM# routing
1822          * a property "enum-impl" must be presented to us with a
1823          * string value "radial".
1824          * This helps us not go for polling operation (default)
1825          * during a ENUM# event.
1826          */
1827         if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "enum-impl",
1828             (caddr_t)&enum_data, &enum_size) == DDI_PROP_SUCCESS) {
1829                 if (strcmp(enum_data, "radial") == 0) {
1830                         pcihp_p->bus_flags |= PCIHP_BUS_ENUM_RADIAL;
1831                 }
1832                 kmem_free(enum_data, enum_size);
1833         }
1834 
1835         for (i = 0; i < PCI_MAX_DEVS; i++) {
1836                 /* initialize slot mutex */
1837                 mutex_init(&pcihp_p->slotinfo[i].slot_mutex, NULL,
1838                     MUTEX_DRIVER, NULL);
1839         }
1840 
1841         /*
1842          *  register the bus instance with the HPS framework.
1843          */
1844         if (hpc_nexus_register_bus(dip, pcihp_new_slot_state, 0) != 0) {
1845                 cmn_err(CE_WARN, "%s%d: failed to register the bus with HPS",
1846                     ddi_driver_name(dip), ddi_get_instance(dip));
1847                 goto cleanup1;
1848         }
1849 
1850         /*
1851          * Create the "devctl" minor for hot plug support. The minor
1852          * number for "devctl" node is in the same format as the AP
1853          * minor nodes.
1854          */
1855         if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
1856             PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), PCIHP_DEVCTL_MINOR),
1857             DDI_NT_NEXUS, 0) != DDI_SUCCESS)
1858                 goto cleanup2;
1859 
1860         /*
1861          * Setup resource maps for this bus node. (Note: This can
1862          * be done from the attach(9E) of the nexus itself.)
1863          */
1864         (void) pci_resource_setup(dip);
1865 
1866         pcihp_p->bus_state = PCIHP_BUS_CONFIGURED;
1867 
1868         mutex_exit(&pcihp_open_mutex);
1869 
1870         return (DDI_SUCCESS);
1871 
1872 cleanup2:
1873         (void) hpc_nexus_unregister_bus(dip);
1874 cleanup1:
1875         for (i = 0; i < PCI_MAX_DEVS; i++)
1876                 mutex_destroy(&pcihp_p->slotinfo[i].slot_mutex);
1877         pcihp_destroy_soft_state(dip);
1878 cleanup:
1879         mutex_exit(&pcihp_open_mutex);
1880         return (DDI_FAILURE);
1881 }
1882 
1883 /*
1884  * pcihp_uninit()
1885  *
1886  * The bus instance is going away, cleanup any data associated with
1887  * the management of hot plug slots. It is assumed that this function
1888  * is called from detach() routine of the PCI nexus driver. Also,
1889  * it is assumed that no devices on the bus are in the configured state.
1890  */
1891 int
1892 pcihp_uninit(dev_info_t *dip)
1893 {
1894         pcihp_t *pcihp_p;
1895         int i, j;
1896         int rv;
1897 
1898         mutex_enter(&pcihp_open_mutex);
1899         /* get a pointer to the soft state structure */
1900         pcihp_p = pcihp_get_soft_state(dip, PCIHP_DR_BUS_UNCONFIGURE, &rv);
1901         ASSERT(pcihp_p != NULL);
1902 
1903         /* slot mutexes should prevent any configure/unconfigure access */
1904         for (i = 0; i < PCI_MAX_DEVS; i++) {
1905                 if (!mutex_tryenter(&pcihp_p->slotinfo[i].slot_mutex)) {
1906                         for (j = 0; j < i; j++) {
1907                                 mutex_exit(&pcihp_p->slotinfo[j].slot_mutex);
1908                         }
1909                         mutex_exit(&pcihp_open_mutex);
1910                         return (DDI_FAILURE);
1911                 }
1912         }
1913 
1914         if ((pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED) ||
1915             (rv == PCIHP_FAILURE)) {
1916                 cmn_err(CE_WARN, "%s%d: pcihp instance is busy",
1917                     ddi_driver_name(dip), ddi_get_instance(dip));
1918                 for (i = 0; i < PCI_MAX_DEVS; i++) {
1919                         mutex_exit(&pcihp_p->slotinfo[i].slot_mutex);
1920                 }
1921                 mutex_exit(&pcihp_open_mutex);
1922                 return (DDI_FAILURE);
1923         }
1924 
1925         /*
1926          * Unregister the bus with the HPS.
1927          *
1928          * (Note: It is assumed that the HPS framework uninstalls
1929          *  event handlers for all the hot plug slots on this bus.)
1930          */
1931         (void) hpc_nexus_unregister_bus(dip);
1932 
1933         /* Free up any kmem_alloc'd memory for slot info table. */
1934         for (i = 0; i < PCI_MAX_DEVS; i++) {
1935                 /* free up slot name strings */
1936                 if (pcihp_p->slotinfo[i].name != NULL)
1937                         kmem_free(pcihp_p->slotinfo[i].name,
1938                             strlen(pcihp_p->slotinfo[i].name) + 1);
1939         }
1940 
1941         /* destroy slot mutexes */
1942         for (i = 0; i < PCI_MAX_DEVS; i++)
1943                 mutex_destroy(&pcihp_p->slotinfo[i].slot_mutex);
1944 
1945         ddi_remove_minor_node(dip, NULL);
1946 
1947         /* free up the soft state structure */
1948         pcihp_destroy_soft_state(dip);
1949 
1950         /*
1951          * Destroy resource maps for this bus node. (Note: This can
1952          * be done from the detach(9E) of the nexus itself.)
1953          */
1954         (void) pci_resource_destroy(dip);
1955 
1956         mutex_exit(&pcihp_open_mutex);
1957 
1958         return (DDI_SUCCESS);
1959 }
1960 
1961 /*
1962  * pcihp_new_slot_state()
1963  *
1964  * This function is called by the HPS when it finds a hot plug
1965  * slot is added or being removed from the hot plug framework.
1966  * It returns 0 for success and HPC_ERR_FAILED for errors.
1967  */
1968 static int
1969 pcihp_new_slot_state(dev_info_t *dip, hpc_slot_t hdl,
1970         hpc_slot_info_t *slot_info, int slot_state)
1971 {
1972         pcihp_t *pcihp_p;
1973         struct pcihp_slotinfo *slotinfop;
1974         int pci_dev;
1975         minor_t ap_minor;
1976         major_t ap_major;
1977         int rv = 0;
1978         time_t time;
1979         int auto_enable = 1;
1980         int rval;
1981 
1982         /* get a pointer to the soft state structure */
1983         pcihp_p = pcihp_get_soft_state(dip, PCIHP_DR_SLOT_ENTER, &rval);
1984         ASSERT(pcihp_p != NULL);
1985 
1986         if (rval == PCIHP_FAILURE) {
1987                 PCIHP_DEBUG((CE_WARN, "pcihp instance is unconfigured"
1988                     " while slot activity is requested\n"));
1989                 return (HPC_ERR_FAILED);
1990         }
1991 
1992         pci_dev = slot_info->pci_dev_num;
1993         slotinfop = &pcihp_p->slotinfo[pci_dev];
1994 
1995         mutex_enter(&slotinfop->slot_mutex);
1996 
1997         switch (slot_state) {
1998 
1999         case HPC_SLOT_ONLINE:
2000 
2001                 /*
2002                  * Make sure the slot is not already ONLINE (paranoia?).
2003                  * (Note: Should this be simply an ASSERTION?)
2004                  */
2005                 if (slotinfop->slot_hdl != NULL) {
2006                         PCIHP_DEBUG((CE_WARN,
2007                             "pcihp (%s%d): pci slot (dev %x) already ONLINE!!",
2008                             ddi_driver_name(dip), ddi_get_instance(dip),
2009                             pci_dev));
2010                         rv = HPC_ERR_FAILED;
2011                         break;
2012                 }
2013 
2014                 /*
2015                  * Add the hot plug slot to the bus.
2016                  */
2017 
2018                 /* create the AP minor node */
2019                 ap_minor = PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), pci_dev);
2020                 if (ddi_create_minor_node(dip, slot_info->pci_slot_name,
2021                     S_IFCHR, ap_minor,
2022                     DDI_NT_PCI_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
2023                         cmn_err(CE_WARN,
2024                             "pcihp (%s%d): ddi_create_minor_node failed"
2025                             " for pci dev %x", ddi_driver_name(dip),
2026                             ddi_get_instance(dip), pci_dev);
2027                         rv = HPC_ERR_FAILED;
2028                         break;
2029                 }
2030 
2031                 /* save the slot handle */
2032                 slotinfop->slot_hdl = hdl;
2033 
2034                 /* setup event handler for all hardware events on the slot */
2035                 ap_major = ddi_driver_major(dip);
2036                 if (hpc_install_event_handler(hdl, -1, pcihp_event_handler,
2037                     (caddr_t)makedevice(ap_major, ap_minor)) != 0) {
2038                         cmn_err(CE_WARN,
2039                             "pcihp (%s%d): install event handler failed"
2040                             " for pci dev %x", ddi_driver_name(dip),
2041                             ddi_get_instance(dip), pci_dev);
2042                         rv = HPC_ERR_FAILED;
2043                         break;
2044                 }
2045                 slotinfop->event_mask = (uint32_t)0xFFFFFFFF;
2046 
2047                 pcihp_create_occupant_props(dip, makedevice(ap_major,
2048                     ap_minor), pci_dev);
2049 
2050                 /* set default auto configuration enabled flag for this slot */
2051                 slotinfop->slot_flags = pcihp_autocfg_enabled;
2052 
2053                 /* copy the slot information */
2054                 slotinfop->name =
2055                     kmem_alloc(strlen(slot_info->pci_slot_name) + 1, KM_SLEEP);
2056                 (void) strcpy(slotinfop->name, slot_info->pci_slot_name);
2057                 slotinfop->slot_type = slot_info->slot_type;
2058                 slotinfop->hs_csr_location = 0;
2059                 slotinfop->slot_capabilities = slot_info->pci_slot_capabilities;
2060                 if (slot_info->slot_flags & HPC_SLOT_NO_AUTO_ENABLE)
2061                         auto_enable = 0;
2062 
2063                 if (slot_info->slot_flags & HPC_SLOT_CREATE_DEVLINK) {
2064                         pci_devlink_flags |= (1 << pci_dev);
2065                         (void) ddi_prop_update_int(DDI_DEV_T_NONE,
2066                             dip, "ap-names", pci_devlink_flags);
2067                 }
2068 
2069                 PCIHP_DEBUG((CE_NOTE,
2070                     "pcihp (%s%d): pci slot (dev %x) ONLINE\n",
2071                     ddi_driver_name(dip), ddi_get_instance(dip), pci_dev));
2072 
2073                 /*
2074                  * The slot may have an occupant that was configured
2075                  * at boot time. If we find a devinfo node in the tree
2076                  * for this slot (i.e pci device number) then we
2077                  * record the occupant state as CONFIGURED.
2078                  */
2079                 if (pcihp_devi_find(dip, pci_dev, 0) != NULL) {
2080                         /* we have a configured occupant */
2081                         slotinfop->ostate = AP_OSTATE_CONFIGURED;
2082                         slotinfop->rstate = AP_RSTATE_CONNECTED;
2083                         slotinfop->condition = AP_COND_OK;
2084 
2085                         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2086                                 /* this will set slot flags too. */
2087                                 (void) pcihp_get_board_type(slotinfop);
2088                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
2089                                     HPC_EVENT_SLOT_CONFIGURE);
2090                                 if (pcihp_cpci_blue_led)
2091                                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2092                                             HPC_EVENT_SLOT_BLUE_LED_OFF);
2093                                 /* ENUM# enabled by default for cPCI devices */
2094                                 slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
2095                                 slotinfop->slot_flags &=
2096                                     ~PCIHP_SLOT_ENUM_INS_PENDING;
2097                         }
2098 
2099                         /* tell HPC driver that the occupant is configured */
2100                         (void) hpc_nexus_control(slotinfop->slot_hdl,
2101                             HPC_CTRL_DEV_CONFIGURED, NULL);
2102 
2103                         /*
2104                          * Tell sysevent listeners that slot has
2105                          * changed state.  At minimum, this is useful
2106                          * when a PCI-E Chassis (containing Occupants) is
2107                          * hotplugged.  In this case, the following will
2108                          * announce that the Occupant in the Receptacle
2109                          * in the Chassis had a state-change.
2110                          */
2111                         pcihp_gen_sysevent(slotinfop->name,
2112                             PCIHP_DR_AP_STATE_CHANGE, SE_NO_HINT,
2113                             pcihp_p->dip, KM_SLEEP);
2114                 } else {
2115                         struct pcihp_config_ctrl ctrl;
2116                         int circular_count;
2117 
2118                         slotinfop->ostate = AP_OSTATE_UNCONFIGURED;
2119                         slotinfop->rstate = AP_RSTATE_EMPTY;
2120                         slotinfop->condition = AP_COND_UNKNOWN;
2121 
2122                         if (!auto_enable) {     /* no further action */
2123                                 break;
2124                         }
2125 
2126                         /*
2127                          * We enable power to the slot and try to
2128                          * configure if there is any card present.
2129                          *
2130                          * Note: This case is possible if the BIOS or
2131                          * firmware doesn't enable the slots during
2132                          * soft reboot.
2133                          */
2134                         if (hpc_nexus_connect(slotinfop->slot_hdl,
2135                             NULL, 0) != HPC_SUCCESS)
2136                                 break;
2137 
2138                         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2139                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
2140                                     HPC_EVENT_SLOT_CONFIGURE);
2141                                 if (pcihp_cpci_blue_led)
2142                                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2143                                             HPC_EVENT_SLOT_BLUE_LED_OFF);
2144                                 slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
2145                                 slotinfop->slot_flags &=
2146                                     ~PCIHP_SLOT_ENUM_INS_PENDING;
2147                         }
2148 
2149                         (void) hpc_nexus_control(slotinfop->slot_hdl,
2150                             HPC_CTRL_DEV_CONFIG_START, NULL);
2151 
2152                         /*
2153                          * Call the configurator to configure the card.
2154                          */
2155                         if (pcicfg_configure(dip, pci_dev, PCICFG_ALL_FUNC, 0)
2156                             != PCICFG_SUCCESS) {
2157                                 if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2158                                         if (pcihp_cpci_blue_led)
2159                                                 pcihp_hs_csr_op(pcihp_p,
2160                                                     pci_dev,
2161                                                     HPC_EVENT_SLOT_BLUE_LED_ON);
2162                                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2163                                             HPC_EVENT_SLOT_UNCONFIGURE);
2164                                 }
2165 
2166                                 /* tell HPC driver occupant configure Error */
2167                                 (void) hpc_nexus_control(slotinfop->slot_hdl,
2168                                     HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
2169 
2170                                 /*
2171                                  * call HPC driver to turn off the power for
2172                                  * the slot.
2173                                  */
2174                                 (void) hpc_nexus_disconnect(slotinfop->slot_hdl,
2175                                     NULL, 0);
2176                         } else {
2177                                 /* record the occupant state as CONFIGURED */
2178                                 slotinfop->ostate = AP_OSTATE_CONFIGURED;
2179                                 slotinfop->rstate = AP_RSTATE_CONNECTED;
2180                                 slotinfop->condition = AP_COND_OK;
2181 
2182                                 /* now, online all the devices in the AP */
2183                                 ctrl.flags = PCIHP_CFG_CONTINUE;
2184                                 ctrl.rv = NDI_SUCCESS;
2185                                 ctrl.dip = NULL;
2186                                 ctrl.pci_dev = pci_dev;
2187                                 ctrl.op = PCIHP_ONLINE;
2188                                 /*
2189                                  * the following sets slot_flags and
2190                                  * hs_csr_location too.
2191                                  */
2192                                 (void) pcihp_get_board_type(slotinfop);
2193 
2194                                 ndi_devi_enter(dip, &circular_count);
2195                                 ddi_walk_devs(ddi_get_child(dip),
2196                                     pcihp_configure, (void *)&ctrl);
2197                                 ndi_devi_exit(dip, circular_count);
2198 
2199                                 if (ctrl.rv != NDI_SUCCESS) {
2200                                         /*
2201                                          * one or more of the devices are not
2202                                          * ONLINE'd. How is this to be
2203                                          * reported?
2204                                          */
2205                                         cmn_err(CE_WARN,
2206                                             "pcihp (%s%d): failed to attach"
2207                                             " one or more drivers for the"
2208                                             " card in the slot %s",
2209                                             ddi_driver_name(dip),
2210                                             ddi_get_instance(dip),
2211                                             slotinfop->name);
2212                                 }
2213 
2214                                 /* tell HPC driver the Occupant is Configured */
2215                                 (void) hpc_nexus_control(slotinfop->slot_hdl,
2216                                     HPC_CTRL_DEV_CONFIGURED, NULL);
2217 
2218                                 /*
2219                                  * Tell sysevent listeners that slot has
2220                                  * changed state.  At minimum, this is useful
2221                                  * when a PCI-E Chassis (containing Occupants)
2222                                  * is hotplugged.  In this case, the following
2223                                  * will announce that the Occupant in the
2224                                  * Receptacle in the Chassis had a state-change.
2225                                  */
2226                                 pcihp_gen_sysevent(slotinfop->name,
2227                                     PCIHP_DR_AP_STATE_CHANGE, SE_NO_HINT,
2228                                     pcihp_p->dip, KM_SLEEP);
2229                         }
2230                 }
2231 
2232                 break;
2233 
2234         case HPC_SLOT_OFFLINE:
2235                 /*
2236                  * A hot plug slot is being removed from the bus.
2237                  * Make sure there is no occupant configured on the
2238                  * slot before removing the AP minor node.
2239                  */
2240                 if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
2241                         cmn_err(CE_WARN, "pcihp (%s%d): Card is still in "
2242                             "configured state for pci dev %x",
2243                             ddi_driver_name(dip), ddi_get_instance(dip),
2244                             pci_dev);
2245                         rv = HPC_ERR_FAILED;
2246                         break;
2247                 }
2248 
2249                 /*
2250                  * If the AP device is in open state then return
2251                  * error.
2252                  */
2253                 if (pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED) {
2254                         rv = HPC_ERR_FAILED;
2255                         break;
2256                 }
2257                 if (slot_info->slot_flags & HPC_SLOT_CREATE_DEVLINK) {
2258                         pci_devlink_flags &= ~(1 << pci_dev);
2259                         (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
2260                             "ap-names", pci_devlink_flags);
2261                 }
2262 
2263                 /* remove the minor node */
2264                 ddi_remove_minor_node(dip, slotinfop->name);
2265 
2266                 /* free up the memory for the name string */
2267                 kmem_free(slotinfop->name, strlen(slotinfop->name) + 1);
2268 
2269                 /* update the slot info data */
2270                 slotinfop->name = NULL;
2271                 slotinfop->slot_hdl = NULL;
2272 
2273                 PCIHP_DEBUG((CE_NOTE,
2274                     "pcihp (%s%d): pci slot (dev %x) OFFLINE\n",
2275                     ddi_driver_name(dip), ddi_get_instance(dip),
2276                     slot_info->pci_dev_num));
2277 
2278                 break;
2279         default:
2280                 cmn_err(CE_WARN,
2281                     "pcihp_new_slot_state: unknown slot_state %d", slot_state);
2282                 rv = HPC_ERR_FAILED;
2283         }
2284 
2285         if (rv == 0) {
2286                 if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
2287                         slotinfop->last_change = (time_t)-1;
2288                 else
2289                         slotinfop->last_change = (time32_t)time;
2290         }
2291 
2292         mutex_exit(&slotinfop->slot_mutex);
2293 
2294         (void) pcihp_get_soft_state(dip, PCIHP_DR_SLOT_EXIT, &rval);
2295 
2296         return (rv);
2297 }
2298 
2299 /*
2300  * Event handler. It is assumed that this function is called from
2301  * a kernel context only.
2302  *
2303  * Parameters:
2304  *      slot_arg        AP minor number.
2305  *      event_mask      Event that occurred.
2306  */
2307 
2308 static int
2309 pcihp_event_handler(caddr_t slot_arg, uint_t event_mask)
2310 {
2311         dev_t ap_dev = (dev_t)slot_arg;
2312         dev_info_t *self;
2313         pcihp_t *pcihp_p;
2314         int pci_dev;
2315         int rv = HPC_EVENT_CLAIMED;
2316         struct pcihp_slotinfo *slotinfop;
2317         struct pcihp_config_ctrl ctrl;
2318         int circular_count;
2319         int rval;
2320         int hint;
2321         hpc_slot_state_t rstate;
2322         struct hpc_led_info led_info;
2323 
2324         /*
2325          * Get the soft state structure.
2326          */
2327         if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)ap_dev,
2328             (void **)&self) != DDI_SUCCESS)
2329                 return (ENXIO);
2330 
2331         pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_SLOT_ENTER, &rval);
2332         ASSERT(pcihp_p != NULL);
2333 
2334         if (rval == PCIHP_FAILURE) {
2335                 PCIHP_DEBUG((CE_WARN, "pcihp instance is unconfigured"
2336                     " while slot activity is requested\n"));
2337                 return (-1);
2338         }
2339 
2340         /* get the PCI device number for the slot */
2341         pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(ap_dev));
2342 
2343         slotinfop = &pcihp_p->slotinfo[pci_dev];
2344 
2345         /*
2346          * All the events that may be handled in interrupt context should be
2347          * free of any mutex usage.
2348          */
2349         switch (event_mask) {
2350 
2351         case HPC_EVENT_CLEAR_ENUM:
2352                 /*
2353                  * Check and clear ENUM# interrupt status. This may be
2354                  * called by the Hotswap controller driver when it is
2355                  * operating in a full hotswap system where the
2356                  * platform may not have control on globally disabling ENUM#.
2357                  * In such cases, the intent is to clear interrupt and
2358                  * process the interrupt in non-interrupt context.
2359                  * This is the first part of the ENUM# event processing.
2360                  */
2361                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): ENUM# is generated"
2362                     " on the bus (for slot %s ?)",
2363                     ddi_driver_name(pcihp_p->dip),
2364                     ddi_get_instance(pcihp_p->dip), slotinfop->name));
2365 
2366                 /* this is the only event coming through in interrupt context */
2367                 rv = pcihp_handle_enum(pcihp_p, pci_dev, PCIHP_CLEAR_ENUM,
2368                     KM_NOSLEEP);
2369 
2370                 (void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT, &rval);
2371 
2372                 return (rv);
2373         default:
2374                 break;
2375         }
2376 
2377         mutex_enter(&slotinfop->slot_mutex);
2378 
2379         if (hpc_nexus_control(slotinfop->slot_hdl,
2380             HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0)
2381                 rv = HPC_ERR_FAILED;
2382 
2383         slotinfop->rstate = (ap_rstate_t)rstate;
2384 
2385         switch (event_mask) {
2386 
2387         case HPC_EVENT_SLOT_INSERTION:
2388                 /*
2389                  * A card is inserted in the slot. Just report this
2390                  * event and return.
2391                  */
2392                 cmn_err(CE_NOTE, "pcihp (%s%d): card is inserted"
2393                     " in the slot %s (pci dev %x)",
2394                     ddi_driver_name(pcihp_p->dip),
2395                     ddi_get_instance(pcihp_p->dip),
2396                     slotinfop->name, pci_dev);
2397 
2398                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2399 
2400                 break;
2401 
2402         case HPC_EVENT_SLOT_CONFIGURE:
2403                 /*
2404                  * Configure the occupant that is just inserted in the slot.
2405                  * The receptacle may or may not be in the connected state. If
2406                  * the receptacle is not connected and the auto configuration
2407                  * is enabled on this slot then connect the slot. If auto
2408                  * configuration is enabled then configure the card.
2409                  */
2410                 if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
2411                         /*
2412                          * auto configuration is disabled. Tell someone
2413                          * like RCM about this hotplug event?
2414                          */
2415                         cmn_err(CE_NOTE, "pcihp (%s%d): SLOT_CONFIGURE event"
2416                             " occurred for pci dev %x (slot %s),"
2417                             " Slot disabled for auto-configuration.",
2418                             ddi_driver_name(pcihp_p->dip),
2419                             ddi_get_instance(pcihp_p->dip), pci_dev,
2420                             slotinfop->name);
2421 
2422                         /* +++ HOOK for RCM to report this hotplug event? +++ */
2423 
2424                         break;
2425                 }
2426 
2427                 if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
2428                         cmn_err(CE_WARN, "pcihp (%s%d): SLOT_CONFIGURE event"
2429                             " re-occurred for pci dev %x (slot %s),",
2430                             ddi_driver_name(pcihp_p->dip),
2431                             ddi_get_instance(pcihp_p->dip), pci_dev,
2432                             slotinfop->name);
2433                         mutex_exit(&slotinfop->slot_mutex);
2434 
2435                         (void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT,
2436                             &rval);
2437 
2438                         return (EAGAIN);
2439                 }
2440 
2441                 /*
2442                  * Auto configuration is enabled. First, make sure the
2443                  * receptacle is in the CONNECTED state.
2444                  */
2445                 if ((rv = hpc_nexus_connect(slotinfop->slot_hdl,
2446                     NULL, 0)) == HPC_SUCCESS) {
2447                         /* record rstate */
2448                         slotinfop->rstate = AP_RSTATE_CONNECTED;
2449                 }
2450 
2451                 /* Clear INS and Turn LED Off and start configuring. */
2452                 if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2453                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2454                             HPC_EVENT_SLOT_CONFIGURE);
2455                         if (pcihp_cpci_blue_led)
2456                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
2457                                     HPC_EVENT_SLOT_BLUE_LED_OFF);
2458                 }
2459 
2460                 (void) hpc_nexus_control(slotinfop->slot_hdl,
2461                     HPC_CTRL_DEV_CONFIG_START, NULL);
2462 
2463                 /*
2464                  * Call the configurator to configure the card.
2465                  */
2466                 if (pcicfg_configure(pcihp_p->dip, pci_dev, PCICFG_ALL_FUNC, 0)
2467                     != PCICFG_SUCCESS) {
2468                         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2469                                 if (pcihp_cpci_blue_led)
2470                                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2471                                             HPC_EVENT_SLOT_BLUE_LED_ON);
2472                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
2473                                     HPC_EVENT_SLOT_UNCONFIGURE);
2474                         }
2475                         /* failed to configure the card */
2476                         cmn_err(CE_WARN, "pcihp (%s%d): failed to configure"
2477                             " the card in the slot %s",
2478                             ddi_driver_name(pcihp_p->dip),
2479                             ddi_get_instance(pcihp_p->dip),
2480                             slotinfop->name);
2481                         /* failed to configure; disconnect the slot */
2482                         if (hpc_nexus_disconnect(slotinfop->slot_hdl,
2483                             NULL, 0) == HPC_SUCCESS) {
2484                                 slotinfop->rstate = AP_RSTATE_DISCONNECTED;
2485                         }
2486 
2487                         /* tell HPC driver occupant configure Error */
2488                         (void) hpc_nexus_control(slotinfop->slot_hdl,
2489                             HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
2490                 } else {
2491                         /* record the occupant state as CONFIGURED */
2492                         slotinfop->ostate = AP_OSTATE_CONFIGURED;
2493                         slotinfop->condition = AP_COND_OK;
2494 
2495                         /* now, online all the devices in the AP */
2496                         ctrl.flags = PCIHP_CFG_CONTINUE;
2497                         ctrl.rv = NDI_SUCCESS;
2498                         ctrl.dip = NULL;
2499                         ctrl.pci_dev = pci_dev;
2500                         ctrl.op = PCIHP_ONLINE;
2501                                 (void) pcihp_get_board_type(slotinfop);
2502 
2503                         ndi_devi_enter(pcihp_p->dip, &circular_count);
2504                         ddi_walk_devs(ddi_get_child(pcihp_p->dip),
2505                             pcihp_configure, (void *)&ctrl);
2506                         ndi_devi_exit(pcihp_p->dip, circular_count);
2507 
2508                         if (ctrl.rv != NDI_SUCCESS) {
2509                                 /*
2510                                  * one or more of the devices are not
2511                                  * ONLINE'd. How is this to be
2512                                  * reported?
2513                                  */
2514                                 cmn_err(CE_WARN,
2515                                     "pcihp (%s%d): failed to attach one or"
2516                                     " more drivers for the card in"
2517                                     " the slot %s",
2518                                     ddi_driver_name(pcihp_p->dip),
2519                                     ddi_get_instance(pcihp_p->dip),
2520                                     slotinfop->name);
2521                         }
2522 
2523                         /* tell HPC driver that the occupant is configured */
2524                         (void) hpc_nexus_control(slotinfop->slot_hdl,
2525                             HPC_CTRL_DEV_CONFIGURED, NULL);
2526 
2527                         cmn_err(CE_NOTE, "pcihp (%s%d): card is CONFIGURED"
2528                             " in the slot %s (pci dev %x)",
2529                             ddi_driver_name(pcihp_p->dip),
2530                             ddi_get_instance(pcihp_p->dip),
2531                             slotinfop->name, pci_dev);
2532                 }
2533 
2534                 break;
2535 
2536         case HPC_EVENT_SLOT_UNCONFIGURE:
2537                 /*
2538                  * Unconfigure the occupant in this slot.
2539                  */
2540                 if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
2541                         /*
2542                          * auto configuration is disabled. Tell someone
2543                          * like RCM about this hotplug event?
2544                          */
2545                         cmn_err(CE_NOTE, "pcihp (%s%d): SLOT_UNCONFIGURE event"
2546                             " for pci dev %x (slot %s) ignored,"
2547                             " Slot disabled for auto-configuration.",
2548                             ddi_driver_name(pcihp_p->dip),
2549                             ddi_get_instance(pcihp_p->dip), pci_dev,
2550                             slotinfop->name);
2551 
2552                         /* +++ HOOK for RCM to report this hotplug event? +++ */
2553 
2554                         break;
2555                 }
2556 
2557                 if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED) {
2558                         cmn_err(CE_WARN, "pcihp (%s%d): SLOT_UNCONFIGURE "
2559                             "event re-occurred for pci dev %x (slot %s),",
2560                             ddi_driver_name(pcihp_p->dip),
2561                             ddi_get_instance(pcihp_p->dip), pci_dev,
2562                             slotinfop->name);
2563                         mutex_exit(&slotinfop->slot_mutex);
2564 
2565                         (void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT,
2566                             &rval);
2567 
2568                         return (EAGAIN);
2569                 }
2570                 /*
2571                  * If the occupant is in the CONFIGURED state then
2572                  * call the configurator to unconfigure the slot.
2573                  */
2574                 if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
2575                         /*
2576                          * Detach all the drivers for the devices in the
2577                          * slot. Call pcihp_configure() to offline the
2578                          * devices.
2579                          */
2580                         ctrl.flags = 0;
2581                         ctrl.rv = NDI_SUCCESS;
2582                         ctrl.dip = NULL;
2583                         ctrl.pci_dev = pci_dev;
2584                         ctrl.op = PCIHP_OFFLINE;
2585 
2586                         (void) devfs_clean(pcihp_p->dip, NULL, DV_CLEAN_FORCE);
2587                         ndi_devi_enter(pcihp_p->dip, &circular_count);
2588                         ddi_walk_devs(ddi_get_child(pcihp_p->dip),
2589                             pcihp_configure, (void *)&ctrl);
2590                         ndi_devi_exit(pcihp_p->dip, circular_count);
2591 
2592                         if (ctrl.rv != NDI_SUCCESS) {
2593                                 /*
2594                                  * Failed to detach one or more drivers.
2595                                  * Restore the status for the drivers
2596                                  * which are offlined during this step.
2597                                  */
2598                                 ctrl.flags = PCIHP_CFG_CONTINUE;
2599                                 ctrl.rv = NDI_SUCCESS;
2600                                 ctrl.dip = NULL;
2601                                 ctrl.pci_dev = pci_dev;
2602                                 ctrl.op = PCIHP_ONLINE;
2603 
2604                                 ndi_devi_enter(pcihp_p->dip, &circular_count);
2605                                 ddi_walk_devs(ddi_get_child(pcihp_p->dip),
2606                                     pcihp_configure, (void *)&ctrl);
2607                                 ndi_devi_exit(pcihp_p->dip, circular_count);
2608                                 rv = HPC_ERR_FAILED;
2609                         } else {
2610                                 (void) hpc_nexus_control(slotinfop->slot_hdl,
2611                                     HPC_CTRL_DEV_UNCONFIG_START, NULL);
2612 
2613                                 if (pcicfg_unconfigure(pcihp_p->dip, pci_dev,
2614                                     PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
2615 
2616                                 /* Resources freed. Turn LED on. Clear EXT. */
2617                                 if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2618                                         if (pcihp_cpci_blue_led)
2619                                                 pcihp_hs_csr_op(pcihp_p,
2620                                                     pci_dev,
2621                                                     HPC_EVENT_SLOT_BLUE_LED_ON);
2622                                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2623                                             HPC_EVENT_SLOT_UNCONFIGURE);
2624                                         slotinfop->hs_csr_location = 0;
2625                                         slotinfop->slot_flags &=
2626                                             ~PCIHP_SLOT_DEV_NON_HOTPLUG;
2627                                 }
2628                                         slotinfop->ostate =
2629                                             AP_OSTATE_UNCONFIGURED;
2630                                         slotinfop->condition = AP_COND_UNKNOWN;
2631                                         /*
2632                                          * send the notification of state change
2633                                          * to the HPC driver.
2634                                          */
2635                                         (void) hpc_nexus_control(
2636                                             slotinfop->slot_hdl,
2637                                             HPC_CTRL_DEV_UNCONFIGURED, NULL);
2638                                         /* disconnect the slot */
2639                                         if (hpc_nexus_disconnect(
2640                                             slotinfop->slot_hdl,
2641                                             NULL, 0) == HPC_SUCCESS) {
2642                                                 slotinfop->rstate =
2643                                                     AP_RSTATE_DISCONNECTED;
2644                                         }
2645 
2646                                         cmn_err(CE_NOTE,
2647                                             "pcihp (%s%d): card is UNCONFIGURED"
2648                                             " in the slot %s (pci dev %x)",
2649                                             ddi_driver_name(pcihp_p->dip),
2650                                             ddi_get_instance(pcihp_p->dip),
2651                                             slotinfop->name, pci_dev);
2652                                 } else {
2653                                         /* tell HPC driver occupant is Busy */
2654                                         (void) hpc_nexus_control(
2655                                             slotinfop->slot_hdl,
2656                                             HPC_CTRL_DEV_UNCONFIG_FAILURE,
2657                                             NULL);
2658 
2659                                         rv = HPC_ERR_FAILED;
2660                                 }
2661                         }
2662                 }
2663 
2664                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2665 
2666                 break;
2667 
2668         case HPC_EVENT_SLOT_REMOVAL:
2669                 /*
2670                  * Card is removed from the slot. The card must have been
2671                  * unconfigured before this event.
2672                  */
2673                 if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
2674                         slotinfop->condition = AP_COND_FAILED;
2675                         cmn_err(CE_WARN, "pcihp (%s%d): card is removed"
2676                             " from the slot %s",
2677                             ddi_driver_name(pcihp_p->dip),
2678                             ddi_get_instance(pcihp_p->dip),
2679                             slotinfop->name);
2680                 } else {
2681                         slotinfop->condition = AP_COND_UNKNOWN;
2682                         cmn_err(CE_NOTE, "pcihp (%s%d): card is removed"
2683                             " from the slot %s",
2684                             ddi_driver_name(pcihp_p->dip),
2685                             ddi_get_instance(pcihp_p->dip),
2686                             slotinfop->name);
2687                 }
2688 
2689                 slotinfop->rstate = AP_RSTATE_EMPTY;
2690 
2691                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2692 
2693                 break;
2694 
2695         case HPC_EVENT_SLOT_POWER_ON:
2696                 /*
2697                  * Slot is connected to the bus. i.e the card is powered
2698                  * on. Are there any error conditions to be checked?
2699                  */
2700                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): card is powered"
2701                     " on in the slot %s",
2702                     ddi_driver_name(pcihp_p->dip),
2703                     ddi_get_instance(pcihp_p->dip),
2704                     slotinfop->name));
2705 
2706                 slotinfop->rstate = AP_RSTATE_CONNECTED; /* record rstate */
2707 
2708                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2709 
2710                 break;
2711 
2712         case HPC_EVENT_SLOT_POWER_OFF:
2713                 /*
2714                  * Slot is disconnected from the bus. i.e the card is powered
2715                  * off. Are there any error conditions to be checked?
2716                  */
2717                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): card is powered"
2718                     " off in the slot %s",
2719                     ddi_driver_name(pcihp_p->dip),
2720                     ddi_get_instance(pcihp_p->dip),
2721                     slotinfop->name));
2722 
2723                 slotinfop->rstate = AP_RSTATE_DISCONNECTED; /* record rstate */
2724 
2725                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2726 
2727                 break;
2728 
2729         case HPC_EVENT_SLOT_LATCH_SHUT:
2730                 /*
2731                  * Latch on the slot is closed.
2732                  */
2733                 cmn_err(CE_NOTE, "pcihp (%s%d): latch is shut for the slot %s",
2734                     ddi_driver_name(pcihp_p->dip),
2735                     ddi_get_instance(pcihp_p->dip),
2736                     slotinfop->name);
2737 
2738                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2739 
2740                 break;
2741 
2742         case HPC_EVENT_SLOT_LATCH_OPEN:
2743                 /*
2744                  * Latch on the slot is open.
2745                  */
2746                 cmn_err(CE_NOTE, "pcihp (%s%d): latch is open for the slot %s",
2747                     ddi_driver_name(pcihp_p->dip),
2748                     ddi_get_instance(pcihp_p->dip),
2749                     slotinfop->name);
2750 
2751                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2752 
2753                 break;
2754 
2755         case HPC_EVENT_PROCESS_ENUM:
2756                 /*
2757                  * HSC knows the device number of the slot where the
2758                  * ENUM# was triggered.
2759                  * Now finish the necessary actions to be taken on that
2760                  * slot. Please note that the interrupt is already cleared.
2761                  * This is the second(last) part of the ENUM# event processing.
2762                  */
2763                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): processing ENUM#"
2764                     " for slot %s",
2765                     ddi_driver_name(pcihp_p->dip),
2766                     ddi_get_instance(pcihp_p->dip),
2767                     slotinfop->name));
2768 
2769                 mutex_exit(&slotinfop->slot_mutex);
2770                 rv = pcihp_enum_slot(pcihp_p, slotinfop, pci_dev,
2771                     PCIHP_HANDLE_ENUM, KM_SLEEP);
2772                 mutex_enter(&slotinfop->slot_mutex);
2773 
2774                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2775 
2776                 break;
2777 
2778         case HPC_EVENT_BUS_ENUM:
2779                 /*
2780                  * Same as HPC_EVENT_SLOT_ENUM as defined the PSARC doc.
2781                  * This term is used for better clarity of its usage.
2782                  *
2783                  * ENUM signal occurred on the bus. It may be from this
2784                  * slot or any other hotplug slot on the bus.
2785                  *
2786                  * It is NOT recommended that the hotswap controller uses
2787                  * event without queuing as NDI and other DDI calls may not
2788                  * necessarily be invokable in interrupt context.
2789                  * Hence the hotswap controller driver should use the
2790                  * CLEAR_ENUM event which returns the slot device number
2791                  * and then call HPC_EVENT_PROCESS_ENUM event with queuing.
2792                  *
2793                  * This can be used when the hotswap controller is
2794                  * implementing a polled event mechanism to do the
2795                  * necessary actions in a single call.
2796                  */
2797                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): ENUM# is generated"
2798                     " on the bus (for slot %s ?)",
2799                     ddi_driver_name(pcihp_p->dip),
2800                     ddi_get_instance(pcihp_p->dip),
2801                     slotinfop->name));
2802 
2803                 mutex_exit(&slotinfop->slot_mutex);
2804                 rv = pcihp_handle_enum(pcihp_p, pci_dev, PCIHP_HANDLE_ENUM,
2805                     KM_SLEEP);
2806                 mutex_enter(&slotinfop->slot_mutex);
2807 
2808                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2809 
2810                 break;
2811 
2812         case HPC_EVENT_SLOT_BLUE_LED_ON:
2813 
2814                 /*
2815                  * Request to turn Hot Swap Blue LED on.
2816                  */
2817                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): Request To Turn On Blue "
2818                     "LED on the bus (for slot %s ?)",
2819                     ddi_driver_name(pcihp_p->dip),
2820                     ddi_get_instance(pcihp_p->dip),
2821                     slotinfop->name));
2822 
2823                 pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_BLUE_LED_ON);
2824                 break;
2825 
2826         case HPC_EVENT_DISABLE_ENUM:
2827                 /*
2828                  * Disable ENUM# which disables auto configuration on this slot
2829                  */
2830                 if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2831                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2832                             HPC_EVENT_DISABLE_ENUM);
2833                         slotinfop->slot_flags &= ~PCIHP_SLOT_AUTO_CFG_EN;
2834                 }
2835                 break;
2836 
2837         case HPC_EVENT_ENABLE_ENUM:
2838                 /*
2839                  * Enable ENUM# which enables auto configuration on this slot.
2840                  */
2841                 if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2842                         pcihp_hs_csr_op(pcihp_p, pci_dev,
2843                             HPC_EVENT_ENABLE_ENUM);
2844                         slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
2845                 }
2846                 break;
2847 
2848         case HPC_EVENT_SLOT_BLUE_LED_OFF:
2849 
2850                 /*
2851                  * Request to turn Hot Swap Blue LED off.
2852                  */
2853                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): Request To Turn Off Blue "
2854                     "LED on the bus (for slot %s ?)",
2855                     ddi_driver_name(pcihp_p->dip),
2856                     ddi_get_instance(pcihp_p->dip),
2857                     slotinfop->name));
2858 
2859                 pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_BLUE_LED_OFF);
2860 
2861                 break;
2862 
2863         case HPC_EVENT_SLOT_NOT_HEALTHY:
2864                 /*
2865                  * HEALTHY# signal on this slot is not OK.
2866                  */
2867                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): HEALTHY# signal is not OK"
2868                     " for this slot %s",
2869                     ddi_driver_name(pcihp_p->dip),
2870                     ddi_get_instance(pcihp_p->dip),
2871                     slotinfop->name));
2872 
2873                 /* record the state in slot_flags field */
2874                 slotinfop->slot_flags |= PCIHP_SLOT_NOT_HEALTHY;
2875                 slotinfop->condition = AP_COND_FAILED;
2876 
2877                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2878 
2879                 break;
2880 
2881         case HPC_EVENT_SLOT_HEALTHY_OK:
2882                 /*
2883                  * HEALTHY# signal on this slot is OK now.
2884                  */
2885                 PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): HEALTHY# signal is OK now"
2886                     " for this slot %s",
2887                     ddi_driver_name(pcihp_p->dip),
2888                     ddi_get_instance(pcihp_p->dip),
2889                     slotinfop->name));
2890 
2891                 /* update the state in slot_flags field */
2892                 slotinfop->slot_flags &= ~PCIHP_SLOT_NOT_HEALTHY;
2893                 slotinfop->condition = AP_COND_OK;
2894 
2895                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2896 
2897                 break;
2898 
2899         case HPC_EVENT_SLOT_ATTN:
2900                 /*
2901                  * Attention button is pressed.
2902                  */
2903                 if (((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) ||
2904                     (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
2905                         /*
2906                          * either auto-conifiguration or the slot is disabled,
2907                          * ignore this event.
2908                          */
2909                         break;
2910                 }
2911 
2912                 if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED)
2913                         hint = SE_INCOMING_RES;
2914                 else
2915                         hint = SE_OUTGOING_RES;
2916 
2917                 if (ddi_getprop(DDI_DEV_T_ANY, pcihp_p->dip, DDI_PROP_DONTPASS,
2918                     "inkernel-autoconfig", 0) == 0) {
2919                         pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_REQ, hint,
2920                             pcihp_p->dip, KM_SLEEP);
2921                         break;
2922                 }
2923 
2924                 if ((slotinfop->ostate == AP_OSTATE_UNCONFIGURED) &&
2925                     (slotinfop->rstate != AP_RSTATE_EMPTY) &&
2926                     (slotinfop->condition != AP_COND_FAILED)) {
2927                         if (slotinfop->rstate == AP_RSTATE_DISCONNECTED) {
2928                                 rv = hpc_nexus_connect(slotinfop->slot_hdl,
2929                                     NULL, 0);
2930                                 if (rv == HPC_SUCCESS)
2931                                         slotinfop->rstate = AP_RSTATE_CONNECTED;
2932                                 else
2933                                         break;
2934                         }
2935 
2936                         rv = pcihp_configure_ap(pcihp_p, pci_dev);
2937 
2938                 } else if ((slotinfop->ostate == AP_OSTATE_CONFIGURED) &&
2939                     (slotinfop->rstate == AP_RSTATE_CONNECTED) &&
2940                     (slotinfop->condition != AP_COND_FAILED)) {
2941                         rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
2942 
2943                         if (rv != HPC_SUCCESS)
2944                                 break;
2945 
2946                         rv = hpc_nexus_disconnect(slotinfop->slot_hdl,
2947                             NULL, 0);
2948                         if (rv == HPC_SUCCESS)
2949                                 slotinfop->rstate = AP_RSTATE_DISCONNECTED;
2950                 }
2951 
2952                 break;
2953 
2954         case HPC_EVENT_SLOT_POWER_FAULT:
2955                 /*
2956                  * Power fault is detected.
2957                  */
2958                 cmn_err(CE_NOTE, "pcihp (%s%d): power-fault"
2959                     " for this slot %s",
2960                     ddi_driver_name(pcihp_p->dip),
2961                     ddi_get_instance(pcihp_p->dip),
2962                     slotinfop->name);
2963 
2964                 /* turn on ATTN led */
2965                 led_info.led = HPC_ATTN_LED;
2966                 led_info.state = HPC_LED_ON;
2967                 rv = hpc_nexus_control(slotinfop->slot_hdl,
2968                     HPC_CTRL_SET_LED_STATE, (caddr_t)&led_info);
2969 
2970                 if (slotinfop->rstate == AP_RSTATE_CONNECTED)
2971                         (void) hpc_nexus_disconnect(slotinfop->slot_hdl,
2972                             NULL, 0);
2973 
2974                 slotinfop->condition = AP_COND_FAILED;
2975 
2976                 pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_AP_STATE_CHANGE,
2977                     SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
2978 
2979                 break;
2980 
2981         default:
2982                 cmn_err(CE_NOTE, "pcihp (%s%d): unknown event %x"
2983                     " for this slot %s",
2984                     ddi_driver_name(pcihp_p->dip),
2985                     ddi_get_instance(pcihp_p->dip), event_mask,
2986                     slotinfop->name);
2987 
2988                 /* +++ HOOK for RCM to report this hotplug event? +++ */
2989 
2990                 break;
2991         }
2992 
2993         mutex_exit(&slotinfop->slot_mutex);
2994 
2995         (void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT, &rval);
2996 
2997         return (rv);
2998 }
2999 
3000 /*
3001  * This function is called to online or offline the devices for an
3002  * attachment point. If the PCI device number of the node matches
3003  * with the device number of the specified hot plug slot then
3004  * the operation is performed.
3005  */
3006 static int
3007 pcihp_configure(dev_info_t *dip, void *hdl)
3008 {
3009         int pci_dev;
3010         struct pcihp_config_ctrl *ctrl = (struct pcihp_config_ctrl *)hdl;
3011         int rv;
3012         pci_regspec_t *pci_rp;
3013         int length;
3014 
3015         /*
3016          * Get the PCI device number information from the devinfo
3017          * node. Since the node may not have the address field
3018          * setup (this is done in the DDI_INITCHILD of the parent)
3019          * we look up the 'reg' property to decode that information.
3020          */
3021         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3022             "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
3023                 ctrl->rv = DDI_FAILURE;
3024                 ctrl->dip = dip;
3025                 return (DDI_WALK_TERMINATE);
3026         }
3027 
3028         /* get the pci device id information */
3029         pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
3030 
3031         /*
3032          * free the memory allocated by ddi_prop_lookup_int_array
3033          */
3034         ddi_prop_free(pci_rp);
3035 
3036         /*
3037          * Match the node for the device number of the slot.
3038          */
3039         if (pci_dev == ctrl->pci_dev) {      /* node is a match */
3040                 if (ctrl->op == PCIHP_ONLINE) {
3041                         /* it is CONFIGURE operation */
3042 
3043                         /* skip this device if it is disabled or faulty */
3044                         if (pcihp_check_status(dip) == B_FALSE) {
3045                                 return (DDI_WALK_PRUNECHILD);
3046                         }
3047 
3048                         rv = ndi_devi_online(dip, NDI_ONLINE_ATTACH|NDI_CONFIG);
3049                 } else {
3050                         /*
3051                          * it is UNCONFIGURE operation.
3052                          */
3053                         rv = ndi_devi_offline(dip, NDI_UNCONFIG);
3054                 }
3055                 if (rv != NDI_SUCCESS) {
3056                         /* failed to attach/detach the driver(s) */
3057                         ctrl->rv = rv;
3058                         ctrl->dip = dip;
3059                         /* terminate the search if specified */
3060                         if (!(ctrl->flags & PCIHP_CFG_CONTINUE))
3061                                 return (DDI_WALK_TERMINATE);
3062                 }
3063         }
3064 
3065         /*
3066          * continue the walk to the next sibling to look for a match
3067          * or to find other nodes if this card is a multi-function card.
3068          */
3069         return (DDI_WALK_PRUNECHILD);
3070 }
3071 
3072 /*
3073  * Check the device for a 'status' property.  A conforming device
3074  * should have a status of "okay", "disabled", "fail", or "fail-xxx".
3075  *
3076  * Return FALSE for a conforming device that is disabled or faulted.
3077  * Return TRUE in every other case.
3078  */
3079 static bool_t
3080 pcihp_check_status(dev_info_t *dip)
3081 {
3082         char *status_prop;
3083         bool_t rv = B_TRUE;
3084 
3085         /* try to get the 'status' property */
3086         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3087             "status", &status_prop) == DDI_PROP_SUCCESS) {
3088 
3089                 /*
3090                  * test if the status is "disabled", "fail", or
3091                  * "fail-xxx".
3092                  */
3093                 if (strcmp(status_prop, "disabled") == 0) {
3094                         rv = B_FALSE;
3095                         PCIHP_DEBUG((CE_NOTE,
3096                             "pcihp (%s%d): device is in disabled state",
3097                             ddi_driver_name(dip), ddi_get_instance(dip)));
3098                 } else if (strncmp(status_prop, "fail", 4) == 0) {
3099                         rv = B_FALSE;
3100                         cmn_err(CE_WARN,
3101                             "pcihp (%s%d): device is in fault state (%s)",
3102                             ddi_driver_name(dip), ddi_get_instance(dip),
3103                             status_prop);
3104                 }
3105 
3106                 ddi_prop_free(status_prop);
3107         }
3108 
3109         return (rv);
3110 }
3111 
3112 /* control structure used to find a device in the devinfo tree */
3113 struct pcihp_find_ctrl {
3114         uint_t          device;
3115         uint_t          function;
3116         dev_info_t      *dip;
3117 };
3118 
3119 static dev_info_t *
3120 pcihp_devi_find(dev_info_t *dip, uint_t device, uint_t function)
3121 {
3122         struct pcihp_find_ctrl ctrl;
3123         int circular_count;
3124 
3125         ctrl.device = device;
3126         ctrl.function = function;
3127         ctrl.dip = NULL;
3128 
3129         ndi_devi_enter(dip, &circular_count);
3130         ddi_walk_devs(ddi_get_child(dip), pcihp_match_dev, (void *)&ctrl);
3131         ndi_devi_exit(dip, circular_count);
3132 
3133         return (ctrl.dip);
3134 }
3135 
3136 static int
3137 pcihp_match_dev(dev_info_t *dip, void *hdl)
3138 {
3139         struct pcihp_find_ctrl *ctrl = (struct pcihp_find_ctrl *)hdl;
3140         pci_regspec_t *pci_rp;
3141         int length;
3142         int pci_dev;
3143         int pci_func;
3144 
3145         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3146             "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
3147                 ctrl->dip = NULL;
3148                 return (DDI_WALK_TERMINATE);
3149         }
3150 
3151         /* get the PCI device address info */
3152         pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
3153         pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
3154 
3155         /*
3156          * free the memory allocated by ddi_prop_lookup_int_array
3157          */
3158         ddi_prop_free(pci_rp);
3159 
3160 
3161         if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
3162                 /* found the match for the specified device address */
3163                 ctrl->dip = dip;
3164                 return (DDI_WALK_TERMINATE);
3165         }
3166 
3167         /*
3168          * continue the walk to the next sibling to look for a match.
3169          */
3170         return (DDI_WALK_PRUNECHILD);
3171 }
3172 
3173 #if 0
3174 /*
3175  * Probe the configuration space of the slot to determine the receptacle
3176  * state. There may not be any devinfo tree created for this slot.
3177  */
3178 static void
3179 pcihp_probe_slot_state(dev_info_t *dip, int dev, hpc_slot_state_t *rstatep)
3180 {
3181         /* XXX FIX IT */
3182 }
3183 #endif
3184 
3185 /*
3186  * This routine is called when a ENUM# assertion is detected for a bus.
3187  * Since ENUM# may be bussed, the slot that asserted ENUM# may not be known.
3188  * The HPC Driver passes the handle of a slot that is its best guess.
3189  * If the best guess slot is the one that asserted ENUM#, the proper handling
3190  * will be done.  If its not, all possible slots will be locked at until
3191  * one that is asserting ENUM is found.
3192  * Also, indicate to the HSC to turn on ENUM# after it is serviced,
3193  * incase if it was disabled by the HSC due to the nature of asynchronous
3194  * delivery of interrupt by the framework.
3195  *
3196  * opcode has the following meanings.
3197  * PCIHP_CLEAR_ENUM = just clear interrupt and return the PCI device no. if
3198  *                      success, else return -1.
3199  * PCIHP_HANDLE_ENUM = clear interrupt and handle interrupt also.
3200  *
3201  */
3202 static int
3203 pcihp_handle_enum(pcihp_t *pcihp_p, int favorite_pci_dev, int opcode,
3204         int kmflag)
3205 {
3206         struct pcihp_slotinfo *slotinfop;
3207         int pci_dev, rc, event_serviced = 0;
3208 
3209         /*
3210          * Handle ENUM# condition for the "favorite" slot first.
3211          */
3212         slotinfop = &pcihp_p->slotinfo[favorite_pci_dev];
3213         if (slotinfop) {
3214                 /*
3215                  * First try the "favorite" pci device.  This is the device
3216                  * associated with the handle passed by the HPC Driver.
3217                  */
3218                 rc = pcihp_enum_slot(pcihp_p, slotinfop, favorite_pci_dev,
3219                     opcode, kmflag);
3220                 if (rc != HPC_EVENT_UNCLAIMED) {        /* indicates success */
3221                         event_serviced = 1;
3222                         /* This MUST be a non-DEBUG feature. */
3223                         if (! pcihp_enum_scan_all) {
3224                                 return (rc);
3225                         }
3226                 }
3227         }
3228 
3229         /*
3230          * If ENUM# is implemented as a radial signal, then there is no
3231          * need to further poll the slots.
3232          */
3233         if (pcihp_p->bus_flags & PCIHP_BUS_ENUM_RADIAL)
3234                 goto enum_service_check;
3235 
3236         /*
3237          * If the "favorite" pci device didn't assert ENUM#, then
3238          * try the rest.  Once we find and handle a device that asserted
3239          * ENUM#, then we will terminate the walk by returning unless
3240          * scan-all flag is set.
3241          */
3242         for (pci_dev = 0; pci_dev < PCI_MAX_DEVS; pci_dev++) {
3243                 if (pci_dev != favorite_pci_dev) {
3244                         slotinfop = &pcihp_p->slotinfo[pci_dev];
3245                         if (slotinfop == NULL) {
3246                                 continue;
3247                         }
3248                         /* Only CPCI devices support ENUM# generation. */
3249                         if (!(slotinfop->slot_type & HPC_SLOT_TYPE_CPCI))
3250                                 continue;
3251                         rc = pcihp_enum_slot(pcihp_p, slotinfop, pci_dev,
3252                             opcode, kmflag);
3253                         if (rc != HPC_EVENT_UNCLAIMED) {
3254                                 event_serviced = 1;
3255                                 /* This MUST be a non-DEBUG feature. */
3256                                 if (! pcihp_enum_scan_all)
3257                                         break;
3258                         }
3259                 }
3260         }
3261 
3262 enum_service_check:
3263         if (event_serviced) {
3264                 return (rc);
3265         }
3266 
3267         /* No ENUM# event found, Return */
3268         return (HPC_EVENT_UNCLAIMED);
3269 }
3270 
3271 /*
3272  * This routine attempts to handle a possible ENUM# assertion case for a
3273  * specified slot.  This only works for adapters that implement Hot Swap
3274  * Friendly Silicon.  If the slot's HS_CSR is read and it specifies ENUM#
3275  * has been asserted, either the insertion or removal handlers will be
3276  * called.
3277  */
3278 static int
3279 pcihp_enum_slot(pcihp_t *pcihp_p, struct pcihp_slotinfo *slotinfop, int pci_dev,
3280                 int opcode, int kmflag)
3281 {
3282         ddi_acc_handle_t handle;
3283         dev_info_t *dip, *new_child = NULL;
3284         int result, rv = -1;
3285         uint8_t hs_csr;
3286 
3287         if (pcihp_config_setup(&dip, &handle, &new_child, pci_dev,
3288             pcihp_p) != DDI_SUCCESS) {
3289                 return (HPC_EVENT_UNCLAIMED);
3290         }
3291 
3292         /*
3293          * Read the device's HS_CSR.
3294          */
3295         result = pcihp_get_hs_csr(slotinfop, handle, (uint8_t *)&hs_csr);
3296         PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): hs_csr = %x, flags = %x",
3297             ddi_driver_name(pcihp_p->dip), ddi_get_instance(pcihp_p->dip),
3298             hs_csr, slotinfop->slot_flags));
3299         /*
3300          * we teardown our device map here, because in case of an
3301          * extraction event, our nodes would be freed and a teardown
3302          * will cause problems.
3303          */
3304         pcihp_config_teardown(&handle, &new_child, pci_dev, pcihp_p);
3305 
3306         if (result == PCIHP_SUCCESS) {
3307 
3308                 /* If ENUM# is masked, then it is not us. Some other device */
3309                 if ((hs_csr & HS_CSR_EIM) && (opcode == PCIHP_CLEAR_ENUM))
3310                         return (HPC_EVENT_UNCLAIMED);
3311                 /*
3312                  * This device supports Full Hot Swap and implements
3313                  * the Hot Swap Control and Status Register.
3314                  */
3315                 if ((hs_csr & HS_CSR_INS) ||
3316                     (slotinfop->slot_flags & PCIHP_SLOT_ENUM_INS_PENDING)) {
3317                         /* handle insertion ENUM */
3318                         PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): "
3319                             "Handle Insertion ENUM (INS) "
3320                             "on the bus (for slot %s ?)",
3321                             ddi_driver_name(pcihp_p->dip),
3322                             ddi_get_instance(pcihp_p->dip),
3323                             slotinfop->name));
3324 
3325                         /*
3326                          * generate sysevent
3327                          */
3328 
3329                         if (opcode == PCIHP_CLEAR_ENUM)
3330                                 pcihp_gen_sysevent(slotinfop->name,
3331                                     PCIHP_DR_REQ,
3332                                     SE_INCOMING_RES, pcihp_p->dip,
3333                                     kmflag);
3334 
3335                         rv = pcihp_handle_enum_insertion(pcihp_p, pci_dev,
3336                             opcode, kmflag);
3337 
3338                 } else if ((hs_csr & HS_CSR_EXT) ||
3339                     (slotinfop->slot_flags & PCIHP_SLOT_ENUM_EXT_PENDING)) {
3340                         /* handle extraction ENUM */
3341                         PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): "
3342                             "Handle Extraction ENUM (EXT) "
3343                             "on the bus (for slot %s ?)",
3344                             ddi_driver_name(pcihp_p->dip),
3345                             ddi_get_instance(pcihp_p->dip),
3346                             slotinfop->name));
3347 
3348                         /*
3349                          * generate sysevent
3350                          */
3351 
3352                         if (opcode == PCIHP_CLEAR_ENUM)
3353                                 pcihp_gen_sysevent(slotinfop->name,
3354                                     PCIHP_DR_REQ,
3355                                     SE_OUTGOING_RES,
3356                                     pcihp_p->dip,
3357                                     kmflag);
3358 
3359                         rv = pcihp_handle_enum_extraction(pcihp_p, pci_dev,
3360                             opcode, kmflag);
3361                 }
3362                 if (opcode == PCIHP_CLEAR_ENUM) {
3363                         if (rv == PCIHP_SUCCESS)
3364                                 rv = pci_dev;
3365                         else
3366                                 rv = HPC_EVENT_UNCLAIMED;
3367                 }
3368         }
3369 
3370         return (rv);
3371 }
3372 
3373 /*
3374  * This routine is called when a ENUM# caused by lifting the lever
3375  * is detected.  If the occupant is configured, it will be unconfigured.
3376  * If the occupant is already unconfigured or is successfully unconfigured,
3377  * the blue LED on the adapter is illuminated which means its OK to remove.
3378  * Please note that the lock must be released before invoking the
3379  * generic AP unconfigure function.
3380  */
3381 static int
3382 pcihp_handle_enum_extraction(pcihp_t *pcihp_p, int pci_dev, int opcode,
3383         int kmflag)
3384 {
3385         struct pcihp_slotinfo *slotinfop;
3386         int rv = PCIHP_FAILURE;
3387 
3388         slotinfop = &pcihp_p->slotinfo[pci_dev];
3389 
3390         /*
3391          * It was observed that, clearing the EXT bit turned the LED ON.
3392          * This is a BIG problem in case if the unconfigure operation
3393          * failed because the board was busy.
3394          * In order to avoid this confusing situation (LED ON but the board
3395          * is not unconfigured), we instead decided not to clear EXT but
3396          * disable further ENUM# from this slot. Disabling ENUM# clears
3397          * the interrupt.
3398          * Finally before returning we clear the interrupt and enable
3399          * ENUM# back again from this slot.
3400          */
3401         pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
3402         if (opcode == PCIHP_CLEAR_ENUM) {
3403                 slotinfop->slot_flags |= PCIHP_SLOT_ENUM_EXT_PENDING;
3404                 return (PCIHP_SUCCESS);
3405         }
3406 
3407         mutex_enter(&slotinfop->slot_mutex);
3408         rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
3409         mutex_exit(&slotinfop->slot_mutex);
3410         if (rv != HPC_SUCCESS && rv != EBUSY) {
3411                 cmn_err(CE_NOTE, "%s%d: PCI device %x Failed on Unconfigure",
3412                     ddi_driver_name(pcihp_p->dip),
3413                     ddi_get_instance(pcihp_p->dip), pci_dev);
3414         }
3415         if (rv == EBUSY)
3416                 cmn_err(CE_NOTE, "%s%d: PCI device %x Busy",
3417                     ddi_driver_name(pcihp_p->dip),
3418                     ddi_get_instance(pcihp_p->dip), pci_dev);
3419         if (rv) {
3420                 if (pcihp_cpci_blue_led)
3421                         pcihp_hs_csr_op(pcihp_p, pci_dev,
3422                             HPC_EVENT_SLOT_BLUE_LED_OFF);
3423         }
3424         /*
3425          * we must clear interrupt in case the unconfigure didn't do it
3426          * due to a duplicate interrupt. Extraction is success.
3427          */
3428         pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_UNCONFIGURE);
3429 
3430         if (!rv) {
3431                 /*
3432                  * Sys Event Notification.
3433                  */
3434                 pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_AP_STATE_CHANGE,
3435                     SE_HINT_REMOVE, pcihp_p->dip, kmflag);
3436         }
3437 
3438         /*
3439          * Enable interrupts back from this board.
3440          * This could potentially be problematic in case if the user is
3441          * quick enough to extract the board.
3442          * But we must do it just in case if the switch is closed again.
3443          */
3444         pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
3445         slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_EXT_PENDING;
3446         return (rv);
3447 }
3448 
3449 /*
3450  * This routine is called when a ENUM# caused by when an adapter insertion
3451  * is detected.  If the occupant is successfully configured (i.e. PCI resources
3452  * successfully assigned, the blue LED is left off, otherwise if configuration
3453  * is not successful, the blue LED is illuminated.
3454  * Please note that the lock must be released before invoking the
3455  * generic AP configure function.
3456  */
3457 static int
3458 pcihp_handle_enum_insertion(pcihp_t *pcihp_p, int pci_dev, int opcode,
3459         int kmflag)
3460 {
3461         struct pcihp_slotinfo *slotinfop;
3462         int rv = PCIHP_FAILURE;
3463         minor_t ap_minor;
3464         major_t ap_major;
3465 
3466         slotinfop = &pcihp_p->slotinfo[pci_dev];
3467         slotinfop->hs_csr_location = 0;
3468         /* we clear the interrupt here. This is a must here. */
3469         pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_CONFIGURE);
3470         /*
3471          * disable further interrupt from this board till it is
3472          * configured.
3473          */
3474         pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
3475         if (opcode == PCIHP_CLEAR_ENUM) {
3476                 slotinfop->slot_flags |= PCIHP_SLOT_ENUM_INS_PENDING;
3477                 return (PCIHP_SUCCESS);
3478         }
3479 
3480         if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) ==
3481             PCIHP_SLOT_AUTO_CFG_EN) {
3482                 mutex_enter(&slotinfop->slot_mutex);
3483                 rv = pcihp_configure_ap(pcihp_p, pci_dev);
3484                 mutex_exit(&slotinfop->slot_mutex);
3485                 if (rv != HPC_SUCCESS) {        /* configure failed */
3486                         cmn_err(CE_NOTE, "%s%d: PCI device %x Failed on"
3487                             " Configure", ddi_driver_name(pcihp_p->dip),
3488                             ddi_get_instance(pcihp_p->dip), pci_dev);
3489                         if (pcihp_cpci_blue_led)
3490                                 pcihp_hs_csr_op(pcihp_p, pci_dev,
3491                                     HPC_EVENT_SLOT_BLUE_LED_ON);
3492                 }
3493 
3494                 /* pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_CLEAR_ENUM); */
3495                 pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
3496 
3497                 if (!rv) {
3498                         ap_major = ddi_driver_major(pcihp_p->dip);
3499                         ap_minor = PCIHP_AP_MINOR_NUM(
3500                             ddi_get_instance(pcihp_p->dip), pci_dev);
3501                         pcihp_create_occupant_props(pcihp_p->dip,
3502                             makedevice(ap_major, ap_minor), pci_dev);
3503 
3504                         /*
3505                          * Sys Event Notification.
3506                          */
3507                         pcihp_gen_sysevent(slotinfop->name,
3508                             PCIHP_DR_AP_STATE_CHANGE,
3509                             SE_HINT_INSERT, pcihp_p->dip, kmflag);
3510                 }
3511 
3512         } else
3513                 rv = PCIHP_SUCCESS;
3514         slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_INS_PENDING;
3515         return (rv);
3516 }
3517 
3518 /*
3519  * Read the Hot Swap Control and Status Register (HS_CSR) and
3520  * place the result in the location pointed to be hs_csr.
3521  */
3522 static int
3523 pcihp_get_hs_csr(struct pcihp_slotinfo *slotinfop,
3524     ddi_acc_handle_t config_handle, uint8_t *hs_csr)
3525 {
3526         if (slotinfop->hs_csr_location == -1)
3527                 return (PCIHP_FAILURE);
3528 
3529         if (slotinfop->hs_csr_location == 0) {
3530                 slotinfop->hs_csr_location =
3531                     pcihp_get_hs_csr_location(config_handle);
3532 
3533                 if (slotinfop->hs_csr_location == -1)
3534                         return (PCIHP_FAILURE);
3535         }
3536         *hs_csr = pci_config_get8(config_handle, slotinfop->hs_csr_location);
3537         return (PCIHP_SUCCESS);
3538 }
3539 
3540 /*
3541  * Write the Hot Swap Control and Status Register (HS_CSR) with
3542  * the value being pointed at by hs_csr.
3543  */
3544 static void
3545 pcihp_set_hs_csr(struct pcihp_slotinfo *slotinfop,
3546     ddi_acc_handle_t config_handle, uint8_t *hs_csr)
3547 {
3548         if (slotinfop->hs_csr_location == -1)
3549                 return;
3550         if (slotinfop->hs_csr_location == 0) {
3551                 slotinfop->hs_csr_location =
3552                     pcihp_get_hs_csr_location(config_handle);
3553                 if (slotinfop->hs_csr_location == -1)
3554                         return;
3555         }
3556         pci_config_put8(config_handle, slotinfop->hs_csr_location, *hs_csr);
3557         PCIHP_DEBUG((CE_NOTE, "hs_csr wrote %x, read %x", *hs_csr,
3558             pci_config_get8(config_handle, slotinfop->hs_csr_location)));
3559 }
3560 
3561 static int
3562 pcihp_get_hs_csr_location(ddi_acc_handle_t config_handle)
3563 {
3564         uint8_t cap_id;
3565         uint_t  cap_id_loc;
3566         uint16_t        status;
3567         int location = -1;
3568 #define PCI_STAT_ECP_SUPP       0x10
3569 
3570         /*
3571          * Need to check the Status register for ECP support first.
3572          * Also please note that for type 1 devices, the
3573          * offset could change. Should support type 1 next.
3574          */
3575         status = pci_config_get16(config_handle, PCI_CONF_STAT);
3576         if (!(status & PCI_STAT_ECP_SUPP)) {
3577                 PCIHP_DEBUG((CE_NOTE, "No Ext Capabilities for device\n"));
3578                 return (-1);
3579         }
3580         cap_id_loc = pci_config_get8(config_handle, PCI_CONF_EXTCAP);
3581 
3582         /*
3583          * Walk the list of capabilities, but don't walk past the end
3584          * of the Configuration Space Header.
3585          */
3586         while ((cap_id_loc) && (cap_id_loc < PCI_CONF_HDR_SIZE)) {
3587 
3588                 cap_id = pci_config_get8(config_handle, cap_id_loc);
3589 
3590                 if (cap_id == CPCI_HOTSWAP_CAPID) {
3591                         location = cap_id_loc + PCI_ECP_HS_CSR;
3592                         break;
3593                 }
3594                 cap_id_loc = pci_config_get8(config_handle,
3595                     cap_id_loc + 1);
3596         }
3597         return (location);
3598 }
3599 
3600 static int
3601 pcihp_add_dummy_reg_property(dev_info_t *dip,
3602     uint_t bus, uint_t device, uint_t func)
3603 {
3604         pci_regspec_t dummy_reg;
3605 
3606         bzero(&dummy_reg, sizeof (dummy_reg));
3607 
3608         dummy_reg.pci_phys_hi = PCIHP_MAKE_REG_HIGH(bus, device, func, 0);
3609 
3610         return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3611             "reg", (int *)&dummy_reg, sizeof (pci_regspec_t)/sizeof (int)));
3612 }
3613 
3614 static void
3615 pcihp_hs_csr_op(pcihp_t *pcihp_p, int pci_dev, int event)
3616 {
3617         struct pcihp_slotinfo *slotinfop;
3618         ddi_acc_handle_t config_handle;
3619         dev_info_t *dip, *new_child = NULL;
3620         uint8_t hs_csr;
3621         int result;
3622 
3623         slotinfop = &pcihp_p->slotinfo[pci_dev];
3624 
3625         if (pcihp_config_setup(&dip, &config_handle, &new_child, pci_dev,
3626             pcihp_p) != DDI_SUCCESS) {
3627                 return;
3628         }
3629 
3630         result = pcihp_get_hs_csr(slotinfop, config_handle, (uint8_t *)&hs_csr);
3631         if ((result != PCIHP_SUCCESS) || (event == -1)) {
3632                 pcihp_config_teardown(&config_handle, &new_child, pci_dev,
3633                     pcihp_p);
3634                 return;
3635         }
3636 
3637         hs_csr &= 0xf;
3638         switch (event) {
3639                 case HPC_EVENT_SLOT_BLUE_LED_ON:
3640                         hs_csr |= HS_CSR_LOO;
3641                         break;
3642                 case HPC_EVENT_SLOT_BLUE_LED_OFF:
3643                         hs_csr &= ~HS_CSR_LOO;
3644                         break;
3645                 case HPC_EVENT_SLOT_CONFIGURE:
3646                         hs_csr |= HS_CSR_INS;   /* clear INS */
3647                         break;
3648                 case HPC_EVENT_CLEAR_ENUM:
3649                         hs_csr |= (HS_CSR_INS | HS_CSR_EXT);
3650                         break;
3651                 case HPC_EVENT_SLOT_UNCONFIGURE:
3652                         hs_csr |= HS_CSR_EXT;   /* clear EXT */
3653                         break;
3654                 case HPC_EVENT_ENABLE_ENUM:
3655                         hs_csr &= ~HS_CSR_EIM;
3656                         break;
3657                 case HPC_EVENT_DISABLE_ENUM:
3658                         hs_csr |= HS_CSR_EIM;
3659                         break;
3660                 case HPC_EVENT_SLOT_NOT_HEALTHY:
3661                 case HPC_EVENT_SLOT_HEALTHY_OK:
3662                 default:
3663                         break;
3664         }
3665         pcihp_set_hs_csr(slotinfop, config_handle, (uint8_t *)&hs_csr);
3666         pcihp_config_teardown(&config_handle, &new_child, pci_dev, pcihp_p);
3667 }
3668 
3669 static int
3670 pcihp_config_setup(dev_info_t **dip, ddi_acc_handle_t *handle,
3671                         dev_info_t **new_child, int pci_dev, pcihp_t *pcihp_p)
3672 {
3673         dev_info_t *pdip = pcihp_p->dip;
3674         int bus, len, rc = DDI_SUCCESS;
3675         struct pcihp_slotinfo *slotinfop;
3676         hpc_slot_state_t rstate;
3677         ddi_acc_hdl_t *hp;
3678         pci_bus_range_t pci_bus_range;
3679 
3680         slotinfop = &pcihp_p->slotinfo[pci_dev];
3681 
3682         /*
3683          * If declared failed, don't allow Config operations.
3684          * Otherwise, if good or failing, it is assumed Ok
3685          * to get config data.
3686          */
3687         if (slotinfop->condition == AP_COND_FAILED) {
3688                 return (PCIHP_FAILURE);
3689         }
3690         /*
3691          * check to see if there is a hardware present first.
3692          * If no hardware present, no need to probe this slot.
3693          * We can do this first probably as a first step towards
3694          * safeguarding from accidental removal (we don't support it!).
3695          */
3696         if (hpc_nexus_control(slotinfop->slot_hdl, HPC_CTRL_GET_SLOT_STATE,
3697             (caddr_t)&rstate) != 0) {
3698                 return (DDI_FAILURE);
3699         }
3700 
3701         if (rstate != HPC_SLOT_CONNECTED) {
3702                 /* error. slot must be connected */
3703                 return (DDI_FAILURE);
3704         }
3705         *new_child = NULL;
3706 
3707         /*
3708          * If there is no dip then we need to see if an
3709          * adapter has just been hot plugged.
3710          */
3711         len = sizeof (pci_bus_range_t);
3712         if (ddi_getlongprop_buf(DDI_DEV_T_ANY, pdip,
3713             0, "bus-range",
3714             (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
3715 
3716                 return (PCIHP_FAILURE);
3717         }
3718 
3719         /* primary bus number of this bus node */
3720         bus = pci_bus_range.lo;
3721 
3722         if (ndi_devi_alloc(pdip, DEVI_PSEUDO_NEXNAME,
3723             (pnode_t)DEVI_SID_NODEID, dip) != NDI_SUCCESS) {
3724 
3725                 PCIHP_DEBUG((CE_NOTE, "Failed to alloc probe node\n"));
3726                 return (PCIHP_FAILURE);
3727         }
3728 
3729         if (pcihp_add_dummy_reg_property(*dip, bus,
3730             pci_dev, 0) != DDI_SUCCESS) {
3731 
3732                 (void) ndi_devi_free(*dip);
3733                 return (PCIHP_FAILURE);
3734         }
3735 
3736         /*
3737          * Probe for a device. Possibly a non (c)PCI board could be sitting
3738          * here which would never respond to PCI config cycles - in which
3739          * case we return. Eventually a configure operation would fail.
3740          */
3741         if (pci_config_setup(*dip, handle) != DDI_SUCCESS) {
3742                 cmn_err(CE_WARN, "Cannot set config space map for"
3743                     " pci device number %d", pci_dev);
3744                 (void) ndi_devi_free(*dip);
3745                 return (PCIHP_FAILURE);
3746         }
3747 
3748         /*
3749          * See if there is any PCI HW at this location
3750          * by reading the Vendor ID.  If it returns with 0xffff
3751          * then there is no hardware at this location.
3752          */
3753         if (pcihp_indirect_map(*dip) == DDI_SUCCESS) {
3754                 if (pci_config_get16(*handle, 0) == 0xffff) {
3755                         pci_config_teardown(handle);
3756                         (void) ndi_devi_free(*dip);
3757                         return (PCIHP_FAILURE);
3758                 }
3759         } else {
3760                 /* Check if mapping is OK */
3761                 hp = impl_acc_hdl_get(*handle);
3762 
3763                 if (ddi_peek16(*dip, (int16_t *)(hp->ah_addr),
3764                     (int16_t *)0) != DDI_SUCCESS) {
3765 #ifdef DEBUG
3766                         cmn_err(CE_WARN, "Cannot Map PCI config space for "
3767                             "device number %d", pci_dev);
3768 #endif
3769                         pci_config_teardown(handle);
3770                         (void) ndi_devi_free(*dip);
3771                         return (PCIHP_FAILURE);
3772                 }
3773         }
3774 
3775         *new_child = *dip;
3776         return (rc);
3777 
3778 }
3779 
3780 static void
3781 pcihp_config_teardown(ddi_acc_handle_t *handle,
3782                         dev_info_t **new_child, int pci_dev, pcihp_t *pcihp_p)
3783 {
3784         struct pcihp_slotinfo *slotinfop = &pcihp_p->slotinfo[pci_dev];
3785 
3786         pci_config_teardown(handle);
3787         if (*new_child) {
3788                 (void) ndi_devi_free(*new_child);
3789                 /*
3790                  * If occupant not configured, reset HS_CSR location
3791                  * so that we reprobe. This covers cases where
3792                  * the receptacle had a status change without a
3793                  * notification to the framework.
3794                  */
3795                 if (slotinfop->ostate != AP_OSTATE_CONFIGURED)
3796                         slotinfop->hs_csr_location = 0;
3797         }
3798 }
3799 
3800 static int
3801 pcihp_get_board_type(struct pcihp_slotinfo *slotinfop)
3802 {
3803         hpc_board_type_t board_type;
3804 
3805         /*
3806          * Get board type data structure, hpc_board_type_t.
3807          */
3808         if (hpc_nexus_control(slotinfop->slot_hdl, HPC_CTRL_GET_BOARD_TYPE,
3809             (caddr_t)&board_type) != 0) {
3810 
3811                 cmn_err(CE_WARN, "Cannot Get Board Type..");
3812                 return (-1);
3813         }
3814 
3815         /*
3816          * We expect the Hotswap Controller to tell us if the board is
3817          * a hotswap board or not, as it probably cannot differentiate
3818          * between a basic hotswap board, a non hotswap board and a
3819          * hotswap nonfriendly board.
3820          * So here is the logic to differentiate between the various
3821          * types of cPCI boards.
3822          * In case if the HSC returns board type as unknown, we assign
3823          * the default board type as defined by a configurable variable
3824          * for a BHS, nonfriendly FHS and non HS board.
3825          */
3826         if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
3827                 if (slotinfop->hs_csr_location > 0)
3828                         board_type = HPC_BOARD_CPCI_FULL_HS;
3829                 else {
3830                         if (board_type == HPC_BOARD_CPCI_HS) {
3831                                 if (slotinfop->hs_csr_location == -1)
3832                                         board_type = HPC_BOARD_CPCI_BASIC_HS;
3833                         }
3834                         if (board_type == HPC_BOARD_UNKNOWN) {
3835                                 if (slotinfop->hs_csr_location == -1) {
3836                                         board_type = pcihp_cpci_board_type;
3837                                 } else if (slotinfop->hs_csr_location != 0) {
3838                                         board_type = HPC_BOARD_CPCI_FULL_HS;
3839                                 }
3840                         }
3841                 }
3842                 /*
3843                  * If board type is a non hotswap board, then we must
3844                  * deny a unconfigure operation. So set this flag.
3845                  * Strictly speaking, there is no reason not to disallow
3846                  * a unconfigure operation on nonhotswap boards. But this
3847                  * is the only way we can prevent a user from accidentally
3848                  * removing the board and damaging it.
3849                  */
3850                 if (board_type == HPC_BOARD_CPCI_NON_HS)
3851                         slotinfop->slot_flags |= PCIHP_SLOT_DEV_NON_HOTPLUG;
3852                 else
3853                         slotinfop->slot_flags &= ~PCIHP_SLOT_DEV_NON_HOTPLUG;
3854         }
3855         return (board_type);
3856 }
3857 
3858 
3859 /*
3860  * Generate the System Event with a possible hint.
3861  */
3862 static void
3863 pcihp_gen_sysevent(char *slot_name, int event_sub_class, int hint,
3864                                 dev_info_t *self, int kmflag)
3865 {
3866 
3867         int err;
3868         char *ev_subclass = NULL;
3869         sysevent_id_t eid;
3870         nvlist_t *ev_attr_list = NULL;
3871         char attach_pnt[MAXPATHLEN];
3872 
3873         /*
3874          * Minor device name (AP) will be bus path
3875          * concatenated with slot name
3876          */
3877 
3878         (void) strcpy(attach_pnt, PCIHP_DEVICES_STR);
3879         (void) ddi_pathname(self, attach_pnt + strlen(PCIHP_DEVICES_STR));
3880         (void) strcat(attach_pnt, ":");
3881         (void) strcat(attach_pnt, slot_name);
3882         err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
3883         if (err != 0) {
3884                 cmn_err(CE_WARN,
3885                     "%s%d: Failed to allocate memory "
3886                     "for event attributes%s", ddi_driver_name(self),
3887                     ddi_get_instance(self), ESC_DR_AP_STATE_CHANGE);
3888                 return;
3889         }
3890 
3891         switch (event_sub_class) {
3892 
3893         /* event sub class: ESC_DR_AP_STATE_CHANGE */
3894         case PCIHP_DR_AP_STATE_CHANGE:
3895 
3896                 ev_subclass = ESC_DR_AP_STATE_CHANGE;
3897 
3898                 switch (hint) {
3899 
3900                 case SE_NO_HINT:        /* fall through */
3901                 case SE_HINT_INSERT:    /* fall through */
3902                 case SE_HINT_REMOVE:
3903 
3904 
3905                         err = nvlist_add_string(ev_attr_list, DR_HINT,
3906                             SE_HINT2STR(hint));
3907 
3908                         if (err != 0) {
3909                                 cmn_err(CE_WARN, "%s%d: Failed to add attr [%s]"
3910                                     " for %s event", ddi_driver_name(self),
3911                                     ddi_get_instance(self),
3912                                     DR_HINT, ESC_DR_AP_STATE_CHANGE);
3913                                 nvlist_free(ev_attr_list);
3914                                 return;
3915                         }
3916                         break;
3917 
3918                 default:
3919                         cmn_err(CE_WARN, "%s%d: Unknown hint on sysevent",
3920                             ddi_driver_name(self), ddi_get_instance(self));
3921                         nvlist_free(ev_attr_list);
3922                         return;
3923                 }
3924 
3925                 break;
3926 
3927         /* event sub class: ESC_DR_REQ */
3928         case PCIHP_DR_REQ:
3929 
3930                 ev_subclass = ESC_DR_REQ;
3931 
3932                 switch (hint) {
3933 
3934                 case SE_INVESTIGATE_RES:        /* fall through */
3935                 case SE_INCOMING_RES:   /* fall through */
3936                 case SE_OUTGOING_RES:   /* fall through */
3937 
3938                         err = nvlist_add_string(ev_attr_list, DR_REQ_TYPE,
3939                             SE_REQ2STR(hint));
3940 
3941                         if (err != 0) {
3942                                 cmn_err(CE_WARN,
3943                                     "%s%d: Failed to add attr [%s] "
3944                                     "for %s event", ddi_driver_name(self),
3945                                     ddi_get_instance(self),
3946                                     DR_REQ_TYPE, ESC_DR_REQ);
3947                                 nvlist_free(ev_attr_list);
3948                                 return;
3949                         }
3950                         break;
3951 
3952                 default:
3953                         cmn_err(CE_WARN, "%s%d:  Unknown hint on sysevent",
3954                             ddi_driver_name(self), ddi_get_instance(self));
3955                         nvlist_free(ev_attr_list);
3956                         return;
3957                 }
3958 
3959                 break;
3960 
3961         default:
3962                 cmn_err(CE_WARN, "%s%d:  Unknown Event subclass",
3963                     ddi_driver_name(self), ddi_get_instance(self));
3964                 nvlist_free(ev_attr_list);
3965                 return;
3966         }
3967 
3968         /*
3969          * Add attachment point as attribute (common attribute)
3970          */
3971 
3972         err = nvlist_add_string(ev_attr_list, DR_AP_ID, attach_pnt);
3973 
3974         if (err != 0) {
3975                 cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event",
3976                     ddi_driver_name(self), ddi_get_instance(self),
3977                     DR_AP_ID, EC_DR);
3978                 nvlist_free(ev_attr_list);
3979                 return;
3980         }
3981 
3982 
3983         /*
3984          * Log this event with sysevent framework.
3985          */
3986 
3987         err = ddi_log_sysevent(self, DDI_VENDOR_SUNW, EC_DR,
3988             ev_subclass, ev_attr_list, &eid,
3989             ((kmflag == KM_SLEEP) ? DDI_SLEEP : DDI_NOSLEEP));
3990         if (err != 0) {
3991                 cmn_err(CE_WARN, "%s%d: Failed to log %s event",
3992                     ddi_driver_name(self), ddi_get_instance(self), EC_DR);
3993         }
3994 
3995         nvlist_free(ev_attr_list);
3996 }
3997 
3998 int
3999 pcihp_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
4000     int flags, char *name, caddr_t valuep, int *lengthp)
4001 {
4002         int pci_dev;
4003 
4004         if (dev == DDI_DEV_T_ANY)
4005                 goto skip;
4006 
4007         if (strcmp(name, "pci-occupant") == 0) {
4008                 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
4009                 pcihp_create_occupant_props(dip, dev, pci_dev);
4010         }
4011         /* other cases... */
4012 skip:
4013         return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
4014 }
4015 
4016 /*
4017  * this function is called only for SPARC platforms, where we may have
4018  * a mix n' match of direct vs indirectly mapped configuration space.
4019  * On x86, this function should always return success since the configuration
4020  * space is always indirect mapped.
4021  */
4022 /*ARGSUSED*/
4023 static int
4024 pcihp_indirect_map(dev_info_t *dip)
4025 {
4026 #if defined(__sparc)
4027         int rc = DDI_FAILURE;
4028 
4029         if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
4030             PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
4031                 rc = DDI_SUCCESS;
4032         else
4033                 if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
4034                     0, PCI_BUS_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
4035                         rc = DDI_SUCCESS;
4036         return (rc);
4037 #else
4038         return (DDI_SUCCESS);
4039 #endif
4040 }