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