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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * 30 * Serengeti CompactPCI Hot Swap Controller Driver. 31 * 32 */ 33 34 #include <sys/types.h> 35 #include <sys/cmn_err.h> 36 #include <sys/kmem.h> 37 #include <sys/errno.h> 38 #include <sys/cpuvar.h> 39 #include <sys/open.h> 40 #include <sys/stat.h> 41 #include <sys/conf.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/modctl.h> 45 #include <sys/ksynch.h> 46 #include <sys/pci.h> 47 #include <sys/serengeti.h> 48 #include <sys/sghsc.h> 49 #include <sys/promif.h> 50 51 /* 52 * Debug flags 53 */ 54 55 int sghsc_configure_ack = 0; 56 int cpci_enable = 1; 57 #ifdef DEBUG 58 #define SGHSC_DEBUG 59 #endif 60 61 #ifdef SGHSC_DEBUG 62 int sghsc_debug = 0; 63 #define DEBUGF(level, args) \ 64 { if (sghsc_debug >= (level)) cmn_err args; } 65 #define DEBUGON sghsc_debug = 3 66 #define DEBUGOFF sghsc_debug = 0 67 #else 68 #define DEBUGF(level, args) /* nothing */ 69 #define DEBUGON 70 #define DEBUGOFF 71 #endif 72 73 /* 74 * Global data 75 */ 76 static void *sghsc_state; /* soft state */ 77 static sghsc_rb_head_t sghsc_rb_header; /* ring buffer header */ 78 79 /* 80 * Definitions for events thread (outside interrupt context), mutex and 81 * condition variable. 82 */ 83 static kthread_t *sghsc_event_thread; 84 static kmutex_t sghsc_event_thread_mutex; 85 static kcondvar_t sghsc_event_thread_cv; 86 static boolean_t sghsc_event_thread_exit = B_FALSE; 87 88 static struct cb_ops sghsc_cb_ops = { 89 nodev, /* open */ 90 nodev, /* close */ 91 nodev, /* strategy */ 92 nodev, /* print */ 93 nodev, /* dump */ 94 nodev, /* read */ 95 nodev, /* write */ 96 nodev, /* ioctl */ 97 nodev, /* devmap */ 98 nodev, /* mmap */ 99 nodev, /* segmap */ 100 nochpoll, /* poll */ 101 ddi_prop_op, /* prop_op */ 102 0, /* streamtab */ 103 D_NEW | D_MP, /* Driver compatibility flag */ 104 CB_REV, /* rev */ 105 nodev, /* int (*cb_aread)() */ 106 nodev /* int (*cb_awrite)() */ 107 }; 108 109 /* 110 * Function prototype for dev_ops 111 */ 112 113 static int sghsc_attach(dev_info_t *, ddi_attach_cmd_t); 114 static int sghsc_detach(dev_info_t *, ddi_detach_cmd_t); 115 116 static struct dev_ops sghsc_dev_ops = { 117 DEVO_REV, /* devo_rev, */ 118 0, /* refcnt */ 119 nulldev, /* get_dev_info */ 120 nulldev, /* identify */ 121 nulldev, /* probe */ 122 sghsc_attach, /* attach */ 123 sghsc_detach, /* detach */ 124 nodev, /* reset */ 125 &sghsc_cb_ops, /* driver operations */ 126 (struct bus_ops *)0, /* no bus operations */ 127 NULL, /* power */ 128 ddi_quiesce_not_needed, /* quiesce */ 129 }; 130 131 static struct modldrv modldrv = { 132 &mod_driverops, 133 "Serengeti CompactPCI HSC", 134 &sghsc_dev_ops, 135 }; 136 137 static struct modlinkage modlinkage = { 138 MODREV_1, 139 &modldrv, 140 NULL 141 }; 142 143 /* 144 * Function prototype for HP support 145 */ 146 static int sghsc_connect(caddr_t, hpc_slot_t slot, void *, uint_t); 147 static int sghsc_disconnect(caddr_t, hpc_slot_t, void *, uint_t); 148 static int sghsc_control(caddr_t, hpc_slot_t, int, caddr_t); 149 150 /* 151 * Function prototypes for internal functions 152 */ 153 static int sghsc_register_slots(sghsc_t *, int); 154 static int sghsc_get_slotnum(sghsc_t *, hpc_slot_t); 155 static int sghsc_scctl(int, int, int, int, int *); 156 static void sghsc_freemem(sghsc_t *); 157 static hpc_slot_t sghsc_find_sloth(int, int, int); 158 static sghsc_t *sghsc_find_softstate(int, int, int); 159 static int sghsc_led_state(sghsc_t *, hpc_slot_t, int, hpc_led_info_t *); 160 static void sghsc_rb_setup(sghsc_rb_head_t *); 161 static void sghsc_rb_teardown(sghsc_rb_head_t *); 162 static int sghsc_rb_get(sghsc_rb_head_t *, sghsc_event_t *); 163 static int sghsc_rb_put(sghsc_rb_head_t *, sghsc_event_t *); 164 165 /* 166 * Patchable timeout value 167 */ 168 int sghsc_mbx_timeout = SGHSC_MBX_TIMEOUT; 169 170 /* 171 * Data for self-identification. This will help enumerate all soft states. 172 */ 173 static int sghsc_maxinst; 174 175 /* 176 * Six slot boat and four slot boats are different in topology (slot to 177 * bus assignment) and here we should have 2 separate maps (the first 3 178 * slots have the same topology). The map is in the "delta" form. Logical 179 * slots correspond to indexes in the map. 180 */ 181 static sdesc_t four_slot_wib_bd[] = { 182 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */ 183 1, 0, 2, 0, /* logical/physical slot 1 - paroli2 */ 184 1, 0, 0, 0, /* logical/physical slot 2 - paroli0 */ 185 0, 7, 1, HPC_SLOT_TYPE_CPCI /* logical/physical slot 3 - Schizo0/B */ 186 }; 187 static sdesc_t four_slot_bd[] = { 188 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */ 189 1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */ 190 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */ 191 1, 7, 1, HPC_SLOT_TYPE_CPCI /* logical/physical slot 3 - Schizo1/B */ 192 }; 193 static sdesc_t six_slot_wib_bd[] = { 194 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */ 195 1, 0, 2, 0, /* logical/physical slot 1 - paroli2 */ 196 1, 0, 0, 0, /* logical/physical slot 2 - paroli0 */ 197 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */ 198 0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo0/B */ 199 0, 7, 3, HPC_SLOT_TYPE_CPCI /* logical/physical slot 5 - Schizo0/B */ 200 }; 201 static sdesc_t six_slot_bd[] = { 202 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */ 203 1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */ 204 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */ 205 0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */ 206 1, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo1/B */ 207 1, 7, 2, HPC_SLOT_TYPE_CPCI /* logical/physical slot 5 - Schizo1/B */ 208 }; 209 210 /* 211 * DR event handlers 212 * We want to register the event handlers once for all instances. In the 213 * other hand we have register them after the sghsc has been attached. 214 * event_initialize gives us the logic of only registering the events only 215 * once. The event thread will do all the work when called from interrupts. 216 */ 217 int sghsc_event_init = 0; 218 static uint_t sghsc_event_handler(char *); 219 static void sghsc_event_thread_code(void); 220 221 /* 222 * DR event msg and payload 223 */ 224 static sbbc_msg_t event_msg; 225 static sghsc_event_t payload; 226 227 /* 228 * Event lock and state 229 */ 230 static kmutex_t sghsc_event_lock; 231 int sghsc_event_state; 232 233 int 234 _init(void) 235 { 236 int error; 237 238 sghsc_maxinst = 0; 239 240 if ((error = ddi_soft_state_init(&sghsc_state, 241 sizeof (sghsc_t), 1)) != 0) 242 return (error); 243 244 if ((error = mod_install(&modlinkage)) != 0) { 245 ddi_soft_state_fini(&sghsc_state); 246 return (error); 247 } 248 249 sghsc_rb_header.buf = NULL; 250 251 mutex_init(&sghsc_event_thread_mutex, NULL, MUTEX_DRIVER, NULL); 252 cv_init(&sghsc_event_thread_cv, NULL, CV_DRIVER, NULL); 253 254 return (error); 255 } 256 257 int 258 _fini(void) 259 { 260 int error; 261 262 if ((error = mod_remove(&modlinkage)) != 0) 263 return (error); 264 /* 265 * Unregister the event handler 266 */ 267 sbbc_mbox_unreg_intr(MBOX_EVENT_CPCI_ENUM, sghsc_event_handler); 268 mutex_destroy(&sghsc_event_lock); 269 270 /* 271 * Kill the event thread if it is running. 272 */ 273 if (sghsc_event_thread != NULL) { 274 mutex_enter(&sghsc_event_thread_mutex); 275 sghsc_event_thread_exit = B_TRUE; 276 /* 277 * Goes to the thread at once. 278 */ 279 cv_signal(&sghsc_event_thread_cv); 280 /* 281 * Waiting for the response from the thread. 282 */ 283 cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex); 284 mutex_exit(&sghsc_event_thread_mutex); 285 sghsc_event_thread = NULL; 286 } 287 mutex_destroy(&sghsc_event_thread_mutex); 288 cv_destroy(&sghsc_event_thread_cv); 289 290 /* 291 * tear down shared, global ring buffer now that it is safe to 292 * do so because sghsc_event_handler has been unregistered and 293 * sghsc_event_thread_code has exited 294 */ 295 sghsc_rb_teardown(&sghsc_rb_header); 296 297 sghsc_maxinst = 0; 298 ddi_soft_state_fini(&sghsc_state); 299 300 return (0); 301 } 302 303 int 304 _info(struct modinfo *modinfop) 305 { 306 return (mod_info(&modlinkage, modinfop)); 307 } 308 309 /* 310 * sghsc_attach() 311 */ 312 /* ARGSUSED */ 313 static int 314 sghsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 315 { 316 sghsc_t *sghsc; 317 uint_t instance; 318 uint_t portid; 319 int rc; 320 int board_type = 0; 321 322 instance = ddi_get_instance(dip); 323 324 switch (cmd) { 325 case DDI_RESUME: 326 return (DDI_SUCCESS); 327 328 case DDI_ATTACH: 329 break; 330 default: 331 cmn_err(CE_WARN, "sghsc%d: unsupported cmd %d", 332 instance, cmd); 333 return (DDI_FAILURE); 334 } 335 336 DEBUGF(1, (CE_NOTE, "attach sghsc driver. ")); 337 338 /* Fetch Safari Extended Agent ID of this device. */ 339 portid = (uint_t)ddi_getprop(DDI_DEV_T_ANY, dip, 340 DDI_PROP_DONTPASS, "portid", -1); 341 342 if (!SG_PORTID_IS_IO_TYPE(portid)) { 343 cmn_err(CE_WARN, "sghsc%d: property %s out of bounds %d\n", 344 instance, "portid", portid); 345 return (DDI_FAILURE); 346 } 347 348 if (ddi_soft_state_zalloc(sghsc_state, instance) != DDI_SUCCESS) 349 return (DDI_FAILURE); 350 351 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance); 352 353 sghsc->sghsc_dip = dip; 354 sghsc->sghsc_instance = instance; 355 sghsc->sghsc_board = SG_PORTID_TO_BOARD_NUM(portid); 356 sghsc->sghsc_node_id = SG_PORTID_TO_NODEID(portid); 357 sghsc->sghsc_portid = portid; 358 359 ddi_set_driver_private(dip, sghsc); 360 361 mutex_init(SGHSC_MUTEX(sghsc), NULL, MUTEX_DRIVER, NULL); 362 363 rc = sghsc_scctl(SGHSC_GET_NUM_SLOTS, sghsc->sghsc_node_id, 364 sghsc->sghsc_board, 0, (int *)&sghsc->sghsc_num_slots); 365 366 if (rc) { 367 cmn_err(CE_WARN, "sghsc%d: unable to size node %d / board %d", 368 instance, sghsc->sghsc_node_id, sghsc->sghsc_board); 369 goto cleanup_stage2; 370 } 371 372 DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d has %d slots", 373 instance, sghsc->sghsc_node_id, sghsc->sghsc_board, 374 sghsc->sghsc_num_slots)); 375 376 switch (sghsc->sghsc_num_slots) { 377 case 4: 378 case 6: 379 rc = 0; 380 break; 381 default: 382 rc = -1; 383 break; 384 } 385 386 if (rc) { 387 cmn_err(CE_WARN, "sghsc%d: wrong num of slots %d for node %d" 388 " / board %d", instance, sghsc->sghsc_num_slots, 389 sghsc->sghsc_node_id, sghsc->sghsc_board); 390 goto cleanup_stage2; 391 } 392 393 rc = sghsc_scctl(SGHSC_GET_CPCI_BOARD_TYPE, sghsc->sghsc_node_id, 394 sghsc->sghsc_board, 0, &board_type); 395 396 DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d is type %d", 397 instance, sghsc->sghsc_node_id, sghsc->sghsc_board, board_type)); 398 399 sghsc->sghsc_slot_table = (sghsc_slot_t *)kmem_zalloc((size_t) 400 (sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)), KM_SLEEP); 401 402 403 if (sghsc_register_slots(sghsc, board_type) != DDI_SUCCESS) { 404 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_register_slots" 405 " failed for node %d / board %d", 406 instance, sghsc->sghsc_node_id, sghsc->sghsc_board)); 407 goto cleanup; 408 } 409 410 if (sghsc_connect((caddr_t)sghsc, 0, 0, SGHSC_ALL_SLOTS_ENABLE) 411 != HPC_SUCCESS) { 412 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_connect failed for" 413 " node %d / board %d", instance, sghsc->sghsc_node_id, 414 sghsc->sghsc_board)); 415 goto cleanup; 416 } 417 418 419 if (sghsc_event_init == 0) { 420 421 /* 422 * allocate shared, global ring buffer before registering 423 * sghsc_event_handler and before starting 424 * sghsc_event_thread_code 425 */ 426 sghsc_rb_setup(&sghsc_rb_header); 427 428 /* 429 * Regiter cpci DR event handler 430 * 431 */ 432 mutex_init(&sghsc_event_lock, NULL, MUTEX_DRIVER, NULL); 433 event_msg.msg_buf = (caddr_t)&payload; 434 event_msg.msg_len = sizeof (payload); 435 rc = sbbc_mbox_reg_intr(MBOX_EVENT_CPCI_ENUM, 436 sghsc_event_handler, &event_msg, 437 (uint_t *)&sghsc_event_state, &sghsc_event_lock); 438 439 if (rc != 0) 440 cmn_err(CE_WARN, "sghsc%d: failed to register events" 441 " for node %d", instance, sghsc->sghsc_node_id); 442 443 sghsc_event_init = 1; 444 445 /* 446 * Create the event thread if it is not already created. 447 */ 448 if (sghsc_event_thread == NULL) { 449 DEBUGF(1, (CE_NOTE, "sghsc: creating event thread" 450 "for node %d", sghsc->sghsc_node_id)); 451 sghsc_event_thread = thread_create(NULL, 0, 452 sghsc_event_thread_code, NULL, 0, &p0, 453 TS_RUN, minclsyspri); 454 } 455 } 456 457 ddi_report_dev(dip); 458 459 /* 460 * Grossly bump up the instance counter. We may have holes inside. 461 */ 462 sghsc_maxinst++; 463 sghsc->sghsc_valid = 1; 464 465 return (DDI_SUCCESS); 466 467 cleanup: 468 /* 469 * Free up allocated resources and return error 470 * sghsc_register_slots => unregister all slots 471 */ 472 sghsc_freemem(sghsc); 473 474 cleanup_stage2: 475 DEBUGF(1, (CE_NOTE, "sghsc%d: attach failed for node %d", 476 instance, sghsc->sghsc_node_id)); 477 mutex_destroy(SGHSC_MUTEX(sghsc)); 478 ddi_set_driver_private(dip, NULL); 479 ddi_soft_state_free(sghsc_state, instance); 480 return (DDI_FAILURE); 481 } 482 483 /* 484 * detach(9E) 485 */ 486 /* ARGSUSED */ 487 static int 488 sghsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 489 { 490 sghsc_t *sghsc; 491 int instance; 492 int i; 493 494 instance = ddi_get_instance(dip); 495 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance); 496 497 if (sghsc == NULL) 498 return (DDI_FAILURE); 499 500 switch (cmd) { 501 case DDI_DETACH: 502 /* 503 * We don't allow to detach in case the pci nexus 504 * didn't run pcihp_uninit(). The buses should be 505 * unregistered by now, otherwise slot info will be 506 * corrupted on the next 'cfgadm'. 507 */ 508 for (i = 0; i < sghsc->sghsc_num_slots; i++) { 509 if (sghsc->sghsc_slot_table[i].handle && 510 hpc_bus_registered( 511 sghsc->sghsc_slot_table[i].handle)) { 512 cmn_err(CE_WARN, 513 "sghsc: must detach buses first"); 514 return (DDI_FAILURE); 515 } 516 } 517 518 if (mutex_tryenter(&sghsc_event_thread_mutex) == 0) 519 return (EBUSY); 520 521 sghsc->sghsc_valid = 0; 522 sghsc_freemem(sghsc); 523 mutex_destroy(SGHSC_MUTEX(sghsc)); 524 ddi_set_driver_private(dip, NULL); 525 ddi_soft_state_free(sghsc_state, instance); 526 527 /* 528 * Grossly decrement the counter. We may have holes inside. 529 */ 530 if (instance == (sghsc_maxinst - 1)) 531 sghsc_maxinst--; 532 mutex_exit(&sghsc_event_thread_mutex); 533 return (DDI_SUCCESS); 534 535 case DDI_SUSPEND: 536 return (DDI_SUCCESS); 537 538 default: 539 return (DDI_FAILURE); 540 } 541 } 542 543 544 /* 545 * Set up and register slot 0 to num_slots with hotplug 546 * framework 547 * Assume SGHSC_MUTEX is held 548 * 549 * Return val: DDI_SUCCESS 550 * DDI_FAILURE 551 */ 552 static int 553 sghsc_register_slots(sghsc_t *sghsc, int board_type) 554 { 555 int i; 556 dev_info_t *dip = sghsc->sghsc_dip; 557 hpc_slot_ops_t *slot_ops = NULL; 558 sdesc_t *slot2bus; 559 560 561 DEBUGF(1, (CE_NOTE, "sghsc%d: slot table has %d entries for " 562 "node %d / board %d", sghsc->sghsc_instance, sghsc->sghsc_num_slots, 563 sghsc->sghsc_node_id, sghsc->sghsc_board)); 564 565 if ((cpci_enable == 0) || (sg_prom_cpci_dr_check() != 0)) 566 return (DDI_SUCCESS); 567 568 if (sghsc->sghsc_slot_table == NULL) 569 return (DDI_FAILURE); 570 571 switch (board_type) { 572 /* 573 * If the GET_CPCI_BOARD_TYPE request failed, board type 574 * will be NO_BOARD_TYPE. In that case, assume it is an 575 * io boat and make board type determination based on the 576 * number of slots. 577 */ 578 case NO_BOARD_TYPE: 579 case CPCI_BOARD: 580 case SP_CPCI_BOARD: 581 switch (sghsc->sghsc_num_slots) { 582 case 4: 583 slot2bus = four_slot_bd; 584 break; 585 case 6: 586 slot2bus = six_slot_bd; 587 break; 588 default: 589 cmn_err(CE_WARN, "sghsc%d: unknown size %d for" 590 " node %d / board %d", 591 sghsc->sghsc_instance, 592 sghsc->sghsc_num_slots, 593 sghsc->sghsc_node_id, sghsc->sghsc_board); 594 break; 595 } 596 break; 597 case WCI_CPCI_BOARD: 598 slot2bus = four_slot_wib_bd; 599 break; 600 case WCI_SP_CPCI_BOARD: 601 slot2bus = six_slot_wib_bd; 602 break; 603 default: 604 cmn_err(CE_WARN, "sghsc%d: unknown type %d for" 605 " node %d / board %d", sghsc->sghsc_instance, 606 board_type, sghsc->sghsc_node_id, 607 sghsc->sghsc_board); 608 return (DDI_FAILURE); 609 } 610 611 /* 612 * constructing the slot table array and register the 613 * slot with the HPS 614 * we don't depend on the .conf file 615 */ 616 for (i = 0; i < sghsc->sghsc_num_slots; i++) { 617 char *nexuspath; 618 hpc_slot_info_t *slot_info; 619 uint32_t base_id; 620 621 /* 622 * Some kind of black list may be needed 623 */ 624 625 /* 626 * Need to talk to SC and get slot info and set slot state: 627 * 1. slot status 628 * 2. slot capabilities 629 * 3. LED status 630 * 4. get bus num 631 */ 632 633 /* 634 * fill up nexuspath, extended id is used instead of the 635 * local one, the node id is encoded in the path twice. 636 */ 637 base_id = sghsc->sghsc_portid & SGHSC_SAFARI_ID_EVEN; 638 nexuspath = sghsc->sghsc_slot_table[i].nexus_path; 639 640 sprintf(nexuspath, SGHSC_PATH, sghsc->sghsc_node_id, 641 (base_id + slot2bus[i].agent_delta), slot2bus[i].off); 642 sghsc->sghsc_slot_table[i].pci_device_num = 643 slot2bus[i].pcidev; 644 645 /* 646 * fill up slot_info 647 */ 648 slot_info = &sghsc->sghsc_slot_table[i].slot_info; 649 650 slot_info->version = HPC_SLOT_INFO_VERSION; 651 slot_info->slot_type = slot2bus[i].slot_type; 652 /* capabilities need to be discovered via SC */ 653 slot_info->pci_slot_capabilities = HPC_SLOT_64BITS; 654 slot_info->pci_dev_num = slot2bus[i].pcidev; 655 656 sprintf(slot_info->pci_slot_name, 657 "sg%dslot%d", sghsc->sghsc_board, i); 658 DEBUGF(1, (CE_NOTE, "pci_slot_name is %s at pci_dev_num %d" 659 " on node %d / board %d", slot_info->pci_slot_name, 660 slot_info->pci_dev_num, sghsc->sghsc_node_id, 661 sghsc->sghsc_board)); 662 663 /* 664 * allocate and fill up slot_ops 665 */ 666 slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 667 sghsc->sghsc_slot_table[i].slot_ops = slot_ops; 668 669 /* assign slot ops for HPS */ 670 slot_ops->hpc_version = HPC_SLOT_OPS_VERSION; 671 slot_ops->hpc_op_connect = sghsc_connect; 672 slot_ops->hpc_op_disconnect = sghsc_disconnect; 673 slot_ops->hpc_op_insert = nodev; 674 slot_ops->hpc_op_remove = nodev; 675 slot_ops->hpc_op_control = sghsc_control; 676 677 /* 678 * HA (Full Hot Swap) is the default mode of operation 679 * but the type of the board is set conservstively as 680 * sghsc has no way of knowing it. The HP Framwork will 681 * overwrite the value set at boot time. 682 */ 683 sghsc->sghsc_slot_table[i].flags = SGHSC_SLOT_AUTO_CFG_EN; 684 sghsc->sghsc_slot_table[i].board_type = HPC_BOARD_UNKNOWN; 685 686 /* Only register CPCI slots */ 687 if (slot_info->slot_type != HPC_SLOT_TYPE_CPCI) { 688 DEBUGF(1, (CE_NOTE, "sghsc_register_slots: " 689 "slot %d is non-cpci", i)); 690 continue; 691 } 692 693 /* 694 * register slots 695 */ 696 if ((hpc_slot_register(dip, nexuspath, slot_info, 697 &sghsc->sghsc_slot_table[i].handle, 698 slot_ops, (caddr_t)sghsc, 0)) != 0) { 699 700 /* 701 * return failure and let attach() 702 * do the cleanup 703 */ 704 cmn_err(CE_WARN, "sghsc%d: Slot <%s> failed during HPS" 705 " registration process for node %d / board %d", 706 sghsc->sghsc_instance, slot_info->pci_slot_name, 707 sghsc->sghsc_node_id, sghsc->sghsc_board); 708 return (DDI_FAILURE); 709 } 710 711 } 712 DEBUGF(1, (CE_NOTE, "sghsc registered successfully for" 713 " node %d / board %d", sghsc->sghsc_node_id, sghsc->sghsc_board)); 714 return (DDI_SUCCESS); 715 } 716 717 /* 718 * Connecting a slot or all slots 719 * State Diagram: 720 * states 721 * hw bits EMPTY DISCONNECT CONNECT 722 * slot_enable NO NO YES 723 * card_present NO YES YES 724 * slot_switch N/A NO/YES YES 725 * 726 * Return val: HPC_SUCCESS if the slot(s) are enabled 727 * HPC_ERR_FAILED if the slot can't be enabled 728 */ 729 /* ARGSUSED */ 730 static int 731 sghsc_connect(caddr_t op_arg, hpc_slot_t sloth, void *data, 732 uint_t flag) 733 { 734 int i = 0; 735 sghsc_t *sghsc = (sghsc_t *)op_arg; 736 int rc; 737 int result; 738 int slot_num = sghsc_get_slotnum(sghsc, sloth); 739 740 switch (flag) { 741 742 case SGHSC_ALL_SLOTS_ENABLE: 743 for (i = 0; i < sghsc->sghsc_num_slots; i++) { 744 /* 745 * All slots will be marked 'empty' as HP Framework 746 * will try to connect those which have no kernel node. 747 */ 748 sghsc->sghsc_slot_table[i].slot_status = 749 HPC_SLOT_EMPTY; 750 } 751 752 return (HPC_SUCCESS); 753 } 754 755 if (slot_num == -1) 756 return (HPC_ERR_INVALID); 757 758 SGHSC_MUTEX_ENTER(sghsc); 759 760 DEBUGF(1, (CE_NOTE, "sghsc%d: connecting logical slot%d for" 761 " node %d / board %d", sghsc->sghsc_instance, slot_num, 762 sghsc->sghsc_node_id, sghsc->sghsc_board)); 763 764 /* 765 * Powering an empty slot is highly illegal so far 766 * (before SC implemented a constant poll). Otherwise 767 * it breaks ddi framework and HP. The workaround 768 * is to check for a card first. 769 */ 770 rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id, 771 sghsc->sghsc_board, slot_num, &result); 772 773 if (rc == ETIMEDOUT) { 774 SGHSC_MUTEX_EXIT(sghsc); 775 return (HPC_ERR_FAILED); 776 } 777 778 if (rc) { 779 cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for" 780 " node %d / board %d", sghsc->sghsc_instance, slot_num, 781 sghsc->sghsc_node_id, sghsc->sghsc_board); 782 sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_UNKNOWN; 783 SGHSC_MUTEX_EXIT(sghsc); 784 return (HPC_ERR_FAILED); 785 } 786 787 788 if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) { 789 sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_EMPTY; 790 SGHSC_MUTEX_EXIT(sghsc); 791 return (HPC_ERR_FAILED); 792 } 793 794 rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_ON, sghsc->sghsc_node_id, 795 sghsc->sghsc_board, slot_num, &result); 796 if (rc) { 797 cmn_err(CE_WARN, "sghsc%d: unable to poweron slot %d for" 798 " node %d / board %d", sghsc->sghsc_instance, 799 slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board); 800 SGHSC_MUTEX_EXIT(sghsc); 801 return (HPC_ERR_FAILED); 802 } else { 803 sghsc->sghsc_slot_table[slot_num].slot_status = 804 HPC_SLOT_CONNECTED; 805 } 806 807 SGHSC_MUTEX_EXIT(sghsc); 808 809 return (HPC_SUCCESS); 810 } 811 812 813 /* 814 * Disconnecting a slot or slots 815 * 816 * return: HPC_SUCCESS if slot(s) are successfully disconnected 817 * HPC_ERR_FAILED if slot(s) can't be disconnected 818 * 819 */ 820 /* ARGSUSED */ 821 static int 822 sghsc_disconnect(caddr_t op_arg, hpc_slot_t sloth, void *data, 823 uint_t flag) 824 { 825 sghsc_t *sghsc = (sghsc_t *)op_arg; 826 int rc; 827 int result; 828 int slot_num = sghsc_get_slotnum(sghsc, sloth); 829 830 switch (flag) { 831 case SGHSC_ALL_SLOTS_DISABLE: 832 return (HPC_SUCCESS); 833 834 } 835 836 if (slot_num == -1) 837 return (HPC_ERR_INVALID); 838 839 SGHSC_MUTEX_ENTER(sghsc); 840 841 /* 842 * Disconnecting an empty or disconnected slot 843 * does't make sense. 844 */ 845 if (sghsc->sghsc_slot_table[slot_num].slot_status != 846 HPC_SLOT_CONNECTED) { 847 SGHSC_MUTEX_EXIT(sghsc); 848 return (HPC_SUCCESS); 849 } 850 851 rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_OFF, sghsc->sghsc_node_id, 852 sghsc->sghsc_board, slot_num, &result); 853 if (rc) { 854 cmn_err(CE_WARN, "sghsc%d: unable to poweroff slot %d for" 855 " node %d / board %d", sghsc->sghsc_instance, 856 slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board); 857 SGHSC_MUTEX_EXIT(sghsc); 858 return (HPC_ERR_FAILED); 859 } else { 860 sghsc->sghsc_slot_table[slot_num].slot_status = 861 HPC_SLOT_DISCONNECTED; 862 } 863 864 SGHSC_MUTEX_EXIT(sghsc); 865 866 return (HPC_SUCCESS); 867 } 868 869 /* 870 * Entry point from the hotplug framework to do 871 * the main hotplug operations 872 * Return val: HPC_SUCCESS success on ops 873 * HPC_NOT_SUPPORTED not supported feature 874 * HPC_ERR_FAILED ops failed 875 */ 876 /*ARGSUSED*/ 877 static int 878 sghsc_control(caddr_t op_arg, hpc_slot_t sloth, int request, 879 caddr_t arg) 880 { 881 sghsc_t *sghsc = (sghsc_t *)op_arg; 882 int slot = sghsc_get_slotnum(sghsc, sloth); 883 int error = HPC_SUCCESS; 884 int rc; 885 int result; 886 887 if ((sghsc == NULL) || (slot < 0) || 888 (slot >= sghsc->sghsc_num_slots)) { 889 cmn_err(CE_WARN, "sghsc%d: sghsc_control fails with slot = %d" 890 " max = %d, sloth = 0x%p for node %d / board %d", 891 sghsc->sghsc_instance, slot, sghsc->sghsc_num_slots, 892 sloth, sghsc->sghsc_node_id, sghsc->sghsc_board); 893 return (HPC_ERR_INVALID); 894 } 895 896 SGHSC_MUTEX_ENTER(sghsc); 897 898 switch (request) { 899 case HPC_CTRL_GET_LED_STATE: { 900 /* arg == hpc_led_info_t */ 901 902 hpc_led_info_t *ledinfo; 903 904 ledinfo = (hpc_led_info_t *)arg; 905 906 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control" 907 " HPC_CTRL_GET_LED_STATE for node %d / board %d slot %d", 908 sghsc->sghsc_instance, sghsc->sghsc_node_id, 909 sghsc->sghsc_board, slot)); 910 911 switch (ledinfo->led) { 912 case HPC_POWER_LED: 913 case HPC_ATTN_LED: 914 case HPC_FAULT_LED: 915 case HPC_ACTIVE_LED: 916 error = sghsc_led_state(sghsc, sloth, 917 HPC_CTRL_GET_LED_STATE, ledinfo); 918 break; 919 default: 920 cmn_err(CE_WARN, "sghsc%d: sghsc_control" 921 " HPC_CTRL_GET_LED_STATE " 922 " unknown led state %d for node %d / board %d" 923 " slot handle 0x%p", sghsc->sghsc_instance, 924 ledinfo->led, sghsc->sghsc_node_id, 925 sghsc->sghsc_board, sloth); 926 error = HPC_ERR_NOTSUPPORTED; 927 break; 928 } 929 930 break; 931 } 932 933 case HPC_CTRL_SET_LED_STATE: { 934 /* arg == hpc_led_info_t */ 935 hpc_led_info_t *ledinfo; 936 937 ledinfo = (hpc_led_info_t *)arg; 938 939 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control" 940 " HPC_CTRL_SET_LED_STATE for node %d / board %d slot %d", 941 sghsc->sghsc_instance, sghsc->sghsc_node_id, 942 sghsc->sghsc_board, slot)); 943 944 switch (ledinfo->led) { 945 case HPC_POWER_LED: 946 case HPC_ATTN_LED: 947 case HPC_FAULT_LED: 948 case HPC_ACTIVE_LED: 949 DEBUGF(1, (CE_NOTE, "sghsc:" 950 " LED writing not supported ")); 951 break; 952 953 default: 954 DEBUGF(1, (CE_NOTE, "sghsc:" 955 " LED not supported ")); 956 error = HPC_ERR_NOTSUPPORTED; 957 } 958 break; 959 } 960 961 case HPC_CTRL_GET_SLOT_STATE: { 962 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control" 963 " HPC_CTRL_GET_SLOT_STATE for node %d / board %d slot %d", 964 sghsc->sghsc_instance, sghsc->sghsc_node_id, 965 sghsc->sghsc_board, slot)); 966 967 /* 968 * Send mailbox cmd to SC to query the latest state 969 */ 970 rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id, 971 sghsc->sghsc_board, slot, &result); 972 973 if (rc == ETIMEDOUT) { 974 error = HPC_ERR_FAILED; 975 break; 976 } 977 978 if (rc) { 979 cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for " 980 "node %d / board %d", sghsc->sghsc_instance, slot, 981 sghsc->sghsc_node_id, sghsc->sghsc_board); 982 sghsc->sghsc_slot_table[slot].slot_status = 983 HPC_SLOT_UNKNOWN; 984 *(hpc_slot_state_t *)arg = HPC_SLOT_UNKNOWN; 985 break; 986 } 987 988 /* 989 * Update the cached state if needed. Initally all 990 * slots are marked as empty for the Hot Plug Framwork. 991 */ 992 if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) { 993 sghsc->sghsc_slot_table[slot].slot_status = 994 HPC_SLOT_EMPTY; 995 } else if ((result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT) { 996 sghsc->sghsc_slot_table[slot].slot_status = 997 HPC_SLOT_CONNECTED; 998 } else if (sghsc->sghsc_slot_table[slot].slot_status == 999 HPC_SLOT_EMPTY || 1000 sghsc->sghsc_slot_table[slot].slot_status == 1001 HPC_SLOT_UNKNOWN) { 1002 sghsc->sghsc_slot_table[slot].slot_status = 1003 HPC_SLOT_DISCONNECTED; 1004 } 1005 /* 1006 * No change 1007 */ 1008 *(hpc_slot_state_t *)arg = 1009 sghsc->sghsc_slot_table[slot].slot_status; 1010 1011 break; 1012 } 1013 1014 case HPC_CTRL_DEV_CONFIGURED: 1015 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control" 1016 " HPC_CTRL_DEV_CONFIGURED for node %d / board %d slot %d", 1017 sghsc->sghsc_instance, sghsc->sghsc_node_id, 1018 sghsc->sghsc_board, slot)); 1019 1020 if (sghsc_configure_ack) 1021 cmn_err(CE_NOTE, "sghsc%d:" 1022 " node %d / board %d slot %d configured", 1023 sghsc->sghsc_instance, sghsc->sghsc_node_id, 1024 sghsc->sghsc_board, slot); 1025 /* 1026 * This is important to tell SC: 1027 * "start looking for ENUMs" 1028 */ 1029 if (sghsc->sghsc_slot_table[slot].flags & 1030 SGHSC_SLOT_AUTO_CFG_EN) 1031 (void) sghsc_scctl(SGHSC_SET_ENUM_CLEARED, 1032 sghsc->sghsc_node_id, sghsc->sghsc_board, 1033 slot, &result); 1034 1035 break; 1036 1037 case HPC_CTRL_DEV_UNCONFIGURED: 1038 /* 1039 * due to unclean drivers, unconfigure may leave 1040 * some state on card, configure may actually 1041 * use these invalid values. therefore, may force 1042 * disconnect. 1043 */ 1044 1045 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control " 1046 "HPC_CTRL_DEV_UNCONFIGURED for node %d / board %d slot %d", 1047 sghsc->sghsc_instance, sghsc->sghsc_node_id, 1048 sghsc->sghsc_board, slot)); 1049 1050 SGHSC_MUTEX_EXIT(sghsc); 1051 if (sghsc_disconnect(op_arg, sloth, 0, 1052 0) != HPC_SUCCESS) { 1053 DEBUGF(1, (CE_NOTE, "sghsc_control: " 1054 "disconnect failed")); 1055 error = HPC_ERR_FAILED; 1056 } 1057 1058 cmn_err(CE_NOTE, "sghsc%d: node %d / board %d " 1059 "slot %d unconfigured", sghsc->sghsc_instance, 1060 sghsc->sghsc_node_id, sghsc->sghsc_board, slot); 1061 return (error); 1062 1063 1064 case HPC_CTRL_GET_BOARD_TYPE: { 1065 /* arg = hpc_board_type_t */ 1066 1067 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control" 1068 " HPC_CTRL_GET_BOARD_TYPE for node %d / board %d slot %d", 1069 sghsc->sghsc_instance, sghsc->sghsc_node_id, 1070 sghsc->sghsc_board, slot)); 1071 1072 *(hpc_board_type_t *)arg = 1073 sghsc->sghsc_slot_table[slot].board_type; 1074 1075 break; 1076 } 1077 1078 case HPC_CTRL_ENABLE_AUTOCFG: 1079 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control" 1080 " HPC_CTRL_ENABLE_AUTOCFG for node %d / board %d slot %d", 1081 sghsc->sghsc_instance, sghsc->sghsc_node_id, 1082 sghsc->sghsc_board, slot)); 1083 1084 sghsc->sghsc_slot_table[slot].flags |= SGHSC_SLOT_AUTO_CFG_EN; 1085 (void) hpc_slot_event_notify(sloth, HPC_EVENT_ENABLE_ENUM, 1086 HPC_EVENT_NORMAL); 1087 1088 /* 1089 * Tell SC to start looking for ENUMs on this slot. 1090 */ 1091 rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED, sghsc->sghsc_node_id, 1092 sghsc->sghsc_board, slot, &result); 1093 1094 if (rc) 1095 cmn_err(CE_WARN, "sghsc%d: unable to arm ENUM for" 1096 " node %d / board %d, slot %d", 1097 sghsc->sghsc_instance, sghsc->sghsc_node_id, 1098 sghsc->sghsc_board, slot); 1099 break; 1100 1101 case HPC_CTRL_DISABLE_AUTOCFG: 1102 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control" 1103 " HPC_CTRL_DISABLE_AUTOCFG for node %d / board %d slot %d", 1104 sghsc->sghsc_instance, sghsc->sghsc_node_id, 1105 sghsc->sghsc_board, slot)); 1106 1107 sghsc->sghsc_slot_table[slot].flags &= ~SGHSC_SLOT_AUTO_CFG_EN; 1108 (void) hpc_slot_event_notify(sloth, HPC_EVENT_DISABLE_ENUM, 1109 HPC_EVENT_NORMAL); 1110 break; 1111 1112 case HPC_CTRL_DISABLE_SLOT: 1113 case HPC_CTRL_ENABLE_SLOT: 1114 break; 1115 1116 /* need to add support for enable/disable_ENUM */ 1117 case HPC_CTRL_DISABLE_ENUM: 1118 case HPC_CTRL_ENABLE_ENUM: 1119 default: 1120 DEBUGF(1, (CE_CONT, "sghsc%d: sghsc_control " 1121 "request (0x%x) not supported", sghsc->sghsc_instance, 1122 request)); 1123 1124 /* invalid request */ 1125 error = HPC_ERR_NOTSUPPORTED; 1126 } 1127 1128 SGHSC_MUTEX_EXIT(sghsc); 1129 1130 return (error); 1131 } 1132 1133 /* 1134 * Read/write slot's led 1135 * Assume MUTEX_HELD 1136 * 1137 * return: HPC_SUCCESS if the led's status is avaiable, 1138 * SC return status otherwise. 1139 */ 1140 static int 1141 sghsc_led_state(sghsc_t *sghsc, hpc_slot_t sloth, int op, 1142 hpc_led_info_t *ledinfo) 1143 { 1144 int rval; 1145 int slot_num; 1146 int result; 1147 1148 slot_num = sghsc_get_slotnum(sghsc, sloth); 1149 rval = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id, 1150 sghsc->sghsc_board, slot_num, &result); 1151 if (rval != HPC_SUCCESS) 1152 return (rval); 1153 1154 switch (op) { 1155 case HPC_CTRL_GET_LED_STATE: 1156 switch (ledinfo->led) { 1157 case HPC_POWER_LED: 1158 if ((result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT) 1159 ledinfo->state = HPC_LED_ON; 1160 else 1161 ledinfo->state = HPC_LED_OFF; 1162 break; 1163 1164 case HPC_ATTN_LED: 1165 case HPC_FAULT_LED: 1166 if ((result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT) 1167 ledinfo->state = HPC_LED_ON; 1168 else 1169 ledinfo->state = HPC_LED_OFF; 1170 break; 1171 1172 case HPC_ACTIVE_LED: 1173 if ((result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT) 1174 ledinfo->state = HPC_LED_ON; 1175 else 1176 ledinfo->state = HPC_LED_OFF; 1177 break; 1178 } 1179 1180 break; 1181 1182 case HPC_CTRL_SET_LED_STATE: 1183 return (HPC_ERR_NOTSUPPORTED); 1184 } 1185 1186 return (HPC_SUCCESS); 1187 } 1188 1189 /* 1190 * sghsc_get_slotnum() 1191 * get slot number from the slot handle 1192 * returns non-negative value to indicate slot number 1193 * -1 for failure 1194 */ 1195 static int 1196 sghsc_get_slotnum(sghsc_t *sghsc, hpc_slot_t sloth) 1197 { 1198 int i; 1199 1200 if (sloth == NULL || sghsc == NULL) 1201 return (-1); 1202 1203 for (i = 0; i < sghsc->sghsc_num_slots; i++) { 1204 1205 if (sghsc->sghsc_slot_table[i].handle == sloth) 1206 return (i); 1207 } 1208 1209 return (-1); 1210 1211 } 1212 1213 /* 1214 * sghsc_scctl() 1215 * mailbox interface 1216 * 1217 * return result code from mailbox operation 1218 */ 1219 static int 1220 sghsc_scctl(int cmd, int node_id, int board, int slot, int *resultp) 1221 { 1222 int ret = 0xbee; 1223 bitcmd_info_t cmd_info, *cmd_infop = &cmd_info; 1224 bitcmd_resp_t cmd_info_r, *cmd_info_r_p = &cmd_info_r; 1225 sbbc_msg_t request, *reqp = &request; 1226 sbbc_msg_t response, *resp = &response; 1227 1228 cmd_infop->cmd_id = 0x01234567; 1229 cmd_infop->node_id = node_id; 1230 cmd_infop->board = board; 1231 cmd_infop->slot = slot; 1232 1233 reqp->msg_type.type = CPCI_MBOX; 1234 reqp->msg_status = 0xeeeeffff; 1235 reqp->msg_len = sizeof (cmd_info); 1236 reqp->msg_bytes = 8; 1237 reqp->msg_buf = (caddr_t)cmd_infop; 1238 reqp->msg_data[0] = 0; 1239 reqp->msg_data[1] = 0; 1240 1241 bzero(resp, sizeof (*resp)); 1242 bzero(cmd_info_r_p, sizeof (*cmd_info_r_p)); 1243 1244 resp->msg_buf = (caddr_t)cmd_info_r_p; 1245 resp->msg_len = sizeof (cmd_info_r); 1246 1247 resp->msg_type.type = CPCI_MBOX; 1248 resp->msg_bytes = 8; 1249 resp->msg_status = 0xddddffff; 1250 1251 switch (cmd) { 1252 case SGHSC_GET_SLOT_STATUS: 1253 reqp->msg_type.sub_type = CPCI_GET_SLOT_STATUS; 1254 resp->msg_type.sub_type = CPCI_GET_SLOT_STATUS; 1255 reqp->msg_len -= 4; 1256 break; 1257 case SGHSC_GET_NUM_SLOTS: 1258 reqp->msg_type.sub_type = CPCI_GET_NUM_SLOTS; 1259 resp->msg_type.sub_type = CPCI_GET_NUM_SLOTS; 1260 reqp->msg_len -= 8; 1261 break; 1262 case SGHSC_SET_SLOT_STATUS_RESET: 1263 reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS; 1264 resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS; 1265 cmd_infop->info = CPCI_SET_STATUS_SLOT_RESET; 1266 break; 1267 case SGHSC_SET_SLOT_STATUS_READY: 1268 reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS; 1269 resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS; 1270 cmd_infop->info = CPCI_SET_STATUS_SLOT_READY; 1271 break; 1272 case SGHSC_SET_SLOT_FAULT_LED_ON: 1273 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1274 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1275 cmd_infop->info = CPCI_SET_FAULT_LED_ON; 1276 break; 1277 case SGHSC_SET_SLOT_FAULT_LED_OFF: 1278 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1279 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1280 cmd_infop->info = CPCI_SET_FAULT_LED_OFF; 1281 break; 1282 case SGHSC_SET_SLOT_FAULT_LED_KEEP: 1283 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1284 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1285 cmd_infop->info = CPCI_SET_FAULT_LED_KEEP; 1286 break; 1287 case SGHSC_SET_SLOT_FAULT_LED_TOGGLE: 1288 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1289 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED; 1290 cmd_infop->info = CPCI_SET_FAULT_LED_TOGGLE; 1291 break; 1292 case SGHSC_SET_SLOT_POWER_OFF: 1293 reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER; 1294 resp->msg_type.sub_type = CPCI_SET_SLOT_POWER; 1295 cmd_infop->info = CPCI_POWER_OFF; 1296 break; 1297 case SGHSC_SET_SLOT_POWER_ON: 1298 reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER; 1299 resp->msg_type.sub_type = CPCI_SET_SLOT_POWER; 1300 cmd_infop->info = CPCI_POWER_ON; 1301 break; 1302 case SGHSC_GET_CPCI_BOARD_TYPE: 1303 reqp->msg_type.sub_type = CPCI_BOARD_TYPE; 1304 resp->msg_type.sub_type = CPCI_BOARD_TYPE; 1305 reqp->msg_len -= 8; 1306 break; 1307 case SGHSC_SET_ENUM_CLEARED: 1308 reqp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED; 1309 resp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED; 1310 break; 1311 default: 1312 cmn_err(CE_WARN, "sghsc: unrecognized action code 0x%x\n", 1313 cmd); 1314 } 1315 1316 DEBUGF(1, (CE_NOTE, 1317 "sghsc: sending mbox command type=%d subtype=0x%x size=%d buf=%p", 1318 reqp->msg_type.type, reqp->msg_type.sub_type, 1319 reqp->msg_len, reqp->msg_buf)); 1320 1321 DEBUGF(1, (CE_NOTE, 1322 "sghsc: sending buf cmd_id=0x%x node_id=0x%x board=0x%x " 1323 "slot=0x%x info=0x%x", cmd_infop->cmd_id, cmd_infop->node_id, 1324 cmd_infop->board, cmd_infop->slot, cmd_infop->info)); 1325 1326 1327 ret = sbbc_mbox_request_response(reqp, resp, sghsc_mbx_timeout); 1328 1329 /* 1330 * The resp->msg_status field may contain an SC error or a common 1331 * error such as ETIMEDOUT. 1332 */ 1333 if ((ret != 0) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 1334 DEBUGF(1, (CE_NOTE, "sghsc: mailbox command error = 0x%x, " 1335 "status = 0x%x", ret, resp->msg_status)); 1336 return (-1); 1337 } 1338 1339 DEBUGF(1, (CE_NOTE, "sghsc: reply request status=0x%x", 1340 reqp->msg_status)); 1341 DEBUGF(1, (CE_NOTE, "sghsc: reply resp status=0x%x", 1342 resp->msg_status)); 1343 DEBUGF(1, (CE_NOTE, "sghsc: reply buf cmd_id=0x%x result=0x%x\n", 1344 cmd_info_r_p->cmd_id, cmd_info_r_p->result)); 1345 1346 #ifdef DEBUG_EXTENDED 1347 if (cmd == SGHSC_GET_NUM_SLOTS) { 1348 DEBUGF(1, (CE_NOTE, "sghsc: node %d / board %d has %d slots", 1349 cmd_infop->node_id, cmd_infop->board, 1350 cmd_info_r_p->result)); 1351 *resultp = cmd_info_r_p->result; 1352 return (0); 1353 } 1354 1355 if ((cmd_info_r_p->result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT) 1356 DEBUGF(1, (CE_NOTE, "sghsc: cpower on")); 1357 1358 if ((cmd_info_r_p->result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT) 1359 DEBUGF(1, (CE_NOTE, "sghsc: power led on")); 1360 1361 if ((cmd_info_r_p->result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT) 1362 DEBUGF(1, (CE_NOTE, "sghsc: fault led on")); 1363 1364 if ((cmd_info_r_p->result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT) 1365 DEBUGF(1, (CE_NOTE, "sghsc: remove(hp) led on")); 1366 1367 if ((cmd_info_r_p->result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) 1368 DEBUGF(1, (CE_NOTE, "sghsc: slot empty")); 1369 1370 tmp = ((cmd_info_r_p->result >> CPCI_STAT_HOT_SWAP_STATUS_SHIFT) & 1371 THREE_BITS); 1372 if (tmp) 1373 DEBUGF(1, (CE_NOTE, 1374 "sghsc: slot condition(hot swap status) is 0x%x", tmp)); 1375 1376 if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_CAP) 1377 DEBUGF(1, (CE_NOTE, 1378 "sghsc: freq cap %x", cmd_info_r_p->result & 1379 CPCI_GET_STAT_SLOT_HZ_CAP)); 1380 1381 if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_SET) 1382 DEBUGF(1, (CE_NOTE, 1383 "sghsc: freq setting %x", cmd_info_r_p->result & 1384 CPCI_GET_STAT_SLOT_HZ_SET)); 1385 1386 1387 if ((cmd_info_r_p->result >> CPCI_STAT_HEALTHY_SHIFT) & ONE_BIT) 1388 DEBUGF(1, (CE_NOTE, "sghsc: healthy")); 1389 1390 if ((cmd_info_r_p->result >> CPCI_STAT_RESET_SHIFT) & ONE_BIT) 1391 DEBUGF(1, (CE_NOTE, "sghsc: in reset")); 1392 1393 if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_GOOD) 1394 DEBUGF(1, (CE_NOTE, "sghsc: power good")); 1395 1396 if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_FAULT) 1397 DEBUGF(1, (CE_NOTE, "sghsc: power fault")); 1398 1399 if (cmd_info_r_p->result & CPCI_GET_STAT_PCI_PRESENT) 1400 DEBUGF(1, (CE_NOTE, "sghsc: pci present")); 1401 #endif 1402 1403 *resultp = cmd_info_r_p->result; 1404 return (0); 1405 } 1406 1407 1408 /* 1409 * sghsc_freemem() 1410 * deallocates memory resources 1411 * 1412 */ 1413 static void 1414 sghsc_freemem(sghsc_t *sghsc) 1415 { 1416 int i; 1417 1418 /* 1419 * Free up allocated resources 1420 * sghsc_register_slots => unregister all slots 1421 */ 1422 for (i = 0; i < sghsc->sghsc_num_slots; i++) { 1423 if (sghsc->sghsc_slot_table[i].slot_ops) 1424 hpc_free_slot_ops(sghsc->sghsc_slot_table[i].slot_ops); 1425 if (sghsc->sghsc_slot_table[i].handle) 1426 hpc_slot_unregister(&sghsc->sghsc_slot_table[i].handle); 1427 } 1428 1429 /* finally free up slot_table */ 1430 kmem_free(sghsc->sghsc_slot_table, 1431 (size_t)(sghsc->sghsc_num_slots * sizeof (sghsc_slot_t))); 1432 1433 } 1434 1435 /* 1436 * sghsc_find_sloth() 1437 * Find slot handle by node id, board number and slot numbert 1438 * Returns slot handle or 0 if slot not found. 1439 */ 1440 static hpc_slot_t 1441 sghsc_find_sloth(int node_id, int board, int slot) 1442 { 1443 int instance; 1444 sghsc_t *sghsc; 1445 1446 for (instance = 0; instance < sghsc_maxinst; instance++) { 1447 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance); 1448 1449 if (sghsc == NULL || sghsc->sghsc_node_id != node_id || 1450 sghsc->sghsc_board != board) 1451 continue; 1452 1453 DEBUGF(1, (CE_NOTE, "sghsc_find_sloth on board %d at node %d" 1454 " slot %d", board, node_id, slot)) 1455 1456 if (sghsc->sghsc_num_slots < (slot + 1)) { 1457 cmn_err(CE_WARN, "sghsc%d: slot data corruption at" 1458 "node %d / board %d", instance, node_id, board); 1459 return (NULL); 1460 } 1461 1462 if (sghsc->sghsc_valid == 0) 1463 return (NULL); 1464 1465 /* 1466 * Found matching slot, return handle. 1467 */ 1468 return (sghsc->sghsc_slot_table[slot].handle); 1469 } 1470 1471 DEBUGF(1, (CE_WARN, "sghsc_find_sloth: slot %d not found for node %d" 1472 " / board %d", slot, node_id, board)); 1473 return (NULL); 1474 } 1475 1476 /* 1477 * sghsc_event_handler() 1478 * Event Handler. This is what for other platforms was an interrupt 1479 * Handler servicing events. It accepts an event and signals it to 1480 * non-interrupt thread. 1481 */ 1482 uint_t 1483 sghsc_event_handler(char *arg) 1484 { 1485 sghsc_event_t *rsp_data; 1486 hpc_slot_t sloth; 1487 sghsc_t *enum_state; 1488 1489 DEBUGF(1, (CE_NOTE, "sghsc: sghsc_event_handler called")) 1490 1491 rsp_data = (sghsc_event_t *)(((sbbc_msg_t *)arg)->msg_buf); 1492 1493 if (rsp_data == NULL) { 1494 cmn_err(CE_WARN, 1495 ("sghsc: sghsc_event_handler argument is null\n")); 1496 return (DDI_INTR_CLAIMED); 1497 } 1498 1499 sloth = sghsc_find_sloth(rsp_data->node_id, rsp_data->board, 1500 rsp_data->slot); 1501 /* 1502 * On a board disconnect sghsc soft state may not exist 1503 * when the interrupt occurs. We should treat these 1504 * interrupts as noise and but them. 1505 */ 1506 if (sloth == NULL) { 1507 DEBUGF(1, (CE_WARN, "sghsc: slot info not available for" 1508 " node %d / board %d slot %d. CPCI event rejected", 1509 rsp_data->node_id, rsp_data->board, rsp_data->slot)); 1510 return (DDI_INTR_CLAIMED); 1511 } 1512 1513 enum_state = sghsc_find_softstate(rsp_data->node_id, rsp_data->board, 1514 rsp_data->slot); 1515 if (enum_state == NULL) { 1516 cmn_err(CE_WARN, "sghsc: soft state not available for" 1517 " node %d / board %d slot %d", rsp_data->node_id, 1518 rsp_data->board, rsp_data->slot); 1519 return (DDI_INTR_UNCLAIMED); 1520 } 1521 1522 DEBUGF(1, (CE_NOTE, "sghsc: node %d", rsp_data->node_id)); 1523 DEBUGF(1, (CE_NOTE, "sghsc: board %d", rsp_data->board)); 1524 DEBUGF(1, (CE_NOTE, "sghsc: slot %d", rsp_data->slot)); 1525 DEBUGF(1, (CE_NOTE, "sghsc: event info %d", rsp_data->info)); 1526 1527 switch (rsp_data->info) { 1528 case SGHSC_EVENT_CARD_INSERT: 1529 DEBUGF(1, (CE_NOTE, "sghsc: card inserted node %d / board %d" 1530 " slot %d", rsp_data->node_id, rsp_data->board, 1531 rsp_data->slot)); 1532 enum_state->sghsc_slot_table[rsp_data->slot].board_type = 1533 HPC_BOARD_CPCI_HS; 1534 enum_state->sghsc_slot_table[rsp_data->slot].slot_status = 1535 HPC_SLOT_DISCONNECTED; 1536 break; 1537 case SGHSC_EVENT_CARD_REMOVE: 1538 DEBUGF(1, (CE_NOTE, "sghsc: card removed node %d / board %d" 1539 " slot %d", rsp_data->node_id, rsp_data->board, 1540 rsp_data->slot)); 1541 enum_state->sghsc_slot_table[rsp_data->slot].board_type = 1542 HPC_BOARD_UNKNOWN; 1543 enum_state->sghsc_slot_table[rsp_data->slot].slot_status = 1544 HPC_SLOT_EMPTY; 1545 return (DDI_INTR_CLAIMED); 1546 case SGHSC_EVENT_POWER_ON: 1547 DEBUGF(1, (CE_NOTE, "sghsc: power on node %d / board %d" 1548 " slot %d", rsp_data->node_id, rsp_data->board, 1549 rsp_data->slot)); 1550 return (DDI_INTR_CLAIMED); 1551 case SGHSC_EVENT_POWER_OFF: 1552 DEBUGF(1, (CE_NOTE, "sghsc: power off node %d / board %d" 1553 " slot %d", rsp_data->node_id, rsp_data->board, 1554 rsp_data->slot)); 1555 return (DDI_INTR_CLAIMED); 1556 case SGHSC_EVENT_HEALTHY_LOST: 1557 DEBUGF(1, (CE_NOTE, "sghsc: healthy lost node %d / board %d" 1558 " slot %d", rsp_data->node_id, rsp_data->board, 1559 rsp_data->slot)); 1560 return (DDI_INTR_CLAIMED); 1561 case SGHSC_EVENT_LEVER_ACTION: 1562 DEBUGF(1, (CE_NOTE, "sghsc: ENUM generated for node %d /" 1563 "board %d slot %d", rsp_data->node_id, rsp_data->board, 1564 rsp_data->slot)); 1565 break; 1566 default: 1567 DEBUGF(1, (CE_NOTE, "sghsc: unrecognized event info for" 1568 " node %d / board %d slot %d", rsp_data->node_id, 1569 rsp_data->board, rsp_data->slot)); 1570 return (DDI_INTR_CLAIMED); 1571 } 1572 1573 /* 1574 * Signal the ENUM event to the non-interrupt thread as the Hot 1575 * Plug Framework will eventually call sghsc_control() but all 1576 * the mailbox messages are not allowed from interrupt context. 1577 */ 1578 1579 if (sghsc_rb_put(&sghsc_rb_header, rsp_data) != DDI_SUCCESS) { 1580 cmn_err(CE_WARN, "sghsc: no space to store #ENUM info"); 1581 return (DDI_INTR_UNCLAIMED); 1582 } 1583 1584 cv_signal(&sghsc_event_thread_cv); 1585 1586 return (DDI_INTR_CLAIMED); 1587 } 1588 1589 /* 1590 * sghsc_event_thread_code() 1591 * Event Thread. This is non-interrupt thread servicing #ENUM, Insert, 1592 * Remove, Power on/off, Healthy lost events. 1593 */ 1594 static void 1595 sghsc_event_thread_code(void) 1596 { 1597 int rc; 1598 int result; 1599 hpc_slot_t sloth; 1600 sghsc_t *sghsc; 1601 sghsc_event_t rsp_data; 1602 1603 mutex_enter(&sghsc_event_thread_mutex); 1604 1605 for (;;) { 1606 /* 1607 * Wait for Event handler to signal event or self destruction. 1608 * Assuming the mutex will be automatically reaccuired. 1609 */ 1610 cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex); 1611 1612 if (sghsc_event_thread_exit) 1613 break; 1614 1615 /* 1616 * Pick up all the relevant events from the ring buffer. 1617 */ 1618 while (sghsc_rb_get(&sghsc_rb_header, &rsp_data) == 1619 DDI_SUCCESS) { 1620 1621 sghsc = sghsc_find_softstate(rsp_data.node_id, 1622 rsp_data.board, rsp_data.slot); 1623 if (sghsc == NULL) 1624 continue; 1625 sloth = sghsc_find_sloth(rsp_data.node_id, 1626 rsp_data.board, rsp_data.slot); 1627 if (sloth == NULL) 1628 continue; 1629 1630 if (!(sghsc->sghsc_slot_table[rsp_data.slot].flags & 1631 SGHSC_SLOT_AUTO_CFG_EN)) 1632 continue; 1633 /* 1634 * Insert event leads only to the electrical 1635 * connection. 1636 */ 1637 if (rsp_data.info == SGHSC_EVENT_CARD_INSERT) { 1638 rc = sghsc_connect((caddr_t)sghsc, sloth, 1639 NULL, 0); 1640 if (rc != HPC_SUCCESS) 1641 cmn_err(CE_WARN, "sghsc:" 1642 " could not connect inserted card," 1643 " node %d / board %d slot %d", 1644 rsp_data.node_id, rsp_data.board, 1645 rsp_data.slot); 1646 continue; 1647 } 1648 1649 /* 1650 * ENUM event received. 1651 * Reset ENUM and notify SC to poll for the next one. 1652 */ 1653 rc = hpc_slot_event_notify(sloth, HPC_EVENT_CLEAR_ENUM, 1654 HPC_EVENT_SYNCHRONOUS); 1655 1656 if (rc == HPC_EVENT_UNCLAIMED) { 1657 DEBUGF(1, (CE_WARN, 1658 "sghsc: unable to clear ENUM")); 1659 continue; 1660 } 1661 1662 rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED, 1663 rsp_data.node_id, rsp_data.board, 1664 rsp_data.slot, &result); 1665 if (rc) { 1666 DEBUGF(1, (CE_WARN, 1667 "sghsc: unable to ACK cleared ENUM")); 1668 continue; 1669 } 1670 1671 /* 1672 * process the ENUM. 1673 */ 1674 rc = hpc_slot_event_notify(sloth, 1675 HPC_EVENT_PROCESS_ENUM, HPC_EVENT_SYNCHRONOUS); 1676 1677 if (rc == HPC_EVENT_UNCLAIMED) { 1678 DEBUGF(1, (CE_WARN, 1679 "sghsc: could not process ENUM")); 1680 } 1681 } 1682 } 1683 1684 DEBUGF(1, (CE_NOTE, "sghsc: thread_exit")); 1685 cv_signal(&sghsc_event_thread_cv); 1686 mutex_exit(&sghsc_event_thread_mutex); 1687 thread_exit(); 1688 } 1689 1690 /* 1691 * sghsc_find_softstate() 1692 * Find softstate by node id and board number. Slot number is used for 1693 * verification. 1694 * Returns board's softstate or 0 if not found. 1695 */ 1696 static sghsc_t * 1697 sghsc_find_softstate(int node_id, int board, int slot) 1698 { 1699 int instance; 1700 sghsc_t *sghsc; 1701 1702 for (instance = 0; instance < sghsc_maxinst; instance++) { 1703 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance); 1704 1705 if (sghsc == NULL || sghsc->sghsc_node_id != node_id || 1706 sghsc->sghsc_board != board) 1707 continue; 1708 1709 if (sghsc->sghsc_num_slots < (slot + 1)) { 1710 cmn_err(CE_WARN, "sghsc%d: " 1711 "slot data corruption", instance); 1712 return (NULL); 1713 } 1714 1715 if (sghsc->sghsc_valid == 0) 1716 return (NULL); 1717 1718 /* 1719 * Found matching data, return soft state. 1720 */ 1721 return (sghsc); 1722 } 1723 1724 cmn_err(CE_WARN, "sghsc: soft state not found"); 1725 return (NULL); 1726 } 1727 1728 /* 1729 * sghsc_rb_setup() 1730 * Initialize the event ring buffer with a fixed size. It may require 1731 * a more elaborate scheme with buffer extension 1732 */ 1733 static void 1734 sghsc_rb_setup(sghsc_rb_head_t *rb_head) 1735 { 1736 if (rb_head->buf == NULL) { 1737 rb_head->put_idx = 0; 1738 rb_head->get_idx = 0; 1739 rb_head->size = SGHSC_RING_BUFFER_SZ; 1740 rb_head->state = SGHSC_RB_EMPTY; 1741 1742 /* 1743 * Allocate space for event ring buffer 1744 */ 1745 rb_head->buf = (sghsc_event_t *)kmem_zalloc( 1746 sizeof (sghsc_event_t) * rb_head->size, KM_SLEEP); 1747 } 1748 } 1749 1750 /* 1751 * sghsc_rb_teardown() 1752 * Free event ring buffer resources. 1753 */ 1754 static void 1755 sghsc_rb_teardown(sghsc_rb_head_t *rb_head) 1756 { 1757 if (rb_head->buf != NULL) { 1758 /* 1759 * Deallocate space for event ring buffer 1760 */ 1761 kmem_free(rb_head->buf, 1762 (size_t)(sizeof (sghsc_event_t) * rb_head->size)); 1763 1764 rb_head->buf = NULL; 1765 rb_head->put_idx = 0; 1766 rb_head->get_idx = 0; 1767 rb_head->size = 0; 1768 rb_head->state = SGHSC_RB_EMPTY; 1769 } 1770 } 1771 1772 /* 1773 * sghsc_rb_put() 1774 * Insert an event info into the event ring buffer. 1775 * Returns DDI_FAILURE if the buffer is full, DDI_SUCCESS otherwise 1776 */ 1777 static int 1778 sghsc_rb_put(sghsc_rb_head_t *rb_head, sghsc_event_t *event) 1779 { 1780 if (rb_head->state == SGHSC_RB_FULL) 1781 return (DDI_FAILURE); 1782 1783 rb_head->buf[rb_head->put_idx] = *event; 1784 1785 rb_head->put_idx = ++rb_head->put_idx & (rb_head->size - 1); 1786 1787 if (rb_head->put_idx == rb_head->get_idx) 1788 rb_head->state = SGHSC_RB_FULL; 1789 else 1790 rb_head->state = SGHSC_RB_FLOAT; 1791 1792 return (DDI_SUCCESS); 1793 } 1794 /* 1795 * sghsc_rb_get() 1796 * Remove an event info from the event ring buffer. 1797 * Returns DDI_FAILURE if the buffer is empty, DDI_SUCCESS otherwise. 1798 */ 1799 static int 1800 sghsc_rb_get(sghsc_rb_head_t *rb_head, sghsc_event_t *event) 1801 { 1802 1803 if (rb_head->state == SGHSC_RB_EMPTY) 1804 return (DDI_FAILURE); 1805 1806 *event = rb_head->buf[rb_head->get_idx]; 1807 1808 rb_head->get_idx = ++rb_head->get_idx & (rb_head->size - 1); 1809 1810 if (rb_head->get_idx == rb_head->put_idx) 1811 rb_head->state = SGHSC_RB_EMPTY; 1812 else 1813 rb_head->state = SGHSC_RB_FLOAT; 1814 1815 return (DDI_SUCCESS); 1816 } 1817