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