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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright (c) * Copyright (c) 2001 Tadpole Technology plc 28 * All rights reserved. 29 * From "@(#)pcicfg.c 1.31 99/06/18 SMI" 30 */ 31 32 /* 33 * Cardbus hotplug module 34 */ 35 36 #include <sys/open.h> 37 #include <sys/file.h> 38 #include <sys/stat.h> 39 #include <sys/ddi.h> 40 #include <sys/sunndi.h> 41 42 #include <sys/note.h> 43 44 #include <sys/pci.h> 45 46 #include <sys/hotplug/hpcsvc.h> 47 #include <sys/hotplug/pci/pcicfg.h> 48 #include <sys/pcic_reg.h> 49 50 #include "cardbus.h" 51 #include "cardbus_hp.h" 52 #include "cardbus_cfg.h" 53 54 /* 55 * ************************************************************************ 56 * *** Implementation specific data structures/definitions. *** 57 * ************************************************************************ 58 */ 59 60 #ifndef HPC_MAX_OCCUPANTS 61 #define HPC_MAX_OCCUPANTS 8 62 typedef struct hpc_occupant_info { 63 int i; 64 char *id[HPC_MAX_OCCUPANTS]; 65 } hpc_occupant_info_t; 66 #endif 67 68 #define PCICFG_FLAGS_CONTINUE 0x1 69 70 #define PCICFG_OP_ONLINE 0x1 71 #define PCICFG_OP_OFFLINE 0x0 72 73 #define CBHP_DEVCTL_MINOR 255 74 75 #define AP_MINOR_NUM_TO_CB_INSTANCE(x) ((x) & 0xFF) 76 #define AP_MINOR_NUM(x) (((uint_t)(3) << 8) | ((x) & 0xFF)) 77 #define AP_IS_CB_MINOR(x) (((x)>>8) == (3)) 78 79 extern int cardbus_debug; 80 extern int number_of_cardbus_cards; 81 82 static int cardbus_autocfg_enabled = 1; /* auto config is enabled by default */ 83 84 /* static functions */ 85 static int cardbus_event_handler(caddr_t slot_arg, uint_t event_mask); 86 static int cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, 87 int request, caddr_t arg); 88 static int cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl, 89 hpc_slot_info_t *slot_info, int slot_state); 90 static int cardbus_list_occupants(dev_info_t *dip, void *hdl); 91 static void create_occupant_props(dev_info_t *self, dev_t dev); 92 static void delete_occupant_props(dev_info_t *dip, dev_t dev); 93 static int cardbus_configure_ap(cbus_t *cbp); 94 static int cardbus_unconfigure_ap(cbus_t *cbp); 95 static int cbus_unconfigure(dev_info_t *devi, int prim_bus); 96 void cardbus_dump_pci_config(dev_info_t *dip); 97 void cardbus_dump_pci_node(dev_info_t *dip); 98 99 int 100 cardbus_init_hotplug(cbus_t *cbp) 101 { 102 char tbuf[MAXNAMELEN]; 103 hpc_slot_info_t slot_info; 104 hpc_slot_ops_t *slot_ops; 105 hpc_slot_t slhandle; /* HPS slot handle */ 106 107 /* 108 * register the bus instance with the HPS framework. 109 */ 110 if (hpc_nexus_register_bus(cbp->cb_dip, 111 cardbus_new_slot_state, 0) != 0) { 112 cmn_err(CE_WARN, "%s%d: failed to register the bus with HPS\n", 113 ddi_driver_name(cbp->cb_dip), cbp->cb_instance); 114 return (DDI_FAILURE); 115 } 116 117 (void) sprintf(cbp->ap_id, "slot%d", cbp->cb_instance); 118 (void) ddi_pathname(cbp->cb_dip, tbuf); 119 cbp->nexus_path = kmem_alloc(strlen(tbuf) + 1, KM_SLEEP); 120 (void) strcpy(cbp->nexus_path, tbuf); 121 cardbus_err(cbp->cb_dip, 8, 122 "cardbus_init_hotplug: nexus_path set to %s", cbp->nexus_path); 123 124 slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 125 cbp->slot_ops = slot_ops; 126 127 /* 128 * Fill in the slot information structure that 129 * describes the slot. 130 */ 131 slot_info.version = HPC_SLOT_INFO_VERSION; 132 slot_info.slot_type = HPC_SLOT_TYPE_PCI; 133 slot_info.slot.pci.device_number = 0; 134 slot_info.slot.pci.slot_capabilities = 0; 135 136 (void) strcpy(slot_info.slot.pci.slot_logical_name, cbp->ap_id); 137 138 slot_ops->hpc_version = HPC_SLOT_OPS_VERSION; 139 slot_ops->hpc_op_connect = NULL; 140 slot_ops->hpc_op_disconnect = NULL; 141 slot_ops->hpc_op_insert = NULL; 142 slot_ops->hpc_op_remove = NULL; 143 slot_ops->hpc_op_control = cardbus_pci_control; 144 145 if (hpc_slot_register(cbp->cb_dip, cbp->nexus_path, &slot_info, 146 &slhandle, slot_ops, (caddr_t)cbp, 0) != 0) { 147 /* 148 * If the slot can not be registered, 149 * then the slot_ops need to be freed. 150 */ 151 cmn_err(CE_WARN, 152 "cbp%d Unable to Register Slot %s", cbp->cb_instance, 153 slot_info.slot.pci.slot_logical_name); 154 155 (void) hpc_nexus_unregister_bus(cbp->cb_dip); 156 hpc_free_slot_ops(slot_ops); 157 cbp->slot_ops = NULL; 158 return (DDI_FAILURE); 159 } 160 161 ASSERT(slhandle == cbp->slot_handle); 162 163 cardbus_err(cbp->cb_dip, 8, 164 "cardbus_init_hotplug: slot_handle 0x%p", cbp->slot_handle); 165 return (DDI_SUCCESS); 166 } 167 168 static int 169 cardbus_event_handler(caddr_t slot_arg, uint_t event_mask) 170 { 171 int ap_minor = (int)((uintptr_t)slot_arg); 172 cbus_t *cbp; 173 int cb_instance; 174 int rv = HPC_EVENT_CLAIMED; 175 176 cb_instance = AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor); 177 178 ASSERT(cb_instance >= 0); 179 cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance); 180 mutex_enter(&cbp->cb_mutex); 181 182 switch (event_mask) { 183 184 case HPC_EVENT_SLOT_INSERTION: 185 /* 186 * A card is inserted in the slot. Just report this 187 * event and return. 188 */ 189 cardbus_err(cbp->cb_dip, 7, 190 "cardbus_event_handler(%s%d): card is inserted", 191 ddi_driver_name(cbp->cb_dip), cbp->cb_instance); 192 193 break; 194 195 case HPC_EVENT_SLOT_CONFIGURE: 196 /* 197 * Configure the occupant that is just inserted in the slot. 198 * The receptacle may or may not be in the connected state. If 199 * the receptacle is not connected and the auto configuration 200 * is enabled on this slot then connect the slot. If auto 201 * configuration is enabled then configure the card. 202 */ 203 if (!(cbp->auto_config)) { 204 /* 205 * auto configuration is disabled. 206 */ 207 cardbus_err(cbp->cb_dip, 7, 208 "cardbus_event_handler(%s%d): " 209 "SLOT_CONFIGURE event occured (slot %s)", 210 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 211 cbp->name); 212 213 break; 214 } 215 216 cardbus_err(cbp->cb_dip, 7, 217 "cardbus_event_handler(%s%d): configure event", 218 ddi_driver_name(cbp->cb_dip), cbp->cb_instance); 219 220 if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 221 cmn_err(CE_WARN, "!slot%d already configured\n", 222 cbp->cb_instance); 223 break; 224 } 225 226 /* 227 * Auto configuration is enabled. First, make sure the 228 * receptacle is in the CONNECTED state. 229 */ 230 if ((rv = hpc_nexus_connect(cbp->slot_handle, 231 NULL, 0)) == HPC_SUCCESS) { 232 cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */ 233 } 234 235 if (cardbus_configure_ap(cbp) == HPC_SUCCESS) 236 create_occupant_props(cbp->cb_dip, makedevice( 237 ddi_driver_major((cbp->cb_dip)), ap_minor)); 238 else 239 rv = HPC_ERR_FAILED; 240 241 break; 242 243 case HPC_EVENT_SLOT_UNCONFIGURE: 244 /* 245 * Unconfigure the occupant in this slot. 246 */ 247 if (!(cbp->auto_config)) { 248 /* 249 * auto configuration is disabled. 250 */ 251 cardbus_err(cbp->cb_dip, 7, 252 "cardbus_event_handler(%s%d): " 253 "SLOT_UNCONFIGURE event" 254 " occured - auto-conf disabled (slot %s)", 255 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 256 cbp->name); 257 258 break; 259 } 260 261 cardbus_err(cbp->cb_dip, 7, 262 "cardbus_event_handler(%s%d): SLOT_UNCONFIGURE event" 263 " occured (slot %s)", 264 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 265 cbp->name); 266 267 if (cardbus_unconfigure_ap(cbp) != HPC_SUCCESS) 268 rv = HPC_ERR_FAILED; 269 270 DEVI(cbp->cb_dip)->devi_ops->devo_bus_ops = cbp->orig_bopsp; 271 --number_of_cardbus_cards; 272 break; 273 274 case HPC_EVENT_SLOT_REMOVAL: 275 /* 276 * Card is removed from the slot. The card must have been 277 * unconfigured before this event. 278 */ 279 if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 280 cardbus_err(cbp->cb_dip, 1, 281 "cardbus_event_handler(%s%d): " 282 "card is removed from" 283 " the slot %s before doing unconfigure!!", 284 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 285 cbp->name); 286 287 break; 288 } 289 290 cardbus_err(cbp->cb_dip, 7, 291 "cardbus_event_handler(%s%d): " 292 "card is removed from the slot %s", 293 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 294 cbp->name); 295 296 break; 297 298 case HPC_EVENT_SLOT_POWER_ON: 299 /* 300 * Slot is connected to the bus. i.e the card is powered 301 * on. 302 */ 303 cardbus_err(cbp->cb_dip, 7, 304 "cardbus_event_handler(%s%d): " 305 "card is powered on in the slot %s", 306 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 307 cbp->name); 308 309 cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */ 310 311 break; 312 313 case HPC_EVENT_SLOT_POWER_OFF: 314 /* 315 * Slot is disconnected from the bus. i.e the card is powered 316 * off. 317 */ 318 cardbus_err(cbp->cb_dip, 7, 319 "cardbus_event_handler(%s%d): " 320 "card is powered off in the slot %s", 321 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 322 cbp->name); 323 324 cbp->rstate = AP_RSTATE_DISCONNECTED; /* record rstate */ 325 326 break; 327 328 default: 329 cardbus_err(cbp->cb_dip, 4, 330 "cardbus_event_handler(%s%d): " 331 "unknown event %x for this slot %s", 332 ddi_driver_name(cbp->cb_dip), cbp->cb_instance, 333 event_mask, cbp->name); 334 335 break; 336 } 337 338 mutex_exit(&cbp->cb_mutex); 339 340 return (rv); 341 } 342 343 static int 344 cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 345 caddr_t arg) 346 { 347 cbus_t *cbp; 348 int rval = HPC_SUCCESS; 349 hpc_led_info_t *hpc_led_info; 350 351 _NOTE(ARGUNUSED(slot_hdl)) 352 353 cbp = (cbus_t *)ops_arg; 354 ASSERT(mutex_owned(&cbp->cb_mutex)); 355 356 switch (request) { 357 358 case HPC_CTRL_GET_SLOT_STATE: { 359 hpc_slot_state_t *hpc_slot_state; 360 361 hpc_slot_state = (hpc_slot_state_t *)arg; 362 363 cardbus_err(cbp->cb_dip, 7, 364 "cardbus_pci_control() - " 365 "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=0x%p", 366 (void *) hpc_slot_state); 367 368 if (cbp->card_present) 369 *hpc_slot_state = HPC_SLOT_CONNECTED; 370 else 371 *hpc_slot_state = HPC_SLOT_EMPTY; 372 373 break; 374 } 375 376 case HPC_CTRL_GET_BOARD_TYPE: { 377 hpc_board_type_t *hpc_board_type; 378 379 hpc_board_type = (hpc_board_type_t *)arg; 380 381 cardbus_err(cbp->cb_dip, 7, 382 "cardbus_pci_control() - HPC_CTRL_GET_BOARD_TYPE"); 383 384 /* 385 * The HPC driver does not know what board type 386 * is plugged in. 387 */ 388 *hpc_board_type = HPC_BOARD_PCI_HOTPLUG; 389 390 break; 391 } 392 393 case HPC_CTRL_DEV_CONFIGURED: 394 case HPC_CTRL_DEV_UNCONFIGURED: 395 cardbus_err(cbp->cb_dip, 5, 396 "cardbus_pci_control() - HPC_CTRL_DEV_%sCONFIGURED", 397 request == HPC_CTRL_DEV_UNCONFIGURED ? "UN" : ""); 398 break; 399 400 case HPC_CTRL_GET_LED_STATE: 401 hpc_led_info = (hpc_led_info_t *)arg; 402 cardbus_err(cbp->cb_dip, 5, 403 "cardbus_pci_control() - HPC_CTRL_GET_LED_STATE " 404 "led %d is %d", 405 hpc_led_info->led, cbp->leds[hpc_led_info->led]); 406 407 hpc_led_info->state = cbp->leds[hpc_led_info->led]; 408 break; 409 410 case HPC_CTRL_SET_LED_STATE: 411 hpc_led_info = (hpc_led_info_t *)arg; 412 413 cardbus_err(cbp->cb_dip, 4, 414 "cardbus_pci_control() - HPC_CTRL_SET_LED_STATE " 415 "led %d to %d", 416 hpc_led_info->led, hpc_led_info->state); 417 418 cbp->leds[hpc_led_info->led] = hpc_led_info->state; 419 break; 420 421 case HPC_CTRL_ENABLE_AUTOCFG: 422 cardbus_err(cbp->cb_dip, 5, 423 "cardbus_pci_control() - HPC_CTRL_ENABLE_AUTOCFG"); 424 425 /* 426 * Cardbus ALWAYS does auto config, from the slots point of 427 * view this is turning on the card and making sure it's ok. 428 * This is all done by the bridge driver before we see any 429 * indication. 430 */ 431 break; 432 433 case HPC_CTRL_DISABLE_AUTOCFG: 434 cardbus_err(cbp->cb_dip, 5, 435 "cardbus_pci_control() - HPC_CTRL_DISABLE_AUTOCFG"); 436 break; 437 438 case HPC_CTRL_DISABLE_ENUM: 439 case HPC_CTRL_ENABLE_ENUM: 440 default: 441 rval = HPC_ERR_NOTSUPPORTED; 442 break; 443 } 444 445 return (rval); 446 } 447 448 /* 449 * cardbus_new_slot_state() 450 * 451 * This function is called by the HPS when it finds a hot plug 452 * slot is added or being removed from the hot plug framework. 453 * It returns 0 for success and HPC_ERR_FAILED for errors. 454 */ 455 static int 456 cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl, 457 hpc_slot_info_t *slot_info, int slot_state) 458 { 459 int cb_instance; 460 cbus_t *cbp; 461 int ap_minor; 462 int rv = 0; 463 464 cardbus_err(dip, 8, 465 "cardbus_new_slot_state: slot_handle 0x%p", hdl); 466 467 /* 468 * get the soft state structure for the bus instance. 469 */ 470 cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 471 DDI_PROP_DONTPASS, "cbus-instance", -1); 472 ASSERT(cb_instance >= 0); 473 cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance); 474 475 mutex_enter(&cbp->cb_mutex); 476 477 switch (slot_state) { 478 479 case HPC_SLOT_ONLINE: 480 /* 481 * Make sure the slot is not already ONLINE 482 */ 483 if (cbp->slot_handle != NULL) { 484 cardbus_err(dip, 4, 485 "cardbus_new_slot_state: " 486 "cardbus already ONLINE!!"); 487 rv = HPC_ERR_FAILED; 488 break; 489 } 490 491 /* 492 * Add the hot plug slot to the bus. 493 */ 494 495 /* create the AP minor node */ 496 ap_minor = AP_MINOR_NUM(cb_instance); 497 if (ddi_create_minor_node(dip, slot_info->pci_slot_name, 498 S_IFCHR, ap_minor, 499 DDI_NT_PCI_ATTACHMENT_POINT, 500 0) == DDI_FAILURE) { 501 cardbus_err(dip, 4, 502 "cardbus_new_slot_state: " 503 "ddi_create_minor_node failed"); 504 rv = HPC_ERR_FAILED; 505 break; 506 } 507 508 /* save the slot handle */ 509 cbp->slot_handle = hdl; 510 511 /* setup event handler for all hardware events on the slot */ 512 if (hpc_install_event_handler(hdl, -1, cardbus_event_handler, 513 (caddr_t)((long)ap_minor)) != 0) { 514 cardbus_err(dip, 4, 515 "cardbus_new_slot_state: " 516 "install event handler failed"); 517 rv = HPC_ERR_FAILED; 518 break; 519 } 520 cbp->event_mask = (uint32_t)0xFFFFFFFF; 521 create_occupant_props(dip, 522 makedevice(ddi_name_to_major(ddi_get_name(dip)), 523 ap_minor)); 524 525 /* set default auto configuration enabled flag for this slot */ 526 cbp->auto_config = cardbus_autocfg_enabled; 527 528 /* copy the slot information */ 529 cbp->name = (char *)kmem_alloc(strlen(slot_info->pci_slot_name) 530 + 1, KM_SLEEP); 531 (void) strcpy(cbp->name, slot_info->pci_slot_name); 532 cardbus_err(cbp->cb_dip, 10, 533 "cardbus_new_slot_state: cbp->name set to %s", cbp->name); 534 535 cardbus_err(dip, 4, 536 "Cardbus slot \"%s\" ONLINE\n", slot_info->pci_slot_name); 537 538 cbp->ostate = AP_OSTATE_UNCONFIGURED; 539 cbp->rstate = AP_RSTATE_EMPTY; 540 541 break; 542 543 case HPC_SLOT_OFFLINE: 544 /* 545 * A hot plug slot is being removed from the bus. 546 * Make sure there is no occupant configured on the 547 * slot before removing the AP minor node. 548 */ 549 if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 550 cmn_err(CE_WARN, 551 "cardbus: Card is still in configured state"); 552 rv = HPC_ERR_FAILED; 553 break; 554 } 555 556 /* 557 * If the AP device is in open state then return 558 * error. 559 */ 560 if (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED) { 561 rv = HPC_ERR_FAILED; 562 break; 563 } 564 565 /* remove the minor node */ 566 ddi_remove_minor_node(dip, cbp->name); 567 /* free up the memory for the name string */ 568 kmem_free(cbp->name, strlen(cbp->name) + 1); 569 570 /* update the slot info data */ 571 cbp->name = NULL; 572 cbp->slot_handle = NULL; 573 574 cardbus_err(dip, 6, 575 "cardbus_new_slot_state: Cardbus slot OFFLINE"); 576 break; 577 578 default: 579 cmn_err(CE_WARN, 580 "cardbus_new_slot_state: unknown slot_state %d\n", 581 slot_state); 582 rv = HPC_ERR_FAILED; 583 } 584 585 mutex_exit(&cbp->cb_mutex); 586 587 return (rv); 588 } 589 590 static int 591 cardbus_list_occupants(dev_info_t *dip, void *hdl) 592 { 593 hpc_occupant_info_t *occupant = (hpc_occupant_info_t *)hdl; 594 char pn[MAXPATHLEN]; 595 596 /* 597 * Ignore the attachment point and pcs. 598 */ 599 if (strcmp(ddi_binding_name(dip), "pcs") == 0) { 600 return (DDI_WALK_CONTINUE); 601 } 602 603 (void) ddi_pathname(dip, pn); 604 605 occupant->id[occupant->i] = kmem_alloc(strlen(pn) + 1, KM_SLEEP); 606 (void) strcpy(occupant->id[occupant->i], pn); 607 608 occupant->i++; 609 610 /* 611 * continue the walk to the next sibling to look for a match 612 * or to find other nodes if this card is a multi-function card. 613 */ 614 return (DDI_WALK_PRUNECHILD); 615 } 616 617 static void 618 create_occupant_props(dev_info_t *self, dev_t dev) 619 { 620 hpc_occupant_info_t occupant; 621 int i; 622 int circular; 623 624 occupant.i = 0; 625 626 ndi_devi_enter(self, &circular); 627 ddi_walk_devs(ddi_get_child(self), cardbus_list_occupants, 628 (void *)&occupant); 629 ndi_devi_exit(self, circular); 630 631 if (occupant.i == 0) { 632 char *c[] = { "" }; 633 cardbus_err(self, 1, "create_occupant_props: no occupant\n"); 634 (void) ddi_prop_update_string_array(dev, self, "pci-occupant", 635 c, 1); 636 } else { 637 cardbus_err(self, 1, 638 "create_occupant_props: %d occupant\n", occupant.i); 639 (void) ddi_prop_update_string_array(dev, self, "pci-occupant", 640 occupant.id, occupant.i); 641 } 642 643 for (i = 0; i < occupant.i; i++) { 644 kmem_free(occupant.id[i], strlen(occupant.id[i]) + 1); 645 } 646 } 647 648 static void 649 delete_occupant_props(dev_info_t *dip, dev_t dev) 650 { 651 if (ddi_prop_remove(dev, dip, "pci-occupant") 652 != DDI_PROP_SUCCESS) 653 return; /* add error handling */ 654 655 } 656 657 /* 658 * ************************************** 659 * CONFIGURE the occupant in the slot. 660 * ************************************** 661 */ 662 static int 663 cardbus_configure_ap(cbus_t *cbp) 664 { 665 dev_info_t *self = cbp->cb_dip; 666 int rv = HPC_SUCCESS; 667 hpc_slot_state_t rstate; 668 struct cardbus_config_ctrl ctrl; 669 int circular_count; 670 671 /* 672 * check for valid request: 673 * 1. It is a hotplug slot. 674 * 2. The receptacle is in the CONNECTED state. 675 */ 676 if (cbp->slot_handle == NULL || cbp->disabled) { 677 return (ENXIO); 678 } 679 680 /* 681 * If the occupant is already in (partially) configured 682 * state then call the ndi_devi_online() on the device 683 * subtree(s) for this attachment point. 684 */ 685 686 if (cbp->ostate == AP_OSTATE_CONFIGURED) { 687 ctrl.flags = PCICFG_FLAGS_CONTINUE; 688 ctrl.busno = cardbus_primary_busno(self); 689 ctrl.rv = NDI_SUCCESS; 690 ctrl.dip = NULL; 691 ctrl.op = PCICFG_OP_ONLINE; 692 693 ndi_devi_enter(self, &circular_count); 694 ddi_walk_devs(ddi_get_child(self), 695 cbus_configure, (void *)&ctrl); 696 ndi_devi_exit(self, circular_count); 697 698 if (cardbus_debug) { 699 cardbus_dump_pci_config(self); 700 cardbus_dump_pci_node(self); 701 } 702 703 if (ctrl.rv != NDI_SUCCESS) { 704 /* 705 * one or more of the devices are not 706 * onlined. 707 */ 708 cmn_err(CE_WARN, "cardbus(%s%d): failed to attach " 709 "one or more drivers for the card in the slot %s", 710 ddi_driver_name(self), cbp->cb_instance, 711 cbp->name); 712 } 713 714 /* tell HPC driver that the occupant is configured */ 715 (void) hpc_nexus_control(cbp->slot_handle, 716 HPC_CTRL_DEV_CONFIGURED, NULL); 717 return (rv); 718 } 719 720 /* 721 * Occupant is in the UNCONFIGURED state. 722 */ 723 724 /* Check if the receptacle is in the CONNECTED state. */ 725 if (hpc_nexus_control(cbp->slot_handle, 726 HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) { 727 return (ENXIO); 728 } 729 730 if (rstate != HPC_SLOT_CONNECTED) { 731 /* error. either the slot is empty or connect failed */ 732 return (ENXIO); 733 } 734 735 cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */ 736 737 /* 738 * Call the configurator to configure the card. 739 */ 740 if (cardbus_configure(cbp) != PCICFG_SUCCESS) { 741 return (EIO); 742 } 743 744 /* record the occupant state as CONFIGURED */ 745 cbp->ostate = AP_OSTATE_CONFIGURED; 746 cbp->condition = AP_COND_OK; 747 748 /* now, online all the devices in the AP */ 749 ctrl.flags = PCICFG_FLAGS_CONTINUE; 750 ctrl.busno = cardbus_primary_busno(self); 751 ctrl.rv = NDI_SUCCESS; 752 ctrl.dip = NULL; 753 ctrl.op = PCICFG_OP_ONLINE; 754 755 ndi_devi_enter(self, &circular_count); 756 ddi_walk_devs(ddi_get_child(self), cbus_configure, (void *)&ctrl); 757 ndi_devi_exit(self, circular_count); 758 759 if (cardbus_debug) { 760 cardbus_dump_pci_config(self); 761 cardbus_dump_pci_node(self); 762 } 763 if (ctrl.rv != NDI_SUCCESS) { 764 /* 765 * one or more of the devices are not 766 * ONLINE'd. 767 */ 768 cmn_err(CE_WARN, "cbhp (%s%d): failed to attach one or" 769 " more drivers for the card in the slot %s", 770 ddi_driver_name(cbp->cb_dip), 771 cbp->cb_instance, cbp->name); 772 /* rv = EFAULT; */ 773 } 774 775 /* tell HPC driver that the occupant is configured */ 776 (void) hpc_nexus_control(cbp->slot_handle, 777 HPC_CTRL_DEV_CONFIGURED, NULL); 778 779 return (rv); 780 } 781 782 /* 783 * ************************************** 784 * UNCONFIGURE the occupant in the slot. 785 * ************************************** 786 */ 787 static int 788 cardbus_unconfigure_ap(cbus_t *cbp) 789 { 790 dev_info_t *self = cbp->cb_dip; 791 int rv = HPC_SUCCESS, nrv; 792 793 /* 794 * check for valid request: 795 * 1. It is a hotplug slot. 796 * 2. The occupant is in the CONFIGURED state. 797 */ 798 799 if (cbp->slot_handle == NULL || cbp->disabled) { 800 return (ENXIO); 801 } 802 803 /* 804 * If the occupant is in the CONFIGURED state then 805 * call the configurator to unconfigure the slot. 806 */ 807 if (cbp->ostate == AP_OSTATE_CONFIGURED) { 808 /* 809 * Detach all the drivers for the devices in the 810 * slot. 811 */ 812 nrv = cardbus_unconfigure_node(self, 813 cardbus_primary_busno(self), 814 B_TRUE); 815 816 if (nrv != NDI_SUCCESS) { 817 /* 818 * Failed to detach one or more drivers. 819 * Restore the status for the drivers 820 * which are offlined during this step. 821 */ 822 cmn_err(CE_WARN, 823 "cbhp (%s%d): Failed to offline all devices" 824 " (slot %s)", ddi_driver_name(cbp->cb_dip), 825 cbp->cb_instance, cbp->name); 826 rv = EBUSY; 827 } else { 828 829 if (cardbus_unconfigure(cbp) == PCICFG_SUCCESS) { 830 /* 831 * Now that resources are freed, 832 * clear EXT and Turn LED ON. 833 */ 834 cbp->ostate = AP_OSTATE_UNCONFIGURED; 835 cbp->condition = AP_COND_UNKNOWN; 836 /* 837 * send the notification of state change 838 * to the HPC driver. 839 */ 840 (void) hpc_nexus_control(cbp->slot_handle, 841 HPC_CTRL_DEV_UNCONFIGURED, NULL); 842 } else { 843 rv = EIO; 844 } 845 } 846 } 847 848 return (rv); 849 } 850 851 int 852 cbus_configure(dev_info_t *dip, void *hdl) 853 { 854 pci_regspec_t *pci_rp; 855 int length, rc; 856 struct cardbus_config_ctrl *ctrl = (struct cardbus_config_ctrl *)hdl; 857 uint8_t bus, device, function; 858 859 /* 860 * Ignore the attachment point and pcs. 861 */ 862 if (strcmp(ddi_binding_name(dip), "hp_attachment") == 0 || 863 strcmp(ddi_binding_name(dip), "pcs") == 0) { 864 cardbus_err(dip, 8, "cbus_configure: Ignoring\n"); 865 return (DDI_WALK_CONTINUE); 866 } 867 868 cardbus_err(dip, 6, "cbus_configure\n"); 869 870 ASSERT(ctrl->op == PCICFG_OP_ONLINE); 871 872 /* 873 * Get the PCI device number information from the devinfo 874 * node. Since the node may not have the address field 875 * setup (this is done in the DDI_INITCHILD of the parent) 876 * we look up the 'reg' property to decode that information. 877 */ 878 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 879 DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 880 (uint_t *)&length) != DDI_PROP_SUCCESS) { 881 /* Porbably not a real device, like PCS for example */ 882 if (ddi_get_child(dip) == NULL) 883 return (DDI_WALK_PRUNECHILD); 884 885 cardbus_err(dip, 1, "cubs_configure: Don't configure device\n"); 886 ctrl->rv = DDI_FAILURE; 887 ctrl->dip = dip; 888 return (DDI_WALK_TERMINATE); 889 } 890 891 if (pci_rp->pci_phys_hi == 0) 892 return (DDI_WALK_CONTINUE); 893 894 /* get the pci device id information */ 895 bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 896 device = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 897 function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 898 899 /* 900 * free the memory allocated by ddi_prop_lookup_int_array 901 */ 902 ddi_prop_free(pci_rp); 903 904 if (bus <= ctrl->busno) 905 return (DDI_WALK_CONTINUE); 906 907 cardbus_err(dip, 8, 908 "cbus_configure on-line device at: " 909 "[0x%x][0x%x][0x%x]\n", bus, device, function); 910 911 rc = ndi_devi_online(dip, NDI_ONLINE_ATTACH|NDI_CONFIG); 912 913 cardbus_err(dip, 7, 914 "cbus_configure %s\n", 915 rc == NDI_SUCCESS ? "Success": "Failure"); 916 917 if (rc != NDI_SUCCESS) 918 return (DDI_WALK_PRUNECHILD); 919 920 return (DDI_WALK_CONTINUE); 921 } 922 923 int 924 cardbus_unconfigure_node(dev_info_t *dip, int prim_bus, boolean_t top_bridge) 925 { 926 dev_info_t *child, *next; 927 928 cardbus_err(dip, 6, "cardbus_unconfigure_node\n"); 929 930 /* 931 * Ignore pcs. 932 */ 933 if (strcmp(ddi_binding_name(dip), "pcs") == 0) { 934 cardbus_err(dip, 8, "cardbus_unconfigure_node: Ignoring\n"); 935 return (NDI_SUCCESS); 936 } 937 938 /* 939 * bottom up off-line 940 */ 941 for (child = ddi_get_child(dip); child; child = next) { 942 int rc; 943 next = ddi_get_next_sibling(child); 944 rc = cardbus_unconfigure_node(child, prim_bus, B_FALSE); 945 if (rc != NDI_SUCCESS) 946 return (rc); 947 } 948 949 /* 950 * Don't unconfigure the bridge itself. 951 */ 952 if (top_bridge) 953 return (NDI_SUCCESS); 954 955 if (cbus_unconfigure(dip, prim_bus) != NDI_SUCCESS) { 956 cardbus_err(dip, 1, 957 "cardbus_unconfigure_node: cardbus_unconfigure failed\n"); 958 return (NDI_FAILURE); 959 } 960 return (NDI_SUCCESS); 961 } 962 963 /* 964 * This will turn resources allocated by cbus_configure() 965 * and remove the device tree from the attachment point 966 * and below. The routine assumes the devices have their 967 * drivers detached. 968 */ 969 static int 970 cbus_unconfigure(dev_info_t *devi, int prim_bus) 971 { 972 pci_regspec_t *pci_rp; 973 uint_t bus, device, func, length; 974 int ndi_flags = NDI_UNCONFIG; 975 976 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi, 977 DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, 978 &length) != DDI_PROP_SUCCESS) { 979 /* 980 * This cannot be one of our devices. If it's something like a 981 * SCSI device then the attempt to offline the HBA 982 * (which probably is one of our devices) 983 * will also do bottom up offlining. That 984 * will fail if this device is busy. So always 985 * return success here 986 * so that the walk will continue. 987 */ 988 return (NDI_SUCCESS); 989 } 990 991 if (pci_rp->pci_phys_hi == 0) 992 return (NDI_FAILURE); 993 994 bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); 995 996 if (bus <= prim_bus) 997 return (NDI_SUCCESS); 998 999 device = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 1000 func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 1001 ddi_prop_free(pci_rp); 1002 1003 cardbus_err(devi, 8, 1004 "cbus_unconfigure: " 1005 "offline bus [0x%x] device [0x%x] function [%x]\n", 1006 bus, device, func); 1007 if (ndi_devi_offline(devi, ndi_flags) != NDI_SUCCESS) { 1008 cardbus_err(devi, 1, 1009 "Device [0x%x] function [%x] is busy\n", device, func); 1010 return (NDI_FAILURE); 1011 } 1012 1013 cardbus_err(devi, 9, 1014 "Tearing down device [0x%x] function [0x%x]\n", device, func); 1015 1016 if (cardbus_teardown_device(devi) != PCICFG_SUCCESS) { 1017 cardbus_err(devi, 1, 1018 "Failed to tear down " 1019 "device [0x%x] function [0x%x]\n", device, func); 1020 return (NDI_FAILURE); 1021 } 1022 1023 return (NDI_SUCCESS); 1024 } 1025 1026 boolean_t 1027 cardbus_is_cb_minor(dev_t dev) 1028 { 1029 return (AP_IS_CB_MINOR(getminor(dev)) ? B_TRUE : B_FALSE); 1030 } 1031 1032 int 1033 cardbus_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1034 { 1035 cbus_t *cbp; 1036 int minor; 1037 1038 _NOTE(ARGUNUSED(credp)) 1039 1040 minor = getminor(*devp); 1041 1042 /* 1043 * Make sure the open is for the right file type. 1044 */ 1045 if (otyp != OTYP_CHR) 1046 return (EINVAL); 1047 1048 /* 1049 * Get the soft state structure for the 'devctl' device. 1050 */ 1051 cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, 1052 AP_MINOR_NUM_TO_CB_INSTANCE(minor)); 1053 if (cbp == NULL) 1054 return (ENXIO); 1055 1056 mutex_enter(&cbp->cb_mutex); 1057 1058 /* 1059 * Handle the open by tracking the device state. 1060 * 1061 * Note: Needs review w.r.t exclusive access to AP or the bus. 1062 * Currently in the pci plug-in we don't use EXCL open at all 1063 * so the code below implements EXCL access on the bus. 1064 */ 1065 1066 /* enforce exclusive access to the bus */ 1067 if ((cbp->soft_state == PCIHP_SOFT_STATE_OPEN_EXCL) || 1068 ((flags & FEXCL) && 1069 (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED))) { 1070 mutex_exit(&cbp->cb_mutex); 1071 return (EBUSY); 1072 } 1073 1074 if (flags & FEXCL) 1075 cbp->soft_state = PCIHP_SOFT_STATE_OPEN_EXCL; 1076 else 1077 cbp->soft_state = PCIHP_SOFT_STATE_OPEN; 1078 1079 mutex_exit(&cbp->cb_mutex); 1080 return (0); 1081 } 1082 1083 /*ARGSUSED*/ 1084 int 1085 cardbus_close(dev_t dev, int flags, int otyp, cred_t *credp) 1086 { 1087 cbus_t *cbp; 1088 int minor; 1089 1090 _NOTE(ARGUNUSED(credp)) 1091 1092 minor = getminor(dev); 1093 1094 if (otyp != OTYP_CHR) 1095 return (EINVAL); 1096 1097 cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, 1098 AP_MINOR_NUM_TO_CB_INSTANCE(minor)); 1099 if (cbp == NULL) 1100 return (ENXIO); 1101 1102 mutex_enter(&cbp->cb_mutex); 1103 cbp->soft_state = PCIHP_SOFT_STATE_CLOSED; 1104 mutex_exit(&cbp->cb_mutex); 1105 return (0); 1106 } 1107 1108 /* 1109 * cardbus_ioctl: devctl hotplug controls 1110 */ 1111 /*ARGSUSED*/ 1112 int 1113 cardbus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1114 int *rvalp) 1115 { 1116 cbus_t *cbp; 1117 dev_info_t *self; 1118 dev_info_t *child_dip = NULL; 1119 struct devctl_iocdata *dcp; 1120 uint_t bus_state; 1121 int rv = 0; 1122 int nrv = 0; 1123 int ap_minor; 1124 hpc_slot_state_t rstate; 1125 devctl_ap_state_t ap_state; 1126 struct hpc_control_data hpc_ctrldata; 1127 struct hpc_led_info led_info; 1128 1129 _NOTE(ARGUNUSED(credp)) 1130 1131 ap_minor = getminor(dev); 1132 cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, 1133 AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor)); 1134 if (cbp == NULL) 1135 return (ENXIO); 1136 1137 self = cbp->cb_dip; 1138 /* 1139 * read devctl ioctl data 1140 */ 1141 if ((cmd != DEVCTL_AP_CONTROL) && ndi_dc_allochdl((void *)arg, 1142 &dcp) != NDI_SUCCESS) 1143 return (EFAULT); 1144 1145 #ifdef CARDBUS_DEBUG 1146 { 1147 char *cmd_name; 1148 1149 switch (cmd) { 1150 case DEVCTL_DEVICE_GETSTATE: cmd_name = "DEVCTL_DEVICE_GETSTATE"; break; 1151 case DEVCTL_DEVICE_ONLINE: cmd_name = "DEVCTL_DEVICE_ONLINE"; break; 1152 case DEVCTL_DEVICE_OFFLINE: cmd_name = "DEVCTL_DEVICE_OFFLINE"; break; 1153 case DEVCTL_DEVICE_RESET: cmd_name = "DEVCTL_DEVICE_RESET"; break; 1154 case DEVCTL_BUS_QUIESCE: cmd_name = "DEVCTL_BUS_QUIESCE"; break; 1155 case DEVCTL_BUS_UNQUIESCE: cmd_name = "DEVCTL_BUS_UNQUIESCE"; break; 1156 case DEVCTL_BUS_RESET: cmd_name = "DEVCTL_BUS_RESET"; break; 1157 case DEVCTL_BUS_RESETALL: cmd_name = "DEVCTL_BUS_RESETALL"; break; 1158 case DEVCTL_BUS_GETSTATE: cmd_name = "DEVCTL_BUS_GETSTATE"; break; 1159 case DEVCTL_AP_CONNECT: cmd_name = "DEVCTL_AP_CONNECT"; break; 1160 case DEVCTL_AP_DISCONNECT: cmd_name = "DEVCTL_AP_DISCONNECT"; break; 1161 case DEVCTL_AP_INSERT: cmd_name = "DEVCTL_AP_INSERT"; break; 1162 case DEVCTL_AP_REMOVE: cmd_name = "DEVCTL_AP_REMOVE"; break; 1163 case DEVCTL_AP_CONFIGURE: cmd_name = "DEVCTL_AP_CONFIGURE"; break; 1164 case DEVCTL_AP_UNCONFIGURE: cmd_name = "DEVCTL_AP_UNCONFIGURE"; break; 1165 case DEVCTL_AP_GETSTATE: cmd_name = "DEVCTL_AP_GETSTATE"; break; 1166 case DEVCTL_AP_CONTROL: cmd_name = "DEVCTL_AP_CONTROL"; break; 1167 default: cmd_name = "Unknown"; break; 1168 } 1169 cardbus_err(cbp->cb_dip, 7, 1170 "cardbus_ioctl: cmd = 0x%x, \"%s\"", cmd, cmd_name); 1171 } 1172 #endif 1173 1174 switch (cmd) { 1175 case DEVCTL_DEVICE_GETSTATE: 1176 case DEVCTL_DEVICE_ONLINE: 1177 case DEVCTL_DEVICE_OFFLINE: 1178 case DEVCTL_BUS_GETSTATE: 1179 rv = ndi_devctl_ioctl(self, cmd, arg, mode, 0); 1180 ndi_dc_freehdl(dcp); 1181 return (rv); 1182 default: 1183 break; 1184 } 1185 1186 switch (cmd) { 1187 case DEVCTL_DEVICE_RESET: 1188 rv = ENOTSUP; 1189 break; 1190 1191 case DEVCTL_BUS_QUIESCE: 1192 if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1193 if (bus_state == BUS_QUIESCED) 1194 break; 1195 (void) ndi_set_bus_state(self, BUS_QUIESCED); 1196 break; 1197 1198 case DEVCTL_BUS_UNQUIESCE: 1199 if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1200 if (bus_state == BUS_ACTIVE) 1201 break; 1202 (void) ndi_set_bus_state(self, BUS_ACTIVE); 1203 break; 1204 1205 case DEVCTL_BUS_RESET: 1206 rv = ENOTSUP; 1207 break; 1208 1209 case DEVCTL_BUS_RESETALL: 1210 rv = ENOTSUP; 1211 break; 1212 1213 case DEVCTL_AP_CONNECT: 1214 case DEVCTL_AP_DISCONNECT: 1215 /* 1216 * CONNECT(DISCONNECT) the hot plug slot to(from) the bus. 1217 */ 1218 case DEVCTL_AP_INSERT: 1219 case DEVCTL_AP_REMOVE: 1220 /* 1221 * Prepare the slot for INSERT/REMOVE operation. 1222 */ 1223 1224 /* 1225 * check for valid request: 1226 * 1. It is a hotplug slot. 1227 * 2. The slot has no occupant that is in 1228 * the 'configured' state. 1229 * 1230 * The lower 8 bits of the minor number is the PCI 1231 * device number for the slot. 1232 */ 1233 if ((cbp->slot_handle == NULL) || cbp->disabled) { 1234 rv = ENXIO; 1235 break; 1236 } 1237 1238 /* the slot occupant must be in the UNCONFIGURED state */ 1239 if (cbp->ostate != AP_OSTATE_UNCONFIGURED) { 1240 rv = EINVAL; 1241 break; 1242 } 1243 1244 /* 1245 * Call the HPC driver to perform the operation on the slot. 1246 */ 1247 mutex_enter(&cbp->cb_mutex); 1248 switch (cmd) { 1249 case DEVCTL_AP_INSERT: 1250 rv = hpc_nexus_insert(cbp->slot_handle, NULL, 0); 1251 break; 1252 case DEVCTL_AP_REMOVE: 1253 rv = hpc_nexus_remove(cbp->slot_handle, NULL, 0); 1254 break; 1255 case DEVCTL_AP_CONNECT: 1256 if ((rv = hpc_nexus_connect(cbp->slot_handle, 1257 NULL, 0)) == 0) 1258 cbp->rstate = AP_RSTATE_CONNECTED; 1259 break; 1260 case DEVCTL_AP_DISCONNECT: 1261 if ((rv = hpc_nexus_disconnect(cbp->slot_handle, 1262 NULL, 0)) == 0) 1263 cbp->rstate = AP_RSTATE_DISCONNECTED; 1264 break; 1265 } 1266 mutex_exit(&cbp->cb_mutex); 1267 1268 switch (rv) { 1269 case HPC_ERR_INVALID: 1270 rv = ENXIO; 1271 break; 1272 case HPC_ERR_NOTSUPPORTED: 1273 rv = ENOTSUP; 1274 break; 1275 case HPC_ERR_FAILED: 1276 rv = EIO; 1277 break; 1278 } 1279 1280 break; 1281 1282 case DEVCTL_AP_CONFIGURE: 1283 /* 1284 * ************************************** 1285 * CONFIGURE the occupant in the slot. 1286 * ************************************** 1287 */ 1288 1289 mutex_enter(&cbp->cb_mutex); 1290 if ((nrv = cardbus_configure_ap(cbp)) == HPC_SUCCESS) { 1291 create_occupant_props(cbp->cb_dip, dev); 1292 } else 1293 rv = nrv; 1294 mutex_exit(&cbp->cb_mutex); 1295 break; 1296 1297 case DEVCTL_AP_UNCONFIGURE: 1298 /* 1299 * ************************************** 1300 * UNCONFIGURE the occupant in the slot. 1301 * ************************************** 1302 */ 1303 1304 mutex_enter(&cbp->cb_mutex); 1305 if ((nrv = cardbus_unconfigure_ap(cbp)) == HPC_SUCCESS) { 1306 delete_occupant_props(cbp->cb_dip, dev); 1307 } else 1308 rv = nrv; 1309 mutex_exit(&cbp->cb_mutex); 1310 break; 1311 1312 case DEVCTL_AP_GETSTATE: 1313 { 1314 int mutex_held; 1315 1316 /* 1317 * return the state of Attachment Point. 1318 * 1319 * If the occupant is in UNCONFIGURED state then 1320 * we should get the receptacle state from the 1321 * HPC driver because the receptacle state 1322 * maintained in the nexus may not be accurate. 1323 */ 1324 1325 /* 1326 * check for valid request: 1327 * 1. It is a hotplug slot. 1328 */ 1329 if (cbp->slot_handle == NULL) { 1330 rv = ENXIO; 1331 break; 1332 } 1333 1334 /* try to acquire the slot mutex */ 1335 mutex_held = mutex_tryenter(&cbp->cb_mutex); 1336 1337 if (cbp->ostate == AP_OSTATE_UNCONFIGURED) { 1338 if (hpc_nexus_control(cbp->slot_handle, 1339 HPC_CTRL_GET_SLOT_STATE, 1340 (caddr_t)&rstate) != 0) { 1341 rv = ENXIO; 1342 if (mutex_held) 1343 mutex_exit(&cbp->cb_mutex); 1344 break; 1345 } 1346 cbp->rstate = (ap_rstate_t)rstate; 1347 } 1348 1349 ap_state.ap_rstate = cbp->rstate; 1350 ap_state.ap_ostate = cbp->ostate; 1351 ap_state.ap_condition = cbp->condition; 1352 ap_state.ap_last_change = 0; 1353 ap_state.ap_error_code = 0; 1354 if (mutex_held) 1355 ap_state.ap_in_transition = 0; /* AP is not busy */ 1356 else 1357 ap_state.ap_in_transition = 1; /* AP is busy */ 1358 1359 if (mutex_held) 1360 mutex_exit(&cbp->cb_mutex); 1361 1362 /* copy the return-AP-state information to the user space */ 1363 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) 1364 rv = ENXIO; 1365 1366 break; 1367 1368 } 1369 1370 case DEVCTL_AP_CONTROL: 1371 /* 1372 * HPC control functions: 1373 * HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT 1374 * Changes the state of the slot and preserves 1375 * the state across the reboot. 1376 * HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG 1377 * Enables or disables the auto configuration 1378 * of hot plugged occupant if the hardware 1379 * supports notification of the hot plug 1380 * events. 1381 * HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE 1382 * Controls the state of an LED. 1383 * HPC_CTRL_GET_SLOT_INFO 1384 * Get slot information data structure 1385 * (hpc_slot_info_t). 1386 * HPC_CTRL_GET_BOARD_TYPE 1387 * Get board type information (hpc_board_type_t). 1388 * HPC_CTRL_GET_CARD_INFO 1389 * Get card information (hpc_card_info_t). 1390 * 1391 * These control functions are used by the cfgadm plug-in 1392 * to implement "-x" and "-v" options. 1393 */ 1394 1395 /* copy user ioctl data first */ 1396 #ifdef _MULTI_DATAMODEL 1397 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1398 struct hpc_control32_data hpc_ctrldata32; 1399 1400 if (copyin((void *)arg, (void *)&hpc_ctrldata32, 1401 sizeof (struct hpc_control32_data)) != 0) { 1402 rv = EFAULT; 1403 break; 1404 } 1405 hpc_ctrldata.cmd = hpc_ctrldata32.cmd; 1406 hpc_ctrldata.data = 1407 (void *)(intptr_t)hpc_ctrldata32.data; 1408 } 1409 #else 1410 if (copyin((void *)arg, (void *)&hpc_ctrldata, 1411 sizeof (struct hpc_control_data)) != 0) { 1412 rv = EFAULT; 1413 break; 1414 } 1415 #endif 1416 1417 #ifdef CARDBUS_DEBUG 1418 { 1419 char *hpc_name; 1420 switch (hpc_ctrldata.cmd) { 1421 case HPC_CTRL_GET_LED_STATE: 1422 hpc_name = "HPC_CTRL_GET_LED_STATE"; 1423 break; 1424 case HPC_CTRL_SET_LED_STATE: 1425 hpc_name = "HPC_CTRL_SET_LED_STATE"; 1426 break; 1427 case HPC_CTRL_ENABLE_SLOT: 1428 hpc_name = "HPC_CTRL_ENABLE_SLOT"; 1429 break; 1430 case HPC_CTRL_DISABLE_SLOT: 1431 hpc_name = "HPC_CTRL_DISABLE_SLOT"; 1432 break; 1433 case HPC_CTRL_ENABLE_AUTOCFG: 1434 hpc_name = "HPC_CTRL_ENABLE_AUTOCFG"; 1435 break; 1436 case HPC_CTRL_DISABLE_AUTOCFG: 1437 hpc_name = "HPC_CTRL_DISABLE_AUTOCFG"; 1438 break; 1439 case HPC_CTRL_GET_BOARD_TYPE: 1440 hpc_name = "HPC_CTRL_GET_BOARD_TYPE"; 1441 break; 1442 case HPC_CTRL_GET_SLOT_INFO: 1443 hpc_name = "HPC_CTRL_GET_SLOT_INFO"; 1444 break; 1445 case HPC_CTRL_GET_CARD_INFO: 1446 hpc_name = "HPC_CTRL_GET_CARD_INFO"; 1447 break; 1448 default: hpc_name = "Unknown"; break; 1449 } 1450 cardbus_err(cbp->cb_dip, 7, 1451 "cardbus_ioctl: HP Control cmd 0x%x - \"%s\"", 1452 hpc_ctrldata.cmd, hpc_name); 1453 } 1454 #endif 1455 /* 1456 * check for valid request: 1457 * 1. It is a hotplug slot. 1458 */ 1459 if (cbp->slot_handle == NULL) { 1460 rv = ENXIO; 1461 break; 1462 } 1463 1464 mutex_enter(&cbp->cb_mutex); 1465 switch (hpc_ctrldata.cmd) { 1466 case HPC_CTRL_GET_LED_STATE: 1467 /* copy the led info from the user space */ 1468 if (copyin(hpc_ctrldata.data, (void *)&led_info, 1469 sizeof (hpc_led_info_t)) != 0) { 1470 rv = ENXIO; 1471 break; 1472 } 1473 1474 /* get the state of LED information */ 1475 if (hpc_nexus_control(cbp->slot_handle, 1476 HPC_CTRL_GET_LED_STATE, 1477 (caddr_t)&led_info) != 0) { 1478 rv = ENXIO; 1479 break; 1480 } 1481 1482 /* copy the led info to the user space */ 1483 if (copyout((void *)&led_info, hpc_ctrldata.data, 1484 sizeof (hpc_led_info_t)) != 0) { 1485 rv = ENXIO; 1486 break; 1487 } 1488 break; 1489 1490 case HPC_CTRL_SET_LED_STATE: 1491 /* copy the led info from the user space */ 1492 if (copyin(hpc_ctrldata.data, (void *)&led_info, 1493 sizeof (hpc_led_info_t)) != 0) { 1494 rv = ENXIO; 1495 break; 1496 } 1497 1498 /* set the state of an LED */ 1499 if (hpc_nexus_control(cbp->slot_handle, 1500 HPC_CTRL_SET_LED_STATE, 1501 (caddr_t)&led_info) != 0) { 1502 rv = ENXIO; 1503 break; 1504 } 1505 1506 break; 1507 1508 case HPC_CTRL_ENABLE_SLOT: 1509 /* 1510 * Enable the slot for hotplug operations. 1511 */ 1512 cbp->disabled = B_FALSE; 1513 1514 /* tell the HPC driver also */ 1515 (void) hpc_nexus_control(cbp->slot_handle, 1516 HPC_CTRL_ENABLE_SLOT, NULL); 1517 1518 break; 1519 1520 case HPC_CTRL_DISABLE_SLOT: 1521 /* 1522 * Disable the slot for hotplug operations. 1523 */ 1524 cbp->disabled = B_TRUE; 1525 1526 /* tell the HPC driver also */ 1527 (void) hpc_nexus_control(cbp->slot_handle, 1528 HPC_CTRL_DISABLE_SLOT, NULL); 1529 1530 break; 1531 1532 case HPC_CTRL_ENABLE_AUTOCFG: 1533 /* 1534 * Enable auto configuration on this slot. 1535 */ 1536 cbp->auto_config = B_TRUE; 1537 1538 /* tell the HPC driver also */ 1539 (void) hpc_nexus_control(cbp->slot_handle, 1540 HPC_CTRL_ENABLE_AUTOCFG, NULL); 1541 break; 1542 1543 case HPC_CTRL_DISABLE_AUTOCFG: 1544 /* 1545 * Disable auto configuration on this slot. 1546 */ 1547 cbp->auto_config = B_FALSE; 1548 1549 /* tell the HPC driver also */ 1550 (void) hpc_nexus_control(cbp->slot_handle, 1551 HPC_CTRL_DISABLE_AUTOCFG, NULL); 1552 1553 break; 1554 1555 case HPC_CTRL_GET_BOARD_TYPE: 1556 { 1557 hpc_board_type_t board_type; 1558 1559 /* 1560 * Get board type data structure, hpc_board_type_t. 1561 */ 1562 if (hpc_nexus_control(cbp->slot_handle, 1563 HPC_CTRL_GET_BOARD_TYPE, 1564 (caddr_t)&board_type) != 0) { 1565 rv = ENXIO; 1566 break; 1567 } 1568 1569 /* copy the board type info to the user space */ 1570 if (copyout((void *)&board_type, hpc_ctrldata.data, 1571 sizeof (hpc_board_type_t)) != 0) { 1572 rv = ENXIO; 1573 break; 1574 } 1575 1576 break; 1577 } 1578 1579 case HPC_CTRL_GET_SLOT_INFO: 1580 { 1581 hpc_slot_info_t slot_info; 1582 1583 /* 1584 * Get slot information structure, hpc_slot_info_t. 1585 */ 1586 slot_info.version = HPC_SLOT_INFO_VERSION; 1587 slot_info.slot_type = 0; 1588 slot_info.pci_slot_capabilities = 0; 1589 slot_info.pci_dev_num = 1590 (uint16_t)AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor); 1591 (void) strcpy(slot_info.pci_slot_name, cbp->name); 1592 1593 /* copy the slot info structure to the user space */ 1594 if (copyout((void *)&slot_info, hpc_ctrldata.data, 1595 sizeof (hpc_slot_info_t)) != 0) { 1596 rv = ENXIO; 1597 break; 1598 } 1599 1600 break; 1601 } 1602 1603 case HPC_CTRL_GET_CARD_INFO: 1604 { 1605 hpc_card_info_t card_info; 1606 ddi_acc_handle_t handle; 1607 1608 /* 1609 * Get card information structure, hpc_card_info_t. 1610 */ 1611 1612 if (cbp->card_present == B_FALSE) { 1613 rv = ENXIO; 1614 break; 1615 } 1616 /* verify that the card is configured */ 1617 if (cbp->ostate != AP_OSTATE_CONFIGURED) { 1618 /* either the card is not present or */ 1619 /* it is not configured. */ 1620 rv = ENXIO; 1621 break; 1622 } 1623 1624 /* get the information from the PCI config header */ 1625 /* for the function 0. */ 1626 for (child_dip = ddi_get_child(cbp->cb_dip); child_dip; 1627 child_dip = ddi_get_next_sibling(child_dip)) 1628 if (strcmp("pcs", ddi_get_name(child_dip))) 1629 break; 1630 1631 if (!child_dip) { 1632 rv = ENXIO; 1633 break; 1634 } 1635 1636 if (pci_config_setup(child_dip, &handle) 1637 != DDI_SUCCESS) { 1638 rv = EIO; 1639 break; 1640 } 1641 card_info.prog_class = pci_config_get8(handle, 1642 PCI_CONF_PROGCLASS); 1643 card_info.base_class = pci_config_get8(handle, 1644 PCI_CONF_BASCLASS); 1645 card_info.sub_class = pci_config_get8(handle, 1646 PCI_CONF_SUBCLASS); 1647 card_info.header_type = pci_config_get8(handle, 1648 PCI_CONF_HEADER); 1649 pci_config_teardown(&handle); 1650 1651 /* copy the card info structure to the user space */ 1652 if (copyout((void *)&card_info, hpc_ctrldata.data, 1653 sizeof (hpc_card_info_t)) != 0) { 1654 rv = ENXIO; 1655 break; 1656 } 1657 1658 break; 1659 } 1660 1661 default: 1662 rv = EINVAL; 1663 break; 1664 } 1665 1666 mutex_exit(&cbp->cb_mutex); 1667 break; 1668 1669 default: 1670 rv = ENOTTY; 1671 } 1672 1673 if (cmd != DEVCTL_AP_CONTROL) 1674 ndi_dc_freehdl(dcp); 1675 1676 cardbus_err(cbp->cb_dip, 7, 1677 "cardbus_ioctl: rv = 0x%x", rv); 1678 1679 return (rv); 1680 } 1681 1682 struct cardbus_pci_desc { 1683 char *name; 1684 ushort_t offset; 1685 int (*cfg_get_func)(); 1686 char *fmt; 1687 }; 1688 1689 #define CFG_GET(f) ((int(*)())(uintptr_t)f) 1690 1691 static struct cardbus_pci_desc generic_pci_cfg[] = { 1692 { "VendorId =", 0, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1693 { "DeviceId =", 2, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1694 { "Command =", 4, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1695 { "Status =", 6, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1696 { "Latency =", 0xd, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1697 { "BASE0 =", 0x10, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1698 { "BASE1 =", 0x14, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1699 { "BASE2 =", 0x18, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1700 { "BASE3 =", 0x1c, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1701 { "BASE4 =", 0x20, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1702 { "CIS Pointer =", 0x28, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1703 { "ILINE =", 0x3c, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1704 { "IPIN =", 0x3d, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1705 { NULL, 0, NULL, NULL } 1706 }; 1707 1708 static struct cardbus_pci_desc cardbus_pci_cfg[] = { 1709 { "VendorId =", 0, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1710 { "DeviceId =", 2, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1711 { "Command =", 4, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1712 { "Status =", 6, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1713 { "CacheLineSz =", 0xc, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1714 { "Latency =", 0xd, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1715 { "MemBase Addr=", 0x10, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1716 { "Pri Bus =", 0x18, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1717 { "Sec Bus =", 0x19, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1718 { "Sub Bus =", 0x1a, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1719 { "CBus Latency=", 0x1b, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1720 { "Mem0 Base =", 0x1c, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1721 { "Mem0 Limit =", 0x20, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1722 { "Mem1 Base =", 0x24, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1723 { "Mem1 Limit =", 0x28, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1724 { "I/O0 Base =", 0x2c, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1725 { "I/O0 Limit =", 0x30, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1726 { "I/O1 Base =", 0x34, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1727 { "I/O1 Limit =", 0x38, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1728 { "ILINE =", 0x3c, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1729 { "IPIN =", 0x3d, CFG_GET(pci_config_get8), "%s 0x%02x" }, 1730 { "Bridge Ctrl =", 0x3e, CFG_GET(pci_config_get16), "%s 0x%04x" }, 1731 { "Legacy Addr =", 0x44, CFG_GET(pci_config_get32), "%s 0x%08x" }, 1732 { NULL, 0, NULL, NULL } 1733 }; 1734 1735 static void 1736 cardbus_dump(struct cardbus_pci_desc *spcfg, ddi_acc_handle_t handle) 1737 { 1738 int i; 1739 for (i = 0; spcfg[i].name; i++) { 1740 1741 cmn_err(CE_NOTE, spcfg[i].fmt, spcfg[i].name, 1742 spcfg[i].cfg_get_func(handle, spcfg[i].offset)); 1743 } 1744 1745 } 1746 1747 void 1748 cardbus_dump_pci_node(dev_info_t *dip) 1749 { 1750 dev_info_t *next; 1751 struct cardbus_pci_desc *spcfg; 1752 ddi_acc_handle_t config_handle; 1753 uint32_t VendorId; 1754 1755 cmn_err(CE_NOTE, "\nPCI leaf node of dip 0x%p:\n", (void *)dip); 1756 for (next = ddi_get_child(dip); next; 1757 next = ddi_get_next_sibling(next)) { 1758 1759 VendorId = ddi_getprop(DDI_DEV_T_ANY, next, 1760 DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 1761 "vendor-id", -1); 1762 if (VendorId == -1) { 1763 /* not a pci device */ 1764 continue; 1765 } 1766 1767 if (pci_config_setup(next, &config_handle) != DDI_SUCCESS) { 1768 cmn_err(CE_WARN, "!pcic child: non pci device\n"); 1769 continue; 1770 } 1771 1772 spcfg = generic_pci_cfg; 1773 cardbus_dump(spcfg, config_handle); 1774 pci_config_teardown(&config_handle); 1775 1776 } 1777 1778 } 1779 1780 void 1781 cardbus_dump_pci_config(dev_info_t *dip) 1782 { 1783 struct cardbus_pci_desc *spcfg; 1784 ddi_acc_handle_t config_handle; 1785 1786 if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) { 1787 cmn_err(CE_WARN, 1788 "!pci_config_setup() failed on 0x%p", (void *)dip); 1789 return; 1790 } 1791 1792 spcfg = cardbus_pci_cfg; 1793 cardbus_dump(spcfg, config_handle); 1794 1795 pci_config_teardown(&config_handle); 1796 } 1797 1798 void 1799 cardbus_dump_socket(dev_info_t *dip) 1800 { 1801 ddi_acc_handle_t iohandle; 1802 caddr_t ioaddr; 1803 ddi_device_acc_attr_t attr; 1804 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1805 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1806 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1807 if (ddi_regs_map_setup(dip, 1, 1808 (caddr_t *)&ioaddr, 1809 0, 1810 4096, 1811 &attr, &iohandle) != DDI_SUCCESS) { 1812 cmn_err(CE_WARN, "Failed to map address for 0x%p", (void *)dip); 1813 return; 1814 } 1815 1816 cmn_err(CE_NOTE, "////////////////////////////////////////"); 1817 cmn_err(CE_NOTE, "SOCKET_EVENT = [0x%x]", 1818 ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT))); 1819 cmn_err(CE_NOTE, "SOCKET_MASK = [0x%x]", 1820 ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK))); 1821 cmn_err(CE_NOTE, "SOCKET_STATE = [0x%x]", 1822 ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_PRESENT_STATE))); 1823 cmn_err(CE_NOTE, "////////////////////////////////////////"); 1824 1825 ddi_regs_map_free(&iohandle); 1826 1827 } 1828