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