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