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