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