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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * Starcat IOSRAM/Tunnel PCI Hot Plug Controller Driver 30 */ 31 32 #define CPCI_ENUM 33 34 #include <sys/note.h> 35 #include <sys/types.h> 36 #include <sys/cmn_err.h> 37 #include <sys/kmem.h> 38 #include <sys/errno.h> 39 #include <sys/open.h> 40 #include <sys/stat.h> 41 #include <sys/conf.h> 42 #include <sys/ddi.h> 43 #include <sys/cmn_err.h> 44 #include <sys/sunddi.h> 45 #include <sys/sunndi.h> 46 #include <sys/ddi_impldefs.h> 47 #include <sys/ndi_impldefs.h> 48 #include <sys/modctl.h> 49 #include <sys/disp.h> 50 #include <sys/async.h> 51 #include <sys/hotplug/hpcsvc.h> 52 #include <sys/mboxsc.h> 53 #include <sys/schpc_msg.h> 54 #include <sys/schpc.h> 55 #include <post/scat_dcd.h> 56 #include <sys/taskq.h> 57 58 #ifdef DEBUG 59 int schpc_dump_save_regs = 0; 60 static uint_t schpc_debug_flags = 0; 61 #define SCHPC_DEBUG0(f, s) if ((f)& schpc_debug_flags) \ 62 cmn_err(CE_CONT, "schpc: " s "\n") 63 #define SCHPC_DEBUG1(f, s, a) if ((f)& schpc_debug_flags) \ 64 cmn_err(CE_CONT, "schpc: " s "\n", a) 65 #define SCHPC_DEBUG2(f, s, a, b) if ((f)& schpc_debug_flags) \ 66 cmn_err(CE_CONT, "schpc: " s "\n", a, b) 67 #define SCHPC_DEBUG3(f, s, a, b, c) if ((f)& schpc_debug_flags) \ 68 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c) 69 #define SCHPC_DEBUG4(f, s, a, b, c, d) if ((f)& schpc_debug_flags) \ 70 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d) 71 #define SCHPC_DEBUG5(f, s, a, b, c, d, e) if ((f)& schpc_debug_flags) \ 72 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e) 73 #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& schpc_debug_flags) \ 74 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e, ff) 75 #else 76 77 #define SCHPC_DEBUG0(f, s) 78 #define SCHPC_DEBUG1(f, s, a) 79 #define SCHPC_DEBUG2(f, s, a, b) 80 #define SCHPC_DEBUG3(f, s, a, b, c) 81 #define SCHPC_DEBUG4(f, s, a, b, c, d) 82 #define SCHPC_DEBUG5(f, s, a, b, c, d, e) 83 #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) 84 85 #endif 86 87 #define D_IDENTIFY 0x00000001 88 #define D_ATTACH 0x00000002 89 #define D_DETACH 0x00000004 90 #define D_OPEN 0x00000008 91 #define D_GETSLOTSTATUS 0x00000010 92 #define D_SETSLOTSTATUS 0x00000020 93 #define D_IOCTL 0x00010000 94 #define D_IOC_CONNECT 0x00020000 95 #define D_IOC_CONTROL 0x00040000 96 #define D_IOC_CONFIG 0x00080000 97 #define D_IOC_STATUS 0x00100000 98 #define D_IOC_MSG 0x00200000 99 #define D_IOC_TEST 0x00400000 100 #define D_IOC_LED 0x00800000 101 #define D_EVENT 0x01000000 102 #define D_THREAD 0x02000000 103 #define D_TRANSID 0x04000000 104 #define D_SLOTTABLE 0x08000000 105 #define D_FREQCHG 0x10000000 106 #define D_APID 0x20000000 107 108 /* 109 * driver global data: 110 */ 111 static void *per_schpc_state; /* soft state head */ 112 dev_info_t *schpc_devi; 113 static schpc_t *schpc_p; 114 115 clock_t schpc_timeout_putmsg = 60 * 1000; /* 60 seconds */ 116 clock_t schpc_timeout_getmsg = 60 * 1000; /* 60 seconds */ 117 clock_t schpc_timeout_event = 60 * 5 * 1000; /* 5 minutes */ 118 119 int schpc_use_legacy_apid = 0; 120 121 static mboxsc_timeout_range_t schpc_putmsg_timeout_range; 122 static mboxsc_timeout_range_t schpc_getmsg_timeout_range; 123 124 static taskq_t *schpc_event_taskq = NULL; 125 126 /* 127 * replies to mboxsc_getmsg() are handled asynchronously by the 128 * schpc_msg_thread using a linked list of schpc_replylist_t 129 * elements 130 */ 131 typedef struct schpc_replylist { 132 struct schpc_replylist *prev; /* link to previous entry */ 133 struct schpc_replylist *next; /* link to next entry */ 134 kcondvar_t reply_cv; /* condvar for getting reply */ 135 kmutex_t reply_lock; /* mutex for getting reply */ 136 uint32_t type; /* mboxsc_xxxmsg() msg type */ 137 uint32_t cmd; /* mboxsc_xxxmsg() cmd */ 138 uint64_t transid; /* mboxsc_xxxmsg() trans id */ 139 uint32_t length; /* mboxsc_xxxmsg() length */ 140 pcimsg_t reply; /* mboxsc_xxxmsg() reply msg */ 141 boolean_t reply_recvd; /* msg reply received */ 142 boolean_t reply_cexit; /* client early exit */ 143 } schpc_replylist_t; 144 145 static kmutex_t schpc_replylist_mutex; /* replylist mutex */ 146 static uint32_t schpc_replylist_count; /* replylist size */ 147 static schpc_replylist_t *schpc_replylist_first; /* replylist 1st elem */ 148 static schpc_replylist_t *schpc_replylist_last; /* replylist last elem */ 149 static boolean_t slots_registered = B_FALSE; /* slots registered? */ 150 151 typedef struct { 152 char *cname; 153 char *caddr; 154 char schizo; 155 char leaf; 156 dev_info_t *dip; 157 } find_dev_t; 158 159 /* 160 * Function prototypes for local functions 161 */ 162 static int schpc_getexpander(dev_info_t *); 163 static int schpc_getboard(dev_info_t *); 164 static void schpc_event_handler(void *); 165 static void schpc_event_filter(pcimsg_t *msg); 166 static void schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd, 167 uint64_t transid, uint32_t length); 168 static uint64_t schpc_gettransid(schpc_t *, int); 169 static int schpc_slot_get_index(schpc_t *, hpc_slot_t); 170 static void schpc_register_all_slots(schpc_t *); 171 static void schpc_setslotled(int, int, int, uint32_t); 172 static void schpc_init_setslot_message(pci_setslot_t *); 173 static void schpc_test(caddr_t, int, void *, uint_t); 174 static int schpc_getslotstatus(uint32_t, uint32_t, uint32_t, pci_getslot_t *); 175 static int schpc_setslotstatus(uint32_t, uint32_t, uint32_t, pci_setslot_t *); 176 static int schpc_match_dip(dev_info_t *, void *); 177 static void schpc_buildapid(dev_info_t *, int, char *); 178 static int schpc_get_slot_status(uint_t, uint_t, uint_t); 179 static void schpc_replylist_unlink(schpc_replylist_t *entry); 180 static schpc_replylist_t *schpc_replylist_link(uint32_t cmd, uint64_t transid, 181 uint32_t length); 182 static void schpc_msg_thread(void); 183 static int schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, 184 uint64_t *transidp, uint32_t length, 185 void *datap, clock_t timeout, 186 schpc_replylist_t **entryp); 187 static int schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp, 188 uint64_t *transidp, uint32_t *lengthp, void *datap, 189 clock_t timeout, schpc_replylist_t *listp); 190 191 static int schpc_slot_freq(pci_getslot_t *); 192 static int schpc_find_dip(dev_info_t *, void *); 193 194 static int schpc_save_leaf(int slot); 195 static void schpc_restore_leaf(int slot); 196 static int schpc_is_leaf_reset_required(int slot); 197 static int schpc_is_freq_switchable(int slot); 198 static void schpc_save_entry(int slot, int list_entry, int save_entry); 199 static void schpc_restore_entry(int slot, int list_entry, int save_entry); 200 201 /* 202 * Function prototype for Hot Plug Services 203 */ 204 static int schpc_connect(caddr_t, hpc_slot_t, void *, uint_t); 205 static int schpc_disconnect(caddr_t, hpc_slot_t, void *, uint_t); 206 static int schpc_cpci_control(caddr_t, hpc_slot_t, int, caddr_t); 207 static int schpc_pci_control(caddr_t, hpc_slot_t, int, caddr_t); 208 209 extern int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t); 210 211 /* 212 * cb_ops and dev_ops: 213 */ 214 static struct cb_ops schpc_cb_ops = { 215 nodev, /* open */ 216 nodev, /* close */ 217 nodev, /* strategy */ 218 nodev, /* print */ 219 nodev, /* dump */ 220 nodev, /* read */ 221 nodev, /* write */ 222 nodev, /* ioctl */ 223 nodev, /* devmap */ 224 nodev, /* mmap */ 225 nodev, /* segmap */ 226 nochpoll, /* poll */ 227 ddi_prop_op, /* prop_op */ 228 0, /* streamtab */ 229 D_NEW | D_MP | D_HOTPLUG /* Driver compatibility flag */ 230 }; 231 232 /* 233 * Function prototype for dev_ops 234 */ 235 static int schpc_attach(dev_info_t *, ddi_attach_cmd_t); 236 static int schpc_detach(dev_info_t *, ddi_detach_cmd_t); 237 static int schpc_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 238 239 static struct dev_ops schpc_dev_ops = { 240 DEVO_REV, /* devo_rev, */ 241 0, /* refcnt */ 242 schpc_info, /* get_dev_info */ 243 nulldev, /* identify */ 244 nulldev, /* probe */ 245 schpc_attach, /* attach */ 246 schpc_detach, /* detach */ 247 nodev, /* reset */ 248 &schpc_cb_ops, /* driver operations */ 249 (struct bus_ops *)0, /* no bus operations */ 250 NULL, /* power */ 251 ddi_quiesce_not_supported, /* devo_quiesce */ 252 }; 253 254 /* 255 * loadable module declarations: 256 */ 257 static struct modldrv modldrv = { 258 &mod_driverops, 259 "PCI Hot Plug Controller Driver (schpc)", 260 &schpc_dev_ops, 261 }; 262 263 static struct modlinkage modlinkage = { 264 MODREV_1, 265 (void *)&modldrv, 266 NULL 267 }; 268 269 int 270 _init(void) 271 { 272 int ret; 273 int rv; 274 275 SCHPC_DEBUG0(D_ATTACH, "_init() installing module"); 276 277 ret = ddi_soft_state_init(&per_schpc_state, sizeof (schpc_t), 1); 278 if (ret != 0) { 279 return (ret); 280 } 281 282 /* 283 * Initialize Outgoing Mailbox. 284 */ 285 ret = mboxsc_init(KEY_PCSC, MBOXSC_MBOX_OUT, NULL); 286 287 if (ret != 0) { 288 ddi_soft_state_fini(&per_schpc_state); 289 return (ret); 290 } 291 292 ret = mboxsc_ctrl(KEY_PCSC, MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE, 293 (void *) &schpc_putmsg_timeout_range); 294 295 if (ret != 0) { 296 ddi_soft_state_fini(&per_schpc_state); 297 return (ret); 298 } 299 300 if (schpc_timeout_putmsg < schpc_putmsg_timeout_range.min_timeout) { 301 schpc_timeout_putmsg = schpc_putmsg_timeout_range.min_timeout; 302 cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n", 303 schpc_timeout_putmsg); 304 } 305 306 if (schpc_timeout_putmsg > schpc_putmsg_timeout_range.max_timeout) { 307 schpc_timeout_putmsg = schpc_putmsg_timeout_range.max_timeout; 308 cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n", 309 schpc_timeout_putmsg); 310 } 311 312 /* 313 * Create the schpc_event_taskq for MBOXSC_MSG_EVENT processing. 314 */ 315 schpc_event_taskq = taskq_create("schpc_event_taskq", 2, 316 minclsyspri, 4, 4, TASKQ_PREPOPULATE); 317 318 /* 319 * Initialize Incoming Mailbox. 320 * NOTE: the callback is null because the schpc_msg_thread will 321 * handle all incoming MBOXSC_MSG_EVENT and MBOXSC_MSG_REPLY 322 * messages. 323 */ 324 ret = mboxsc_init(KEY_SCPC, MBOXSC_MBOX_IN, NULL); 325 326 if (ret != 0) { 327 cmn_err(CE_WARN, "schpc: can not initialize KEY_SCPC as " 328 "MBOXSC_MBOX_IN"); 329 ddi_soft_state_fini(&per_schpc_state); 330 return (ret); 331 } 332 333 ret = mboxsc_ctrl(KEY_SCPC, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE, 334 (void *) &schpc_getmsg_timeout_range); 335 336 if (ret != 0) { 337 ddi_soft_state_fini(&per_schpc_state); 338 return (ret); 339 } 340 341 if (schpc_timeout_getmsg < schpc_getmsg_timeout_range.min_timeout) { 342 schpc_timeout_getmsg = schpc_getmsg_timeout_range.min_timeout; 343 cmn_err(CE_WARN, " schpc: resetting getmsg timeout to %ld\n", 344 schpc_timeout_getmsg); 345 } 346 347 if (schpc_timeout_getmsg > schpc_getmsg_timeout_range.max_timeout) { 348 schpc_timeout_getmsg = schpc_getmsg_timeout_range.max_timeout; 349 cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n", 350 schpc_timeout_putmsg); 351 } 352 353 if (schpc_timeout_event < schpc_getmsg_timeout_range.min_timeout) { 354 schpc_timeout_event = schpc_getmsg_timeout_range.min_timeout; 355 cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n", 356 schpc_timeout_event); 357 } 358 359 if (schpc_timeout_event > schpc_getmsg_timeout_range.max_timeout) { 360 schpc_timeout_event = schpc_getmsg_timeout_range.max_timeout; 361 cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n", 362 schpc_timeout_event); 363 } 364 365 ret = mod_install(&modlinkage); 366 if (ret != 0) { 367 if ((rv = mboxsc_fini(KEY_PCSC)) != 0) { 368 cmn_err(CE_WARN, "schpc: _init() - " 369 "mboxsc_fini(KEY_PCSC) failed: 0x%x", rv); 370 } 371 if ((rv = mboxsc_fini(KEY_SCPC)) != 0) { 372 cmn_err(CE_WARN, "schpc: _init() - " 373 "mboxsc_fini(KEY_SCPC) failed: 0x%x", rv); 374 } 375 taskq_destroy(schpc_event_taskq); 376 ddi_soft_state_fini(&per_schpc_state); 377 return (ret); 378 } 379 380 SCHPC_DEBUG0(D_ATTACH, "_init() module installed"); 381 382 /* 383 * Start the schpc_msg_thread to continuously monitor the 384 * MBOXSC_MBOX_IN mailbox for incoming MBOXSC_MSG_EVENTs and 385 * MBOXSC_MSG_REPLYs. 386 */ 387 mutex_init(&schpc_replylist_mutex, NULL, MUTEX_DRIVER, NULL); 388 (void) thread_create(NULL, 0, schpc_msg_thread, 389 NULL, 0, &p0, TS_RUN, minclsyspri); 390 391 SCHPC_DEBUG0(D_ATTACH, "_init() started schpc_msg_thread"); 392 393 return (ret); 394 } 395 396 int 397 _fini(void) 398 { 399 SCHPC_DEBUG0(D_ATTACH, "_fini()"); 400 401 return (DDI_FAILURE); 402 } 403 404 int 405 _info(struct modinfo *modinfop) 406 { 407 SCHPC_DEBUG0(D_ATTACH, "_info() called."); 408 409 return (mod_info(&modlinkage, modinfop)); 410 } 411 412 static int 413 schpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 414 { 415 int instance = ddi_get_instance(devi); 416 int rval; 417 418 SCHPC_DEBUG1(D_ATTACH, "attach(%x) ATTACH", instance); 419 420 switch (cmd) { 421 case DDI_ATTACH: 422 423 /* 424 * Allocate the soft state structure for this instance. 425 */ 426 rval = ddi_soft_state_zalloc(per_schpc_state, instance); 427 428 if (rval != DDI_SUCCESS) { 429 SCHPC_DEBUG1(D_ATTACH, 430 "schpc_attach(%x) Can not allocate " 431 "soft state structure", instance); 432 return (DDI_FAILURE); 433 } 434 435 schpc_p = (schpc_t *)ddi_get_soft_state(per_schpc_state, 436 instance); 437 438 if (schpc_p == NULL) { 439 return (DDI_FAILURE); 440 } 441 442 mutex_init(&schpc_p->schpc_mutex, NULL, MUTEX_DRIVER, NULL); 443 cv_init(&schpc_p->schpc_cv, NULL, CV_DRIVER, NULL); 444 445 /* 446 * Put schpc structure on global linked list. 447 */ 448 449 /* 450 * Initialize starting transaction ID. 451 */ 452 schpc_p->schpc_transid = 0; 453 454 schpc_p->schpc_number_of_slots = STARCAT_MAX_SLOTS; 455 456 SCHPC_DEBUG2(D_ATTACH, "schpc_attach(%x) slot-table property " 457 "describes %d slots", instance, 458 schpc_p->schpc_number_of_slots); 459 460 schpc_p->schpc_hotplugmodel = ddi_getprop(DDI_DEV_T_ANY, 461 devi, 0, "hot-plug-model", SCHPC_HOTPLUGTYPE_CPCIHOTPLUG); 462 463 SCHPC_DEBUG2(D_ATTACH, "attach(%x) ATTACH - Hot Plug Model=%x", 464 instance, schpc_p->schpc_hotplugmodel); 465 466 /* 467 * What type of hot plug do these slots support? The only 468 * types of slots we support is the cPCI Hot Plug Model 469 * and Not Hot Pluggable. 470 */ 471 if (schpc_p->schpc_hotplugmodel != 472 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) { 473 schpc_p->schpc_hotplugmodel = 474 SCHPC_HOTPLUGTYPE_NOTHOTPLUGGABLE; 475 } 476 477 schpc_p->schpc_slot = (schpc_slot_t *)kmem_zalloc((size_t) 478 (schpc_p->schpc_number_of_slots * sizeof (schpc_slot_t)), 479 KM_SLEEP); 480 481 schpc_p->schpc_devi = devi; 482 schpc_p->schpc_instance = instance; 483 484 /* 485 * Start thread to search the device tree and register 486 * all found pci slots. 487 */ 488 (void) thread_create(NULL, 0, schpc_register_all_slots, 489 (void *)schpc_p, 0, &p0, TS_RUN, minclsyspri); 490 491 break; 492 493 case DDI_PM_RESUME: 494 case DDI_RESUME: 495 return (DDI_SUCCESS); 496 default: 497 cmn_err(CE_WARN, "schpc%d: Cmd != DDI_ATTACH/DDI_RESUME", 498 instance); 499 500 return (DDI_FAILURE); 501 } 502 503 SCHPC_DEBUG1(D_ATTACH, 504 "schpc_attach(%x) Attach - DDI_SUCCESS", instance); 505 506 return (DDI_SUCCESS); 507 } 508 509 /*ARGSUSED*/ 510 static int 511 schpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 512 { 513 int instance = ddi_get_instance(devi); 514 515 SCHPC_DEBUG1(D_DETACH, "detach(%x) DETACH", instance); 516 517 return (DDI_FAILURE); 518 } 519 520 /*ARGSUSED*/ 521 static int 522 schpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 523 void **result) 524 { 525 int error; 526 527 switch (infocmd) { 528 case DDI_INFO_DEVT2DEVINFO: 529 *result = (void *)schpc_devi; 530 error = DDI_SUCCESS; 531 break; 532 case DDI_INFO_DEVT2INSTANCE: 533 *result = (void *)0; 534 error = DDI_SUCCESS; 535 break; 536 default: 537 error = DDI_FAILURE; 538 } 539 return (error); 540 } 541 542 /* 543 * schpc_connect() 544 * 545 * Called by Hot Plug Services to connect a slot to the bus. 546 */ 547 548 /*ARGSUSED*/ 549 static int 550 schpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 551 { 552 int rval; 553 int expander, board; 554 pci_setslot_t setslot; 555 pci_getslot_t getslot; 556 int slot; 557 558 SCHPC_DEBUG2(D_IOC_CONNECT, "schpc_connect( ops_arg=%p slot_hdl=%p)", 559 (void *)ops_arg, (void *)slot_hdl); 560 561 mutex_enter(&schpc_p->schpc_mutex); 562 563 slot = schpc_slot_get_index(schpc_p, slot_hdl); 564 565 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 566 SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect - HPC Not Inited"); 567 mutex_exit(&schpc_p->schpc_mutex); 568 return (HPC_ERR_FAILED); 569 } 570 571 /* 572 * Check to see if the slot is already connected. 573 */ 574 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED) { 575 mutex_exit(&schpc_p->schpc_mutex); 576 return (0); 577 } 578 579 /* 580 * Block if another thread is executing a HPC command. 581 */ 582 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 583 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 584 } 585 586 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 587 588 mutex_exit(&schpc_p->schpc_mutex); 589 590 expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 591 board = schpc_p->schpc_slot[slot].board; /* get board */ 592 593 SCHPC_DEBUG3(D_IOC_CONNECT, 594 "schpc_connect Expander=%x Board=%x Slot=%x", 595 expander, board, SCHPC_SLOT_NUM(slot)); 596 597 598 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_OCC_GOOD)) { 599 cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete " 600 "connection on Expander %d Board %d Slot %d - " 601 "Ap_Id=%s : Occupant is in failed state", 602 expander, board, SCHPC_SLOT_NUM(slot), 603 schpc_p->schpc_slot[slot].ap_id); 604 605 /* Fault LED should already be illuminated */ 606 607 goto failed; 608 } 609 610 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD)) { 611 cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete " 612 "connection on Expander %d Board %d Slot %d - " 613 "Ap_Id=%s : Receptacle is in failed state", 614 expander, board, SCHPC_SLOT_NUM(slot), 615 schpc_p->schpc_slot[slot].ap_id); 616 617 /* Fault LED should already be illuminated */ 618 619 goto failed; 620 } 621 622 rval = schpc_getslotstatus(expander, board, slot, &getslot); 623 624 if (rval) { 625 /* 626 * System Controller/Mailbox failure. 627 */ 628 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 629 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 630 "Communicate with System Controller", expander, board, 631 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 632 633 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 634 635 goto failed; 636 } 637 638 if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) { 639 640 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 641 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 642 "Read Slot Status", expander, board, 643 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 644 645 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 646 647 goto failed; 648 } 649 650 if (getslot.slot_empty) { 651 /* 652 * If the slot is empty - fail the connection request. 653 */ 654 goto failed; 655 } 656 657 SCHPC_DEBUG3(D_FREQCHG, "Slot %d - slot_freq_setting %d " 658 "slot_freq_cap %d", slot, getslot.slot_freq_setting, 659 getslot.slot_freq_cap); 660 661 if (!schpc_is_freq_switchable(slot) && 662 (getslot.slot_freq_setting > getslot.slot_freq_cap)) { 663 664 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 665 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 666 "Bus Speed Mismatch", expander, 667 board, SCHPC_SLOT_NUM(slot), 668 schpc_p->schpc_slot[slot].ap_id); 669 670 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 671 672 goto failed; 673 } 674 675 if (schpc_is_leaf_reset_required(slot) && 676 (schpc_p->schpc_slot[slot].saved_regs == NULL)) { 677 678 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Save Regs before connect", 679 slot); 680 681 /* 682 * A prior disconnect had not saved off the leaf so lets 683 * save it now. This is probably due to the domain being 684 * booted with a slot with no cassette. 685 */ 686 if (schpc_save_leaf(slot) != 0) { 687 cmn_err(CE_WARN, "schpc - Unable to save leaf regs on " 688 689 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ", 690 expander, board, slot & 3, 691 schpc_p->schpc_slot[slot].ap_id); 692 693 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 694 695 goto failed; 696 } 697 } 698 699 /* 700 * Initialize Set Slot Command. 701 */ 702 schpc_init_setslot_message(&setslot); 703 704 setslot.slot_power_on = PCIMSG_ON; /* Turn slot power on */ 705 706 setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash Fault LED */ 707 708 rval = schpc_setslotstatus(expander, board, slot, &setslot); 709 710 if (rval != 0) { 711 /* 712 * System Controller/Mailbox failure. 713 */ 714 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 715 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 716 "Communicate with System Controller", expander, board, 717 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 718 719 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 720 721 goto failed; 722 } 723 724 if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) { 725 726 /* 727 * The Request was successfully completed. 728 */ 729 730 SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect() - setslotstatus " 731 "succeeded"); 732 733 /* 734 * Need to check HEALTHY# signal. 735 */ 736 rval = schpc_getslotstatus(expander, board, slot, &getslot); 737 738 if (rval) { 739 /* 740 * System Controller/Mailbox failure. 741 */ 742 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 743 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 744 "Unable to Communicate with System Controller", 745 expander, board, SCHPC_SLOT_NUM(slot), 746 schpc_p->schpc_slot[slot].ap_id); 747 748 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 749 750 goto failed; 751 } 752 753 if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) { 754 755 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 756 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 757 "Unable to Read Slot Status", expander, board, 758 SCHPC_SLOT_NUM(slot), 759 schpc_p->schpc_slot[slot].ap_id); 760 761 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 762 763 goto failed; 764 } 765 766 if ((getslot.slot_powergood != PCIMSG_ON) || 767 (getslot.slot_powerfault == PCIMSG_ON)) { 768 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 769 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 770 "Power failure detected", expander, board, 771 SCHPC_SLOT_NUM(slot), 772 schpc_p->schpc_slot[slot].ap_id); 773 774 /* 775 * Initialize Set Slot Command. 776 */ 777 schpc_init_setslot_message(&setslot); 778 779 /* 780 * Turn slot power off. 781 */ 782 setslot.slot_power_off = PCIMSG_ON; 783 784 (void) schpc_setslotstatus(expander, board, 785 slot, &setslot); 786 787 schpc_setslotled(expander, board, slot, 788 (SERVICE_LED_ON | FAULT_LED_ON)); 789 790 goto failed; 791 } 792 793 if (!getslot.slot_HEALTHY) { 794 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 795 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 796 "Adapter did not assert HEALTHY#", expander, board, 797 SCHPC_SLOT_NUM(slot), 798 schpc_p->schpc_slot[slot].ap_id); 799 800 /* 801 * Initialize Set Slot Command. 802 */ 803 schpc_init_setslot_message(&setslot); 804 805 /* 806 * Turn slot power off. 807 */ 808 setslot.slot_power_off = PCIMSG_ON; 809 810 (void) schpc_setslotstatus(expander, board, slot, 811 &setslot); 812 813 schpc_setslotled(expander, board, slot, 814 (SERVICE_LED_ON | FAULT_LED_ON)); 815 816 goto failed; 817 } 818 819 /* 820 * Initialize Set Slot Command. 821 */ 822 schpc_init_setslot_message(&setslot); 823 824 /* 825 * Start monitoring ENUM# and HEALTHY# 826 */ 827 setslot.slot_enable_HEALTHY = PCIMSG_ON; 828 setslot.slot_enable_ENUM = PCIMSG_ON; 829 830 rval = schpc_setslotstatus(expander, board, slot, &setslot); 831 832 if (rval != 0) { 833 /* 834 * System Controller/Mailbox failure. 835 */ 836 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 837 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 838 "Unable to Communicate with System Controller", 839 expander, board, SCHPC_SLOT_NUM(slot), 840 schpc_p->schpc_slot[slot].ap_id); 841 842 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 843 844 goto failed; 845 } 846 if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) { 847 848 int freq; 849 find_dev_t find_dev; 850 851 /* 852 * The Request was successfully completed. 853 */ 854 855 SCHPC_DEBUG0(D_IOC_CONNECT, 856 "schpc_connect() - setslotstatus succeeded"); 857 858 schpc_p->schpc_slot[slot].state |= 859 SCHPC_SLOTSTATE_CONNECTED; 860 861 schpc_setslotled(expander, board, slot, 862 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_OFF)); 863 864 find_dev.cname = schpc_p->schpc_slot[slot].nexus_path; 865 find_dev.caddr = (char *)kmem_alloc(MAXPATHLEN, 866 KM_SLEEP); 867 find_dev.dip = NULL; 868 869 /* root node doesn't have to be held */ 870 ddi_walk_devs(ddi_root_node(), schpc_find_dip, 871 &find_dev); 872 if (find_dev.dip != NULL) { 873 /* 874 * Update the clock-frequency property to 875 * reflect the new slot-frequency. 876 */ 877 freq = schpc_slot_freq(&getslot); 878 SCHPC_DEBUG2(D_FREQCHG, 879 "schpc_connect: updating dip=%p freq=%dHZ", 880 (void *)find_dev.dip, freq); 881 if (ndi_prop_update_int(DDI_DEV_T_NONE, 882 find_dev.dip, "clock-frequency", freq) 883 != DDI_SUCCESS) { 884 cmn_err(CE_WARN, 885 "schpc: - failed to update " 886 "clock-frequency property for %s", 887 find_dev.cname); 888 } 889 ndi_rele_devi(find_dev.dip); 890 } else { 891 cmn_err(CE_WARN, 892 "schpc: couldn't find dip for %s ", 893 find_dev.cname); 894 } 895 kmem_free(find_dev.caddr, MAXPATHLEN); 896 897 mutex_enter(&schpc_p->schpc_mutex); 898 schpc_p->schpc_slot[slot].state &= 899 ~SCHPC_SLOTSTATE_EXECUTING; 900 901 /* 902 * If leaf registers were saved off, then they 903 * need to be restored. 904 */ 905 schpc_restore_leaf(slot); 906 907 /* 908 * Since the device saw a PCI Reset, we need to 909 * wait 2^25 clock cycles before the first 910 * Configuration access. The worst case is 33MHz, 911 * which is a 1 second wait. 912 */ 913 drv_usecwait(1000000); 914 915 cv_signal(&schpc_p->schpc_cv); 916 mutex_exit(&schpc_p->schpc_mutex); 917 918 return (0); 919 } else { 920 /* 921 * The System Controller Rejected the 922 * connection request. 923 */ 924 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed " 925 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s :" 926 "System Controller failed connection request", 927 expander, board, SCHPC_SLOT_NUM(slot), 928 schpc_p->schpc_slot[slot].ap_id); 929 930 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 931 932 goto failed; 933 } 934 } 935 936 /* 937 * The System Controller Rejected the connection request. 938 */ 939 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on " 940 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller " 941 "failed connection request", expander, board, SCHPC_SLOT_NUM(slot), 942 schpc_p->schpc_slot[slot].ap_id); 943 944 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 945 946 failed: 947 mutex_enter(&schpc_p->schpc_mutex); 948 schpc_p->schpc_slot[slot].state &= 949 ~SCHPC_SLOTSTATE_EXECUTING; 950 cv_signal(&schpc_p->schpc_cv); 951 mutex_exit(&schpc_p->schpc_mutex); 952 953 return (HPC_ERR_FAILED); 954 } 955 956 /* 957 * schpc_disconnect() 958 * 959 * Called by Hot Plug Services to disconnect a slot to the bus. 960 */ 961 962 /*ARGSUSED*/ 963 static int 964 schpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, 965 uint_t flags) 966 { 967 int rval; 968 int expander, board, slot; 969 pci_setslot_t setslot; 970 971 SCHPC_DEBUG2(D_IOC_CONNECT, 972 "schpc_disconnect( ops_arg=%p slot_hdl=%p)", (void *)ops_arg, 973 slot_hdl); 974 975 mutex_enter(&schpc_p->schpc_mutex); 976 977 slot = schpc_slot_get_index(schpc_p, slot_hdl); 978 979 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 980 SCHPC_DEBUG0(D_IOC_CONNECT, 981 "schpc_disconnect - HPC Not Inited"); 982 mutex_exit(&schpc_p->schpc_mutex); 983 return (HPC_ERR_FAILED); 984 } 985 986 /* 987 * Check to see if we are already disconnected. 988 */ 989 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) { 990 mutex_exit(&schpc_p->schpc_mutex); 991 return (0); 992 } 993 994 /* 995 * Block if another thread is executing a HPC command. 996 */ 997 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 998 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 999 } 1000 1001 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 1002 1003 mutex_exit(&schpc_p->schpc_mutex); 1004 1005 expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 1006 board = schpc_p->schpc_slot[slot].board; /* get board */ 1007 1008 /* 1009 * If a leaf reset is going to be asserted due to a mode/freq. 1010 * change, then the leaf registers of the XMITS bridge will need 1011 * to be saved off prior to the connect. 1012 */ 1013 if (schpc_is_leaf_reset_required(slot)) { 1014 if (schpc_save_leaf(slot) != 0) { 1015 1016 cmn_err(CE_WARN, "schpc - Unable to save leaf regs on " 1017 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ", 1018 expander, board, slot & 3, 1019 schpc_p->schpc_slot[slot].ap_id); 1020 1021 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 1022 1023 goto failed; 1024 } 1025 } 1026 1027 /* 1028 * Initialize Set Slot Command. 1029 */ 1030 schpc_init_setslot_message(&setslot); 1031 1032 setslot.slot_power_off = PCIMSG_ON; /* Turn Power Off */ 1033 1034 setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */ 1035 1036 setslot.slot_disable_ENUM = PCIMSG_ON; /* Mask the ENUM# signal */ 1037 setslot.slot_disable_HEALTHY = PCIMSG_ON; /* Mask the HEALTHY# sig */ 1038 1039 rval = schpc_setslotstatus(expander, board, slot, &setslot); 1040 1041 SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - " 1042 "setslotstatus returned 0x%x", rval); 1043 1044 if (rval != 0) { 1045 /* 1046 * System Controller/Mailbox failure. 1047 */ 1048 cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on " 1049 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 1050 "Communicate with System Controller", expander, board, 1051 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 1052 1053 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 1054 1055 goto failed; 1056 } 1057 1058 SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - " 1059 "slot_replystatus returned 0x%x", setslot.slot_replystatus); 1060 1061 if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) { 1062 1063 /* 1064 * The Request was successfully completed. 1065 */ 1066 schpc_p->schpc_slot[slot].state &= 1067 ~SCHPC_SLOTSTATE_CONNECTED; 1068 1069 schpc_setslotled(expander, board, slot, 1070 (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF)); 1071 1072 SCHPC_DEBUG0(D_IOC_CONNECT, 1073 "schpc_disconnect() - setslotstatus succeeded"); 1074 1075 mutex_enter(&schpc_p->schpc_mutex); 1076 schpc_p->schpc_slot[slot].state &= 1077 ~SCHPC_SLOTSTATE_EXECUTING; 1078 cv_signal(&schpc_p->schpc_cv); 1079 mutex_exit(&schpc_p->schpc_mutex); 1080 1081 return (0); 1082 } 1083 /* 1084 * System Controller/Mailbox failure. 1085 */ 1086 cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on " 1087 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller " 1088 "failed disconnection request", expander, board, 1089 SCHPC_SLOT_NUM(slot), 1090 schpc_p->schpc_slot[slot].ap_id); 1091 1092 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 1093 1094 failed: 1095 schpc_restore_leaf(slot); 1096 mutex_enter(&schpc_p->schpc_mutex); 1097 schpc_p->schpc_slot[slot].state &= 1098 ~SCHPC_SLOTSTATE_EXECUTING; 1099 cv_signal(&schpc_p->schpc_cv); 1100 mutex_exit(&schpc_p->schpc_mutex); 1101 1102 return (HPC_ERR_FAILED); 1103 } 1104 1105 /* 1106 * schpc_cpci_control 1107 * 1108 * Called by Hot Plug Services to perform a attachment point specific 1109 * on a Hot Pluggable Compact PCI Slot. 1110 */ 1111 /*ARGSUSED*/ 1112 static int 1113 schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 1114 caddr_t arg) 1115 { 1116 int rval; 1117 int expander, board, slot; 1118 pci_setslot_t setslot; 1119 pci_getslot_t slotstatus; 1120 hpc_led_info_t *hpc_led_info; 1121 1122 SCHPC_DEBUG3(D_IOC_CONTROL, 1123 "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)", 1124 (void *)ops_arg, (void *)slot_hdl, request); 1125 1126 mutex_enter(&schpc_p->schpc_mutex); 1127 1128 slot = schpc_slot_get_index(schpc_p, slot_hdl); 1129 1130 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 1131 SCHPC_DEBUG0(D_IOC_CONNECT, 1132 "schpc_disconnect - HPC Not Inited"); 1133 mutex_exit(&schpc_p->schpc_mutex); 1134 return (HPC_ERR_FAILED); 1135 } 1136 1137 /* 1138 * Block if another thread is executing a HPC command. 1139 */ 1140 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 1141 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 1142 } 1143 1144 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 1145 1146 mutex_exit(&schpc_p->schpc_mutex); 1147 1148 expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 1149 board = schpc_p->schpc_slot[slot].board; /* get board */ 1150 1151 /* 1152 * Initialize Set Slot Command. 1153 */ 1154 schpc_init_setslot_message(&setslot); 1155 1156 /* 1157 * Initialize LED to last know state. 1158 */ 1159 switch (schpc_p->schpc_slot[slot].led.led_power) { 1160 case LED_ON: 1161 setslot.slot_led_power = PCIMSG_LED_ON; 1162 break; 1163 case LED_OFF: 1164 setslot.slot_led_power = PCIMSG_LED_OFF; 1165 break; 1166 case LED_FLASH: 1167 setslot.slot_led_power = PCIMSG_LED_FLASH; 1168 break; 1169 } 1170 1171 switch (schpc_p->schpc_slot[slot].led.led_service) { 1172 case LED_ON: 1173 setslot.slot_led_service = PCIMSG_LED_ON; 1174 break; 1175 case LED_OFF: 1176 setslot.slot_led_service = PCIMSG_LED_OFF; 1177 break; 1178 case LED_FLASH: 1179 setslot.slot_led_service = PCIMSG_LED_FLASH; 1180 break; 1181 } 1182 1183 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1184 case LED_ON: 1185 setslot.slot_led_fault = PCIMSG_LED_ON; 1186 break; 1187 case LED_OFF: 1188 setslot.slot_led_fault = PCIMSG_LED_OFF; 1189 break; 1190 case LED_FLASH: 1191 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1192 break; 1193 } 1194 1195 switch (request) { 1196 1197 case HPC_CTRL_GET_LED_STATE: 1198 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1199 "HPC_CTRL_GET_LED_STATE"); 1200 hpc_led_info = (hpc_led_info_t *)arg; 1201 1202 switch (hpc_led_info->led) { 1203 case HPC_FAULT_LED: 1204 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1205 case LED_OFF: 1206 hpc_led_info->state = HPC_LED_OFF; 1207 break; 1208 case LED_ON: 1209 hpc_led_info->state = HPC_LED_ON; 1210 break; 1211 case LED_FLASH: 1212 hpc_led_info->state = HPC_LED_BLINK; 1213 break; 1214 } 1215 break; 1216 1217 case HPC_POWER_LED: 1218 switch (schpc_p->schpc_slot[slot].led.led_power) { 1219 case LED_OFF: 1220 hpc_led_info->state = HPC_LED_OFF; 1221 break; 1222 case LED_ON: 1223 hpc_led_info->state = HPC_LED_ON; 1224 break; 1225 case LED_FLASH: 1226 hpc_led_info->state = HPC_LED_BLINK; 1227 break; 1228 } 1229 break; 1230 case HPC_ATTN_LED: 1231 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1232 case LED_OFF: 1233 hpc_led_info->state = HPC_LED_OFF; 1234 break; 1235 case LED_ON: 1236 hpc_led_info->state = HPC_LED_OFF; 1237 break; 1238 case LED_FLASH: 1239 hpc_led_info->state = HPC_LED_ON; 1240 break; 1241 } 1242 break; 1243 case HPC_ACTIVE_LED: 1244 switch (schpc_p->schpc_slot[slot].led.led_service) { 1245 case LED_OFF: 1246 hpc_led_info->state = HPC_LED_OFF; 1247 break; 1248 case LED_ON: 1249 hpc_led_info->state = HPC_LED_ON; 1250 break; 1251 case LED_FLASH: 1252 hpc_led_info->state = HPC_LED_BLINK; 1253 break; 1254 } 1255 break; 1256 default: 1257 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 1258 "Invalid LED %x", hpc_led_info->led); 1259 1260 mutex_enter(&schpc_p->schpc_mutex); 1261 schpc_p->schpc_slot[slot].state &= 1262 ~SCHPC_SLOTSTATE_EXECUTING; 1263 cv_signal(&schpc_p->schpc_cv); 1264 mutex_exit(&schpc_p->schpc_mutex); 1265 1266 return (HPC_ERR_FAILED); 1267 } 1268 1269 mutex_enter(&schpc_p->schpc_mutex); 1270 schpc_p->schpc_slot[slot].state &= 1271 ~SCHPC_SLOTSTATE_EXECUTING; 1272 cv_signal(&schpc_p->schpc_cv); 1273 mutex_exit(&schpc_p->schpc_mutex); 1274 1275 return (0); 1276 1277 case HPC_CTRL_SET_LED_STATE: 1278 hpc_led_info = (hpc_led_info_t *)arg; 1279 1280 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 1281 "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", 1282 (void *)hpc_led_info); 1283 1284 switch (hpc_led_info->led) { 1285 case HPC_FAULT_LED: 1286 switch (hpc_led_info->state) { 1287 case HPC_LED_OFF: 1288 schpc_p->schpc_slot[slot].led.led_fault = 1289 LED_OFF; 1290 setslot.slot_led_fault = PCIMSG_LED_OFF; 1291 break; 1292 case HPC_LED_ON: 1293 schpc_p->schpc_slot[slot].led.led_fault = 1294 LED_ON; 1295 setslot.slot_led_fault = PCIMSG_LED_ON; 1296 break; 1297 case HPC_LED_BLINK: 1298 schpc_p->schpc_slot[slot].led.led_fault = 1299 LED_FLASH; 1300 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1301 break; 1302 } 1303 break; 1304 case HPC_POWER_LED: 1305 switch (hpc_led_info->state) { 1306 case HPC_LED_OFF: 1307 schpc_p->schpc_slot[slot].led.led_power = 1308 LED_OFF; 1309 setslot.slot_led_power = PCIMSG_LED_OFF; 1310 break; 1311 case HPC_LED_ON: 1312 schpc_p->schpc_slot[slot].led.led_power = 1313 LED_ON; 1314 setslot.slot_led_power = PCIMSG_LED_ON; 1315 break; 1316 case HPC_LED_BLINK: 1317 schpc_p->schpc_slot[slot].led.led_power = 1318 LED_FLASH; 1319 setslot.slot_led_power = PCIMSG_LED_FLASH; 1320 break; 1321 } 1322 break; 1323 case HPC_ATTN_LED: 1324 switch (hpc_led_info->state) { 1325 case HPC_LED_OFF: 1326 schpc_p->schpc_slot[slot].led.led_fault = 1327 LED_OFF; 1328 setslot.slot_led_fault = PCIMSG_LED_OFF; 1329 break; 1330 case HPC_LED_ON: 1331 schpc_p->schpc_slot[slot].led.led_fault = 1332 LED_FLASH; 1333 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1334 break; 1335 case HPC_LED_BLINK: 1336 schpc_p->schpc_slot[slot].led.led_fault = 1337 LED_FLASH; 1338 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1339 break; 1340 } 1341 break; 1342 case HPC_ACTIVE_LED: 1343 switch (hpc_led_info->state) { 1344 case HPC_LED_OFF: 1345 schpc_p->schpc_slot[slot].led.led_service = 1346 LED_OFF; 1347 setslot.slot_led_service = PCIMSG_LED_OFF; 1348 break; 1349 case HPC_LED_ON: 1350 schpc_p->schpc_slot[slot].led.led_service = 1351 LED_ON; 1352 setslot.slot_led_service = PCIMSG_LED_ON; 1353 break; 1354 case HPC_LED_BLINK: 1355 schpc_p->schpc_slot[slot].led.led_service = 1356 LED_FLASH; 1357 setslot.slot_led_service = PCIMSG_LED_FLASH; 1358 break; 1359 } 1360 break; 1361 default: 1362 mutex_enter(&schpc_p->schpc_mutex); 1363 schpc_p->schpc_slot[slot].state &= 1364 ~SCHPC_SLOTSTATE_EXECUTING; 1365 cv_signal(&schpc_p->schpc_cv); 1366 mutex_exit(&schpc_p->schpc_mutex); 1367 1368 return (0); 1369 } 1370 1371 (void) schpc_setslotstatus(expander, board, slot, &setslot); 1372 1373 mutex_enter(&schpc_p->schpc_mutex); 1374 schpc_p->schpc_slot[slot].state &= 1375 ~SCHPC_SLOTSTATE_EXECUTING; 1376 cv_signal(&schpc_p->schpc_cv); 1377 mutex_exit(&schpc_p->schpc_mutex); 1378 1379 return (0); 1380 1381 case HPC_CTRL_GET_SLOT_STATE: { 1382 hpc_slot_state_t *hpc_slot_state; 1383 1384 hpc_slot_state = (hpc_slot_state_t *)arg; 1385 1386 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 1387 "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p", 1388 (void *)hpc_slot_state); 1389 1390 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 1391 1392 if (!rval) { 1393 1394 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 1395 return (HPC_ERR_FAILED); 1396 } 1397 1398 if (slotstatus.slot_empty == PCIMSG_ON) { 1399 *hpc_slot_state = HPC_SLOT_EMPTY; 1400 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty"); 1401 } else if (slotstatus.slot_power_on == PCIMSG_ON) { 1402 *hpc_slot_state = HPC_SLOT_CONNECTED; 1403 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected"); 1404 schpc_p->schpc_slot[slot].state |= 1405 SCHPC_SLOTSTATE_CONNECTED; 1406 } else { 1407 *hpc_slot_state = HPC_SLOT_DISCONNECTED; 1408 SCHPC_DEBUG0(D_IOC_CONTROL, 1409 "Slot Disconnected"); 1410 schpc_p->schpc_slot[slot].state &= 1411 ~SCHPC_SLOTSTATE_CONNECTED; 1412 } 1413 } else { 1414 SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed"); 1415 1416 mutex_enter(&schpc_p->schpc_mutex); 1417 schpc_p->schpc_slot[slot].state &= 1418 ~SCHPC_SLOTSTATE_EXECUTING; 1419 cv_signal(&schpc_p->schpc_cv); 1420 mutex_exit(&schpc_p->schpc_mutex); 1421 1422 return (HPC_ERR_FAILED); 1423 } 1424 1425 mutex_enter(&schpc_p->schpc_mutex); 1426 schpc_p->schpc_slot[slot].state &= 1427 ~SCHPC_SLOTSTATE_EXECUTING; 1428 cv_signal(&schpc_p->schpc_cv); 1429 mutex_exit(&schpc_p->schpc_mutex); 1430 1431 return (0); 1432 } 1433 case HPC_CTRL_GET_BOARD_TYPE: { 1434 hpc_board_type_t *hpc_board_type; 1435 1436 hpc_board_type = (hpc_board_type_t *)arg; 1437 1438 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1439 "HPC_CTRL_GET_BOARD_TYPE"); 1440 1441 /* 1442 * The HPC driver does not know what board type 1443 * is plugged in. 1444 */ 1445 *hpc_board_type = HPC_BOARD_CPCI_HS; 1446 1447 mutex_enter(&schpc_p->schpc_mutex); 1448 schpc_p->schpc_slot[slot].state &= 1449 ~SCHPC_SLOTSTATE_EXECUTING; 1450 cv_signal(&schpc_p->schpc_cv); 1451 mutex_exit(&schpc_p->schpc_mutex); 1452 1453 return (0); 1454 1455 } 1456 case HPC_CTRL_DEV_CONFIGURED: 1457 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1458 "HPC_CTRL_DEV_CONFIGURED"); 1459 1460 mutex_enter(&schpc_p->schpc_mutex); 1461 schpc_p->schpc_slot[slot].state &= 1462 ~SCHPC_SLOTSTATE_EXECUTING; 1463 cv_signal(&schpc_p->schpc_cv); 1464 mutex_exit(&schpc_p->schpc_mutex); 1465 1466 return (0); 1467 1468 case HPC_CTRL_DEV_UNCONFIGURED: 1469 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1470 "HPC_CTRL_DEV_UNCONFIGURED"); 1471 1472 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) { 1473 /* 1474 * When the occupant is unconfigured, power 1475 * down the slot. 1476 */ 1477 rval = schpc_disconnect((caddr_t)schpc_p, 1478 schpc_p->schpc_slot[slot].slot_handle, 1479 0, 0); 1480 1481 schpc_p->schpc_slot[slot].state &= 1482 ~SCHPC_SLOTSTATE_ENUM; 1483 } 1484 1485 mutex_enter(&schpc_p->schpc_mutex); 1486 schpc_p->schpc_slot[slot].state &= 1487 ~SCHPC_SLOTSTATE_EXECUTING; 1488 cv_signal(&schpc_p->schpc_cv); 1489 mutex_exit(&schpc_p->schpc_mutex); 1490 1491 return (0); 1492 1493 case HPC_CTRL_ENABLE_AUTOCFG: 1494 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1495 "HPC_CTRL_ENABLE_AUTOCFG"); 1496 1497 schpc_p->schpc_slot[slot].state |= 1498 SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1499 1500 mutex_enter(&schpc_p->schpc_mutex); 1501 schpc_p->schpc_slot[slot].state &= 1502 ~SCHPC_SLOTSTATE_EXECUTING; 1503 cv_signal(&schpc_p->schpc_cv); 1504 mutex_exit(&schpc_p->schpc_mutex); 1505 1506 return (0); 1507 1508 case HPC_CTRL_DISABLE_AUTOCFG: 1509 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1510 "HPC_CTRL_DISABLE_AUTOCFG"); 1511 schpc_p->schpc_slot[slot].state &= 1512 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1513 1514 mutex_enter(&schpc_p->schpc_mutex); 1515 schpc_p->schpc_slot[slot].state &= 1516 ~SCHPC_SLOTSTATE_EXECUTING; 1517 cv_signal(&schpc_p->schpc_cv); 1518 mutex_exit(&schpc_p->schpc_mutex); 1519 1520 return (0); 1521 1522 case HPC_CTRL_DISABLE_ENUM: 1523 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1524 "HPC_CTRL_DISABLE_ENUM"); 1525 1526 setslot.slot_disable_ENUM = PCIMSG_ON; 1527 1528 rval = schpc_setslotstatus(expander, board, slot, &setslot); 1529 1530 if (rval) 1531 rval = HPC_ERR_FAILED; 1532 1533 mutex_enter(&schpc_p->schpc_mutex); 1534 schpc_p->schpc_slot[slot].state &= 1535 ~SCHPC_SLOTSTATE_EXECUTING; 1536 cv_signal(&schpc_p->schpc_cv); 1537 mutex_exit(&schpc_p->schpc_mutex); 1538 1539 return (rval); 1540 1541 case HPC_CTRL_ENABLE_ENUM: 1542 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1543 "HPC_CTRL_ENABLE_ENUM"); 1544 1545 setslot.slot_enable_ENUM = PCIMSG_ON; 1546 1547 rval = schpc_setslotstatus(expander, board, slot, &setslot); 1548 1549 if (rval) 1550 rval = HPC_ERR_FAILED; 1551 1552 mutex_enter(&schpc_p->schpc_mutex); 1553 schpc_p->schpc_slot[slot].state &= 1554 ~SCHPC_SLOTSTATE_EXECUTING; 1555 cv_signal(&schpc_p->schpc_cv); 1556 mutex_exit(&schpc_p->schpc_mutex); 1557 1558 return (rval); 1559 1560 default: 1561 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1562 "****NOT SUPPORTED CONTROL CMD"); 1563 1564 mutex_enter(&schpc_p->schpc_mutex); 1565 schpc_p->schpc_slot[slot].state &= 1566 ~SCHPC_SLOTSTATE_EXECUTING; 1567 cv_signal(&schpc_p->schpc_cv); 1568 mutex_exit(&schpc_p->schpc_mutex); 1569 1570 return (HPC_ERR_NOTSUPPORTED); 1571 } 1572 } 1573 1574 /* 1575 * schpc_pci_control 1576 * 1577 * Called by Hot Plug Services to perform a attachment point specific 1578 * on a Hot Pluggable Standard PCI Slot. 1579 */ 1580 /*ARGSUSED*/ 1581 static int 1582 schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 1583 caddr_t arg) 1584 { 1585 int rval; 1586 int expander, board, slot; 1587 pci_setslot_t setslot; 1588 pci_getslot_t slotstatus; 1589 hpc_led_info_t *hpc_led_info; 1590 1591 SCHPC_DEBUG3(D_IOC_CONTROL, 1592 "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)", 1593 (void *)ops_arg, (void *)slot_hdl, request); 1594 1595 mutex_enter(&schpc_p->schpc_mutex); 1596 1597 slot = schpc_slot_get_index(schpc_p, slot_hdl); 1598 1599 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 1600 SCHPC_DEBUG0(D_IOC_CONNECT, 1601 "schpc_disconnect - HPC Not Inited"); 1602 mutex_exit(&schpc_p->schpc_mutex); 1603 return (HPC_ERR_FAILED); 1604 } 1605 1606 /* 1607 * Block if another thread is executing a HPC command. 1608 */ 1609 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 1610 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 1611 } 1612 1613 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 1614 1615 mutex_exit(&schpc_p->schpc_mutex); 1616 1617 expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 1618 board = schpc_p->schpc_slot[slot].board; /* get board */ 1619 1620 /* 1621 * Initialize Set Slot Command. 1622 */ 1623 schpc_init_setslot_message(&setslot); 1624 1625 /* 1626 * Initialize LED to last know state. 1627 */ 1628 switch (schpc_p->schpc_slot[slot].led.led_power) { 1629 case LED_ON: 1630 setslot.slot_led_power = PCIMSG_LED_ON; 1631 break; 1632 case LED_OFF: 1633 setslot.slot_led_power = PCIMSG_LED_OFF; 1634 break; 1635 case LED_FLASH: 1636 setslot.slot_led_power = PCIMSG_LED_FLASH; 1637 break; 1638 } 1639 1640 switch (schpc_p->schpc_slot[slot].led.led_service) { 1641 case LED_ON: 1642 setslot.slot_led_service = PCIMSG_LED_ON; 1643 break; 1644 case LED_OFF: 1645 setslot.slot_led_service = PCIMSG_LED_OFF; 1646 break; 1647 case LED_FLASH: 1648 setslot.slot_led_service = PCIMSG_LED_FLASH; 1649 break; 1650 } 1651 1652 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1653 case LED_ON: 1654 setslot.slot_led_fault = PCIMSG_LED_ON; 1655 break; 1656 case LED_OFF: 1657 setslot.slot_led_fault = PCIMSG_LED_OFF; 1658 break; 1659 case LED_FLASH: 1660 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1661 break; 1662 } 1663 1664 switch (request) { 1665 1666 1667 case HPC_CTRL_GET_SLOT_STATE: { 1668 hpc_slot_state_t *hpc_slot_state; 1669 1670 hpc_slot_state = (hpc_slot_state_t *)arg; 1671 1672 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 1673 "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p", 1674 (void *)hpc_slot_state); 1675 1676 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 1677 1678 if (!rval) { 1679 1680 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 1681 1682 mutex_enter(&schpc_p->schpc_mutex); 1683 schpc_p->schpc_slot[slot].state &= 1684 ~SCHPC_SLOTSTATE_EXECUTING; 1685 cv_signal(&schpc_p->schpc_cv); 1686 mutex_exit(&schpc_p->schpc_mutex); 1687 1688 return (HPC_ERR_FAILED); 1689 } 1690 1691 if (slotstatus.slot_empty == PCIMSG_ON) { 1692 *hpc_slot_state = HPC_SLOT_EMPTY; 1693 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty"); 1694 } else if (slotstatus.slot_power_on == PCIMSG_ON) { 1695 *hpc_slot_state = HPC_SLOT_CONNECTED; 1696 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected"); 1697 schpc_p->schpc_slot[slot].state |= 1698 SCHPC_SLOTSTATE_CONNECTED; 1699 } else { 1700 *hpc_slot_state = HPC_SLOT_DISCONNECTED; 1701 SCHPC_DEBUG0(D_IOC_CONTROL, 1702 "Slot Disconnected"); 1703 schpc_p->schpc_slot[slot].state &= 1704 ~SCHPC_SLOTSTATE_CONNECTED; 1705 } 1706 } else { 1707 SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed"); 1708 1709 mutex_enter(&schpc_p->schpc_mutex); 1710 schpc_p->schpc_slot[slot].state &= 1711 ~SCHPC_SLOTSTATE_EXECUTING; 1712 cv_signal(&schpc_p->schpc_cv); 1713 mutex_exit(&schpc_p->schpc_mutex); 1714 1715 return (HPC_ERR_FAILED); 1716 } 1717 1718 mutex_enter(&schpc_p->schpc_mutex); 1719 schpc_p->schpc_slot[slot].state &= 1720 ~SCHPC_SLOTSTATE_EXECUTING; 1721 cv_signal(&schpc_p->schpc_cv); 1722 mutex_exit(&schpc_p->schpc_mutex); 1723 1724 return (0); 1725 } 1726 case HPC_CTRL_GET_BOARD_TYPE: { 1727 hpc_board_type_t *hpc_board_type; 1728 1729 hpc_board_type = (hpc_board_type_t *)arg; 1730 1731 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1732 "HPC_CTRL_GET_BOARD_TYPE"); 1733 1734 1735 /* 1736 * The HPC driver does not know what board type 1737 * is plugged in. 1738 */ 1739 *hpc_board_type = HPC_BOARD_PCI_HOTPLUG; 1740 1741 mutex_enter(&schpc_p->schpc_mutex); 1742 schpc_p->schpc_slot[slot].state &= 1743 ~SCHPC_SLOTSTATE_EXECUTING; 1744 cv_signal(&schpc_p->schpc_cv); 1745 mutex_exit(&schpc_p->schpc_mutex); 1746 1747 return (0); 1748 1749 } 1750 case HPC_CTRL_DEV_UNCONFIG_START: 1751 case HPC_CTRL_DEV_CONFIG_START: 1752 case HPC_CTRL_DEV_CONFIGURED: 1753 case HPC_CTRL_DEV_UNCONFIGURED: 1754 mutex_enter(&schpc_p->schpc_mutex); 1755 schpc_p->schpc_slot[slot].state &= 1756 ~SCHPC_SLOTSTATE_EXECUTING; 1757 cv_signal(&schpc_p->schpc_cv); 1758 mutex_exit(&schpc_p->schpc_mutex); 1759 1760 return (0); 1761 1762 case HPC_CTRL_GET_LED_STATE: 1763 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1764 "HPC_CTRL_GET_LED_STATE"); 1765 hpc_led_info = (hpc_led_info_t *)arg; 1766 1767 switch (hpc_led_info->led) { 1768 case HPC_FAULT_LED: 1769 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1770 case LED_OFF: 1771 hpc_led_info->state = HPC_LED_OFF; 1772 break; 1773 case LED_ON: 1774 hpc_led_info->state = HPC_LED_ON; 1775 break; 1776 case LED_FLASH: 1777 hpc_led_info->state = HPC_LED_BLINK; 1778 break; 1779 } 1780 break; 1781 1782 case HPC_POWER_LED: 1783 switch (schpc_p->schpc_slot[slot].led.led_power) { 1784 case LED_OFF: 1785 hpc_led_info->state = HPC_LED_OFF; 1786 break; 1787 case LED_ON: 1788 hpc_led_info->state = HPC_LED_ON; 1789 break; 1790 case LED_FLASH: 1791 hpc_led_info->state = HPC_LED_BLINK; 1792 break; 1793 } 1794 break; 1795 case HPC_ATTN_LED: 1796 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1797 case LED_OFF: 1798 hpc_led_info->state = HPC_LED_OFF; 1799 break; 1800 case LED_ON: 1801 hpc_led_info->state = HPC_LED_OFF; 1802 break; 1803 case LED_FLASH: 1804 hpc_led_info->state = HPC_LED_ON; 1805 break; 1806 } 1807 break; 1808 case HPC_ACTIVE_LED: 1809 switch (schpc_p->schpc_slot[slot].led.led_service) { 1810 case LED_OFF: 1811 hpc_led_info->state = HPC_LED_OFF; 1812 break; 1813 case LED_ON: 1814 hpc_led_info->state = HPC_LED_ON; 1815 break; 1816 case LED_FLASH: 1817 hpc_led_info->state = HPC_LED_BLINK; 1818 break; 1819 } 1820 break; 1821 default: 1822 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 1823 "Invalid LED %x", hpc_led_info->led); 1824 1825 mutex_enter(&schpc_p->schpc_mutex); 1826 schpc_p->schpc_slot[slot].state &= 1827 ~SCHPC_SLOTSTATE_EXECUTING; 1828 cv_signal(&schpc_p->schpc_cv); 1829 mutex_exit(&schpc_p->schpc_mutex); 1830 1831 return (HPC_ERR_FAILED); 1832 } 1833 1834 mutex_enter(&schpc_p->schpc_mutex); 1835 schpc_p->schpc_slot[slot].state &= 1836 ~SCHPC_SLOTSTATE_EXECUTING; 1837 cv_signal(&schpc_p->schpc_cv); 1838 mutex_exit(&schpc_p->schpc_mutex); 1839 1840 return (0); 1841 1842 case HPC_CTRL_SET_LED_STATE: 1843 hpc_led_info = (hpc_led_info_t *)arg; 1844 1845 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 1846 "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", 1847 (void *)hpc_led_info); 1848 1849 switch (hpc_led_info->led) { 1850 case HPC_FAULT_LED: 1851 switch (hpc_led_info->state) { 1852 case HPC_LED_OFF: 1853 schpc_p->schpc_slot[slot].led.led_fault = 1854 LED_OFF; 1855 setslot.slot_led_fault = PCIMSG_LED_OFF; 1856 break; 1857 case HPC_LED_ON: 1858 schpc_p->schpc_slot[slot].led.led_fault = 1859 LED_ON; 1860 setslot.slot_led_fault = PCIMSG_LED_ON; 1861 break; 1862 case HPC_LED_BLINK: 1863 schpc_p->schpc_slot[slot].led.led_fault = 1864 LED_FLASH; 1865 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1866 break; 1867 } 1868 break; 1869 case HPC_POWER_LED: 1870 switch (hpc_led_info->state) { 1871 case HPC_LED_OFF: 1872 schpc_p->schpc_slot[slot].led.led_power = 1873 LED_OFF; 1874 setslot.slot_led_power = PCIMSG_LED_OFF; 1875 break; 1876 case HPC_LED_ON: 1877 schpc_p->schpc_slot[slot].led.led_power = 1878 LED_ON; 1879 setslot.slot_led_power = PCIMSG_LED_ON; 1880 break; 1881 case HPC_LED_BLINK: 1882 schpc_p->schpc_slot[slot].led.led_power = 1883 LED_FLASH; 1884 setslot.slot_led_power = PCIMSG_LED_FLASH; 1885 break; 1886 } 1887 break; 1888 case HPC_ATTN_LED: 1889 switch (hpc_led_info->state) { 1890 case HPC_LED_OFF: 1891 schpc_p->schpc_slot[slot].led.led_fault = 1892 LED_OFF; 1893 setslot.slot_led_fault = PCIMSG_LED_OFF; 1894 break; 1895 case HPC_LED_ON: 1896 schpc_p->schpc_slot[slot].led.led_fault = 1897 LED_FLASH; 1898 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1899 break; 1900 case HPC_LED_BLINK: 1901 schpc_p->schpc_slot[slot].led.led_fault = 1902 LED_FLASH; 1903 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1904 break; 1905 } 1906 break; 1907 case HPC_ACTIVE_LED: 1908 switch (hpc_led_info->state) { 1909 case HPC_LED_OFF: 1910 schpc_p->schpc_slot[slot].led.led_service = 1911 LED_OFF; 1912 setslot.slot_led_service = PCIMSG_LED_OFF; 1913 break; 1914 case HPC_LED_ON: 1915 schpc_p->schpc_slot[slot].led.led_service = 1916 LED_ON; 1917 setslot.slot_led_service = PCIMSG_LED_ON; 1918 break; 1919 case HPC_LED_BLINK: 1920 schpc_p->schpc_slot[slot].led.led_service = 1921 LED_FLASH; 1922 setslot.slot_led_service = PCIMSG_LED_FLASH; 1923 break; 1924 } 1925 break; 1926 default: 1927 mutex_enter(&schpc_p->schpc_mutex); 1928 schpc_p->schpc_slot[slot].state &= 1929 ~SCHPC_SLOTSTATE_EXECUTING; 1930 cv_signal(&schpc_p->schpc_cv); 1931 mutex_exit(&schpc_p->schpc_mutex); 1932 1933 return (0); 1934 } 1935 1936 (void) schpc_setslotstatus(expander, board, slot, &setslot); 1937 1938 mutex_enter(&schpc_p->schpc_mutex); 1939 schpc_p->schpc_slot[slot].state &= 1940 ~SCHPC_SLOTSTATE_EXECUTING; 1941 cv_signal(&schpc_p->schpc_cv); 1942 mutex_exit(&schpc_p->schpc_mutex); 1943 1944 return (0); 1945 1946 case HPC_CTRL_ENABLE_AUTOCFG: 1947 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1948 "HPC_CTRL_ENABLE_AUTOCFG"); 1949 1950 schpc_p->schpc_slot[slot].state |= 1951 SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1952 1953 mutex_enter(&schpc_p->schpc_mutex); 1954 schpc_p->schpc_slot[slot].state &= 1955 ~SCHPC_SLOTSTATE_EXECUTING; 1956 cv_signal(&schpc_p->schpc_cv); 1957 mutex_exit(&schpc_p->schpc_mutex); 1958 1959 return (0); 1960 1961 case HPC_CTRL_DISABLE_AUTOCFG: 1962 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1963 "HPC_CTRL_DISABLE_AUTOCFG"); 1964 schpc_p->schpc_slot[slot].state &= 1965 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1966 1967 mutex_enter(&schpc_p->schpc_mutex); 1968 schpc_p->schpc_slot[slot].state &= 1969 ~SCHPC_SLOTSTATE_EXECUTING; 1970 cv_signal(&schpc_p->schpc_cv); 1971 mutex_exit(&schpc_p->schpc_mutex); 1972 1973 return (0); 1974 1975 case HPC_CTRL_DISABLE_ENUM: 1976 case HPC_CTRL_ENABLE_ENUM: 1977 default: 1978 mutex_enter(&schpc_p->schpc_mutex); 1979 schpc_p->schpc_slot[slot].state &= 1980 ~SCHPC_SLOTSTATE_EXECUTING; 1981 cv_signal(&schpc_p->schpc_cv); 1982 mutex_exit(&schpc_p->schpc_mutex); 1983 1984 return (HPC_ERR_NOTSUPPORTED); 1985 } 1986 } 1987 1988 /* 1989 * schpc_test 1990 * 1991 * Tests the slot. 1992 */ 1993 /*ARGSUSED*/ 1994 static void 1995 schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags) 1996 { 1997 pci_getslot_t slotstatus; 1998 pci_setslot_t setslot; 1999 int expander, board; 2000 int rval; 2001 int retry = 1; 2002 2003 SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)", 2004 (void *)ops_arg, SCHPC_SLOT_NUM(slot)); 2005 2006 SCHPC_DEBUG3(D_IOC_TEST, 2007 " schpc_test() Expander=%d Board=%d Slot=%d", 2008 schpc_p->schpc_slot[slot].expander, 2009 schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot)); 2010 2011 expander = schpc_p->schpc_slot[slot].expander; 2012 board = schpc_p->schpc_slot[slot].board; 2013 2014 restart_test: 2015 /* 2016 * Initial the slot with its occupant and receptacle in good condition. 2017 */ 2018 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_REC_GOOD; 2019 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_OCC_GOOD; 2020 2021 2022 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 2023 2024 if (rval) { 2025 /* 2026 * System Controller/Mailbox failure. 2027 */ 2028 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2029 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 2030 "Communicate with System Controller", expander, board, 2031 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 2032 2033 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 2034 return; 2035 } 2036 2037 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 2038 2039 cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d " 2040 "is not hot pluggable\n", expander, board, 2041 SCHPC_SLOT_NUM(slot)); 2042 2043 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 2044 return; 2045 } 2046 2047 switch (slotstatus.slot_condition) { 2048 case PCIMSG_SLOTCOND_OCC_FAIL: 2049 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2050 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2051 "System Controller/Occupant Failed", 2052 expander, board, SCHPC_SLOT_NUM(slot), 2053 schpc_p->schpc_slot[slot].ap_id); 2054 2055 schpc_setslotled(expander, board, slot, 2056 (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON)); 2057 2058 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_OCC_GOOD; 2059 return; 2060 case PCIMSG_SLOTCOND_REC_FAIL: 2061 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2062 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2063 "System Controller/Receptacle Failed", 2064 expander, board, SCHPC_SLOT_NUM(slot), 2065 schpc_p->schpc_slot[slot].ap_id); 2066 2067 schpc_setslotled(expander, board, slot, 2068 (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON)); 2069 2070 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 2071 return; 2072 } 2073 2074 if (slotstatus.slot_power_on) { 2075 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON; 2076 2077 if (!slotstatus.slot_HEALTHY) { 2078 /* 2079 * cPCI Adapter is not asserting HEALTHY#. 2080 */ 2081 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2082 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2083 "PCI adapter not HEALTHY", expander, board, 2084 SCHPC_SLOT_NUM(slot), 2085 schpc_p->schpc_slot[slot].ap_id); 2086 2087 schpc_setslotled(expander, board, slot, 2088 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 2089 2090 schpc_p->schpc_slot[slot].state &= 2091 ~SCHPC_SLOTSTATE_OCC_GOOD; 2092 2093 return; 2094 } 2095 2096 if (!slotstatus.slot_powergood) { 2097 /* 2098 * PCI Power Input is not good. 2099 */ 2100 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2101 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2102 "System Controller PCI Power Input Not Good", 2103 expander, board, SCHPC_SLOT_NUM(slot), 2104 schpc_p->schpc_slot[slot].ap_id); 2105 2106 schpc_setslotled(expander, board, slot, 2107 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 2108 2109 schpc_p->schpc_slot[slot].state &= 2110 ~SCHPC_SLOTSTATE_OCC_GOOD; 2111 2112 return; 2113 } 2114 2115 if (slotstatus.slot_powerfault) { 2116 /* 2117 * PCI Power Fault. 2118 */ 2119 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2120 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2121 "System Controller PCI Power Fault", 2122 expander, board, SCHPC_SLOT_NUM(slot), 2123 schpc_p->schpc_slot[slot].ap_id); 2124 2125 schpc_setslotled(expander, board, slot, 2126 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 2127 2128 schpc_p->schpc_slot[slot].state &= 2129 ~SCHPC_SLOTSTATE_OCC_GOOD; 2130 2131 return; 2132 } 2133 } 2134 2135 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0"); 2136 2137 /* 2138 * Is the slot empty? 2139 */ 2140 if (slotstatus.slot_empty) { 2141 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty"); 2142 2143 schpc_p->schpc_slot[slot].state &= 2144 ~SCHPC_SLOTSTATE_PRESENT; 2145 2146 if (slotstatus.slot_power_on) { 2147 2148 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot " 2149 "is powered ON"); 2150 2151 /* 2152 * Tests will be retried once after powering off 2153 * an empty slot. 2154 */ 2155 if (retry) { 2156 2157 /* 2158 * Turn off the slot and restart test. 2159 */ 2160 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() " 2161 "Turning Empty Slot OFF"); 2162 2163 schpc_init_setslot_message(&setslot); 2164 setslot.slot_power_off = PCIMSG_ON; 2165 (void) schpc_setslotstatus( 2166 expander, board, slot, &setslot); 2167 2168 retry = 0; 2169 2170 goto restart_test; 2171 } 2172 } 2173 } else { 2174 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present"); 2175 2176 if (!slotstatus.slot_power_on) { 2177 if (retry) { 2178 /* 2179 * If there is a cassette present and the 2180 * power is off, try turning the power on and 2181 * restart the test. This allows access to 2182 * the FRUID when an empty cassette is 2183 * installed. 2184 */ 2185 SCHPC_DEBUG0(D_IOC_TEST, 2186 "schpc_test() Power On Adapter"); 2187 schpc_init_setslot_message(&setslot); 2188 setslot.slot_power_on = PCIMSG_ON; 2189 (void) schpc_setslotstatus( 2190 expander, board, slot, &setslot); 2191 retry = 0; 2192 goto restart_test; 2193 } 2194 } 2195 2196 schpc_p->schpc_slot[slot].state |= 2197 SCHPC_SLOTSTATE_PRESENT; 2198 } 2199 2200 /* 2201 * Is the slot powered up? 2202 */ 2203 schpc_init_setslot_message(&setslot); 2204 2205 if (slotstatus.slot_power_on) { 2206 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On"); 2207 2208 schpc_p->schpc_slot[slot].state |= 2209 SCHPC_SLOTSTATE_CONNECTED; 2210 2211 setslot.slot_led_power = PCIMSG_LED_ON; 2212 setslot.slot_led_service = PCIMSG_LED_OFF; 2213 setslot.slot_enable_ENUM = PCIMSG_ON; 2214 setslot.slot_enable_HEALTHY = PCIMSG_ON; 2215 } else { 2216 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off"); 2217 2218 schpc_p->schpc_slot[slot].state &= 2219 ~SCHPC_SLOTSTATE_CONNECTED; 2220 2221 setslot.slot_led_power = PCIMSG_LED_OFF; 2222 setslot.slot_led_service = PCIMSG_LED_ON; 2223 setslot.slot_disable_ENUM = PCIMSG_ON; 2224 setslot.slot_disable_HEALTHY = PCIMSG_ON; 2225 } 2226 2227 setslot.slot_led_fault = PCIMSG_LED_OFF; 2228 2229 (void) schpc_setslotstatus(expander, board, slot, &setslot); 2230 2231 /* 2232 * Save LED State. 2233 */ 2234 switch (setslot.slot_led_power) { 2235 case PCIMSG_LED_ON: 2236 schpc_p->schpc_slot[slot].led.led_power = LED_ON; 2237 break; 2238 case PCIMSG_LED_OFF: 2239 schpc_p->schpc_slot[slot].led.led_power = LED_OFF; 2240 break; 2241 case PCIMSG_LED_FLASH: 2242 schpc_p->schpc_slot[slot].led.led_power = LED_FLASH; 2243 break; 2244 } 2245 switch (setslot.slot_led_service) { 2246 case PCIMSG_LED_ON: 2247 schpc_p->schpc_slot[slot].led.led_service = LED_ON; 2248 break; 2249 case PCIMSG_LED_OFF: 2250 schpc_p->schpc_slot[slot].led.led_service = LED_OFF; 2251 break; 2252 case PCIMSG_LED_FLASH: 2253 schpc_p->schpc_slot[slot].led.led_service = LED_FLASH; 2254 break; 2255 } 2256 switch (setslot.slot_led_fault) { 2257 case PCIMSG_LED_ON: 2258 schpc_p->schpc_slot[slot].led.led_fault = LED_ON; 2259 break; 2260 case PCIMSG_LED_OFF: 2261 schpc_p->schpc_slot[slot].led.led_fault = LED_OFF; 2262 break; 2263 case PCIMSG_LED_FLASH: 2264 schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH; 2265 break; 2266 } 2267 } 2268 2269 2270 /* 2271 * schpc_event_handler 2272 * 2273 * Placed on the schpc_event_taskq by schpc_event_filter when an 2274 * unsolicited MBOXSC_MSG_EVENT is received from the SC. It handles 2275 * things like power insertion/removal, ENUM#, etc. 2276 */ 2277 static void 2278 schpc_event_handler(void *arg) 2279 { 2280 pci_getslot_t slotstatus; 2281 uint8_t expander, board, slot; 2282 int rval; 2283 pcimsg_t *event = (pcimsg_t *)arg; 2284 2285 /* 2286 * OK, we got an event message. Since the event message only tells 2287 * us something has changed and not changed to what, we need to get 2288 * the current slot status to find how WHAT was change to WHAT. 2289 */ 2290 2291 slot = event->pcimsg_slot; 2292 expander = event->pcimsg_node; /* get expander */ 2293 board = event->pcimsg_board; /* get board */ 2294 2295 SCHPC_DEBUG3(D_EVENT, 2296 "schpc_event_handler() - exp=%d board=%d slot=%d", 2297 expander, board, slot); 2298 2299 /* create a slot table index */ 2300 slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot); 2301 2302 SCHPC_DEBUG1(D_EVENT, 2303 "schpc_event_handler() - expanded slot %d", slot); 2304 2305 if (schpc_p == NULL) { 2306 cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc"); 2307 kmem_free(event, sizeof (pcimsg_t)); 2308 return; 2309 } 2310 2311 mutex_enter(&schpc_p->schpc_mutex); 2312 2313 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 2314 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited"); 2315 mutex_exit(&schpc_p->schpc_mutex); 2316 kmem_free(event, sizeof (pcimsg_t)); 2317 return; 2318 } 2319 /* 2320 * Block if another thread is executing a HPC command. 2321 */ 2322 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 2323 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy"); 2324 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 2325 } 2326 2327 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 2328 2329 mutex_exit(&schpc_p->schpc_mutex); 2330 2331 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 2332 2333 if (rval) { 2334 cmn_err(CE_WARN, "schpc/Event Handler - Can not get status " 2335 "for expander=%d board=%d slot=%d\n", 2336 expander, board, SCHPC_SLOT_NUM(slot)); 2337 2338 mutex_enter(&schpc_p->schpc_mutex); 2339 schpc_p->schpc_slot[slot].state &= 2340 ~SCHPC_SLOTSTATE_EXECUTING; 2341 cv_signal(&schpc_p->schpc_cv); 2342 mutex_exit(&schpc_p->schpc_mutex); 2343 kmem_free(event, sizeof (pcimsg_t)); 2344 return; 2345 } 2346 2347 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 2348 cmn_err(CE_WARN, "schpc/Event Handler - Can not get good " 2349 "status for expander=%d board=%d slot=%d\n", 2350 expander, board, SCHPC_SLOT_NUM(slot)); 2351 2352 mutex_enter(&schpc_p->schpc_mutex); 2353 schpc_p->schpc_slot[slot].state &= 2354 ~SCHPC_SLOTSTATE_EXECUTING; 2355 cv_signal(&schpc_p->schpc_cv); 2356 mutex_exit(&schpc_p->schpc_mutex); 2357 2358 kmem_free(event, sizeof (pcimsg_t)); 2359 return; 2360 } 2361 2362 SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d", 2363 expander, board, SCHPC_SLOT_NUM(slot)); 2364 2365 if (schpc_p->schpc_slot[slot].slot_ops == NULL) { 2366 SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event " 2367 "for unregistered slot for expander=%d board=%d slot=%d", 2368 expander, board, SCHPC_SLOT_NUM(slot)); 2369 2370 mutex_enter(&schpc_p->schpc_mutex); 2371 schpc_p->schpc_slot[slot].state &= 2372 ~SCHPC_SLOTSTATE_EXECUTING; 2373 cv_signal(&schpc_p->schpc_cv); 2374 mutex_exit(&schpc_p->schpc_mutex); 2375 2376 kmem_free(event, sizeof (pcimsg_t)); 2377 return; 2378 } 2379 2380 /* Slot Power Event */ 2381 2382 if (event->pcimsg_type.pcimsg_slotevent.slot_power) { 2383 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event"); 2384 /* 2385 * The SC may have changed to slot power status. 2386 */ 2387 if (slotstatus.slot_power_on) { 2388 schpc_p->schpc_slot[slot].state |= 2389 SCHPC_SLOTSTATE_CONNECTED; 2390 2391 (void) hpc_slot_event_notify( 2392 schpc_p->schpc_slot[slot].slot_handle, 2393 HPC_EVENT_SLOT_POWER_ON, 0); 2394 } else { 2395 schpc_p->schpc_slot[slot].state &= 2396 ~SCHPC_SLOTSTATE_CONNECTED; 2397 2398 (void) hpc_slot_event_notify( 2399 schpc_p->schpc_slot[slot].slot_handle, 2400 HPC_EVENT_SLOT_POWER_OFF, 0); 2401 } 2402 } 2403 2404 /* Adapter Insertion/Removal Event */ 2405 2406 if (event->pcimsg_type.pcimsg_slotevent.slot_presence) { 2407 if (slotstatus.slot_empty == PCIMSG_ON) { 2408 2409 /* Adapter Removed */ 2410 2411 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed"); 2412 2413 if (schpc_p->schpc_slot[slot].state & 2414 SCHPC_SLOTSTATE_CONNECTED) { 2415 /* 2416 * If the adapter has been removed while 2417 * there the slot is connected, it could be 2418 * due to a ENUM handling. 2419 */ 2420 cmn_err(CE_WARN, "Card removed from " 2421 "powered on slot at " 2422 "expander=%d board=%d slot=%d\n", 2423 expander, board, SCHPC_SLOT_NUM(slot)); 2424 2425 schpc_p->schpc_slot[slot].state &= 2426 ~SCHPC_SLOTSTATE_EXECUTING; 2427 rval = schpc_disconnect((caddr_t)schpc_p, 2428 schpc_p->schpc_slot[slot].slot_handle, 2429 0, 0); 2430 mutex_enter(&schpc_p->schpc_mutex); 2431 while (schpc_p->schpc_slot[slot].state & 2432 SCHPC_SLOTSTATE_EXECUTING) { 2433 SCHPC_DEBUG0(D_EVENT, 2434 "schpc_event_handler - " 2435 "Slot is busy"); 2436 cv_wait(&schpc_p->schpc_cv, 2437 &schpc_p->schpc_mutex); 2438 } 2439 2440 schpc_p->schpc_slot[slot].state |= 2441 SCHPC_SLOTSTATE_EXECUTING; 2442 2443 mutex_exit(&schpc_p->schpc_mutex); 2444 } 2445 schpc_p->schpc_slot[slot].state |= 2446 SCHPC_SLOTSTATE_OCC_GOOD; 2447 2448 schpc_p->schpc_slot[slot].state &= 2449 ~SCHPC_SLOTSTATE_PRESENT; 2450 2451 (void) hpc_slot_event_notify( 2452 schpc_p->schpc_slot[slot].slot_handle, 2453 HPC_EVENT_SLOT_REMOVAL, 0); 2454 } else { 2455 2456 /* Adapter Inserted */ 2457 2458 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted"); 2459 2460 if (schpc_p->schpc_slot[slot].state & 2461 SCHPC_SLOTSTATE_PRESENT) { 2462 /* 2463 * If the adapter is already present 2464 * throw the this event away. 2465 */ 2466 2467 SCHPC_DEBUG0(D_EVENT, 2468 "Adapter is already present"); 2469 2470 mutex_enter(&schpc_p->schpc_mutex); 2471 schpc_p->schpc_slot[slot].state &= 2472 ~SCHPC_SLOTSTATE_EXECUTING; 2473 cv_signal(&schpc_p->schpc_cv); 2474 mutex_exit(&schpc_p->schpc_mutex); 2475 2476 kmem_free(event, sizeof (pcimsg_t)); 2477 return; 2478 } 2479 2480 schpc_p->schpc_slot[slot].state |= 2481 SCHPC_SLOTSTATE_PRESENT; 2482 2483 schpc_p->schpc_slot[slot].state &= 2484 ~SCHPC_SLOTSTATE_CONNECTED; 2485 2486 (void) hpc_slot_event_notify( 2487 schpc_p->schpc_slot[slot].slot_handle, 2488 HPC_EVENT_SLOT_INSERTION, 0); 2489 2490 if (schpc_p->schpc_slot[slot].state & 2491 SCHPC_SLOTSTATE_AUTOCFG_ENABLE) { 2492 SCHPC_DEBUG0(D_EVENT, "Auto Configuration " 2493 "(Connect/Configure) Started"); 2494 2495 schpc_p->schpc_slot[slot].state &= 2496 ~SCHPC_SLOTSTATE_EXECUTING; 2497 2498 rval = schpc_connect((caddr_t)schpc_p, 2499 schpc_p->schpc_slot[slot].slot_handle, 2500 0, 0); 2501 2502 if (rval) { 2503 cmn_err(CE_WARN, "schpc/Event Handler -" 2504 " Can not connect"); 2505 2506 mutex_enter(&schpc_p->schpc_mutex); 2507 schpc_p->schpc_slot[slot].state &= 2508 ~SCHPC_SLOTSTATE_EXECUTING; 2509 cv_signal(&schpc_p->schpc_cv); 2510 mutex_exit(&schpc_p->schpc_mutex); 2511 2512 kmem_free(event, sizeof (pcimsg_t)); 2513 return; 2514 } 2515 mutex_enter(&schpc_p->schpc_mutex); 2516 while (schpc_p->schpc_slot[slot].state & 2517 SCHPC_SLOTSTATE_EXECUTING) { 2518 SCHPC_DEBUG0(D_EVENT, 2519 "schpc_event_handler - " 2520 "Slot is busy"); 2521 cv_wait(&schpc_p->schpc_cv, 2522 &schpc_p->schpc_mutex); 2523 } 2524 2525 schpc_p->schpc_slot[slot].state |= 2526 SCHPC_SLOTSTATE_EXECUTING; 2527 2528 mutex_exit(&schpc_p->schpc_mutex); 2529 2530 (void) hpc_slot_event_notify( 2531 schpc_p->schpc_slot[slot].slot_handle, 2532 HPC_EVENT_SLOT_CONFIGURE, 0); 2533 } else { 2534 schpc_setslotled(expander, board, slot, 2535 SERVICE_LED_ON); 2536 } 2537 } 2538 } 2539 2540 /* ENUM# signal change event */ 2541 2542 if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) { 2543 /* 2544 * ENUM should only be received to the adapter remove 2545 * procedure. 2546 */ 2547 2548 SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted"); 2549 2550 schpc_setslotled(expander, board, slot, FAULT_LED_FLASH); 2551 2552 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM; 2553 2554 (void) hpc_slot_event_notify( 2555 schpc_p->schpc_slot[slot].slot_handle, 2556 HPC_EVENT_SLOT_ENUM, 0); 2557 } 2558 2559 /* HEALTHY# signal change event */ 2560 2561 if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) { 2562 2563 if (!slotstatus.slot_HEALTHY) { 2564 2565 SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED"); 2566 2567 schpc_p->schpc_slot[slot].state &= 2568 ~SCHPC_SLOTSTATE_OCC_GOOD; 2569 2570 (void) hpc_slot_event_notify( 2571 schpc_p->schpc_slot[slot].slot_handle, 2572 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 2573 2574 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 2575 } else { 2576 SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK"); 2577 2578 schpc_p->schpc_slot[slot].state |= 2579 SCHPC_SLOTSTATE_OCC_GOOD; 2580 2581 (void) hpc_slot_event_notify( 2582 schpc_p->schpc_slot[slot].slot_handle, 2583 HPC_EVENT_SLOT_HEALTHY_OK, 0); 2584 2585 schpc_setslotled(expander, board, slot, 2586 FAULT_LED_OFF); 2587 } 2588 } 2589 2590 /* Good Power change event */ 2591 2592 if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) { 2593 if (slotstatus.slot_powergood == PCIMSG_ON) { 2594 2595 SCHPC_DEBUG0(D_EVENT, 2596 "Event Type: Slot Power Good Detected"); 2597 2598 schpc_p->schpc_slot[slot].state |= 2599 SCHPC_SLOTSTATE_OCC_GOOD; 2600 2601 (void) hpc_slot_event_notify( 2602 schpc_p->schpc_slot[slot].slot_handle, 2603 HPC_EVENT_SLOT_HEALTHY_OK, 0); 2604 2605 schpc_setslotled(expander, board, slot, 2606 FAULT_LED_OFF); 2607 } else { 2608 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good " 2609 "Detected"); 2610 2611 if (schpc_p->schpc_slot[slot].state & 2612 SCHPC_SLOTSTATE_CONNECTED) { 2613 2614 SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: " 2615 "power failed"); 2616 2617 schpc_p->schpc_slot[slot].state &= 2618 ~SCHPC_SLOTSTATE_OCC_GOOD; 2619 2620 (void) hpc_slot_event_notify( 2621 schpc_p->schpc_slot[slot].slot_handle, 2622 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 2623 2624 schpc_setslotled(expander, board, slot, 2625 FAULT_LED_ON); 2626 } 2627 } 2628 } 2629 2630 /* Power Fault change event */ 2631 2632 if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) { 2633 if (slotstatus.slot_powerfault == PCIMSG_ON) { 2634 2635 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault " 2636 "Detected"); 2637 2638 schpc_p->schpc_slot[slot].state &= 2639 ~SCHPC_SLOTSTATE_OCC_GOOD; 2640 2641 (void) hpc_slot_event_notify( 2642 schpc_p->schpc_slot[slot].slot_handle, 2643 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 2644 2645 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 2646 } else { 2647 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault " 2648 "Cleared"); 2649 2650 schpc_p->schpc_slot[slot].state |= 2651 SCHPC_SLOTSTATE_OCC_GOOD; 2652 2653 (void) hpc_slot_event_notify( 2654 schpc_p->schpc_slot[slot].slot_handle, 2655 HPC_EVENT_SLOT_HEALTHY_OK, 0); 2656 2657 schpc_setslotled(expander, board, slot, 2658 FAULT_LED_OFF); 2659 } 2660 } 2661 mutex_enter(&schpc_p->schpc_mutex); 2662 schpc_p->schpc_slot[slot].state &= 2663 ~SCHPC_SLOTSTATE_EXECUTING; 2664 cv_signal(&schpc_p->schpc_cv); 2665 mutex_exit(&schpc_p->schpc_mutex); 2666 2667 kmem_free(event, sizeof (pcimsg_t)); 2668 } 2669 2670 2671 /* 2672 * schpc_event_filter 2673 * 2674 * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the 2675 * schpc_event_taskq for processing by the schpc_event_handler _if_ 2676 * hotpluggable pci slots have been registered; otherwise, the 2677 * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox 2678 * open for future messages. 2679 */ 2680 static void 2681 schpc_event_filter(pcimsg_t *pmsg) 2682 { 2683 if (slots_registered == B_TRUE) { 2684 2685 pcimsg_t *pevent; 2686 2687 /* 2688 * If hotpluggable pci slots have been registered then enqueue 2689 * the event onto the schpc_event_taskq for processing. 2690 */ 2691 2692 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 2693 "slots_registered = B_TRUE"); 2694 2695 pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP); 2696 bcopy(pmsg, pevent, sizeof (pcimsg_t)); 2697 2698 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 2699 "event alloc'd"); 2700 2701 if (taskq_dispatch(schpc_event_taskq, schpc_event_handler, 2702 (void *)pevent, TQ_SLEEP) == NULL) { 2703 cmn_err(CE_WARN, "schpc: schpc_event_filter - " 2704 "taskq_dispatch failed to enqueue event"); 2705 kmem_free(pevent, sizeof (pcimsg_t)); 2706 return; 2707 } 2708 2709 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 2710 "event was taskq_dispatch'ed to schpc_event_handler"); 2711 } else { 2712 /* 2713 * Oops, schpc received an event _before_ the slots have been 2714 * registered. In that case there is no choice but to toss 2715 * the event. 2716 */ 2717 cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding " 2718 "premature event"); 2719 } 2720 } 2721 2722 2723 /* 2724 * schpc_msg_thread 2725 * A stand-alone thread that monitors the incoming mailbox for 2726 * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from 2727 * the mailbox for processing. 2728 * 2729 * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the 2730 * schpc_replylist, and the waiting thread is notified that its REPLY 2731 * message has arrived; otherwise, if no REPLY match is found, then it is 2732 * discarded. 2733 * 2734 * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed 2735 * by the schpc_event_handler. 2736 * 2737 * The schpc_msg_thread is started in _init(). 2738 */ 2739 void 2740 schpc_msg_thread(void) 2741 { 2742 int err; 2743 uint32_t type; 2744 uint32_t cmd; 2745 uint64_t transid; 2746 uint32_t length; 2747 pcimsg_t msg; 2748 2749 SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running"); 2750 2751 /* CONSTCOND */ 2752 while (1) { 2753 2754 /* setup wildcard arguments */ 2755 type = 0; 2756 cmd = 0; 2757 transid = 0; 2758 length = sizeof (pcimsg_t); 2759 bzero(&msg, sizeof (pcimsg_t)); 2760 2761 err = mboxsc_getmsg(KEY_SCPC, &type, &cmd, 2762 &transid, &length, (void *)&msg, 2763 schpc_timeout_getmsg); 2764 2765 if (err) { 2766 switch (err) { 2767 2768 /*FALLTHROUGH*/ 2769 case ETIMEDOUT: 2770 case EAGAIN: 2771 continue; 2772 2773 default: 2774 /* 2775 * unfortunately, we can't do very much here 2776 * because we're wildcarding mboxsc_getmsg 2777 * so if it encounters an error, we can't 2778 * identify which transid it belongs to. 2779 */ 2780 cmn_err(CE_WARN, 2781 "schpc - mboxsc_getmsg failed, err=0x%x", err); 2782 delay(drv_usectohz(100000)); 2783 continue; 2784 } 2785 } 2786 2787 if (msg.pcimsg_revision != PCIMSG_REVISION) { 2788 /* 2789 * This version of the schpc driver only understands 2790 * version 1.0 of the PCI Hot Plug Message format. 2791 */ 2792 cmn_err(CE_WARN, " schpc: schpc_msg_thread - " 2793 "discarding event w/ unknown message version %x", 2794 msg.pcimsg_revision); 2795 continue; 2796 } 2797 2798 switch (type) { 2799 2800 case MBOXSC_MSG_EVENT: 2801 schpc_event_filter(&msg); 2802 break; 2803 2804 case MBOXSC_MSG_REPLY: 2805 schpc_reply_handler(&msg, type, cmd, transid, length); 2806 break; 2807 2808 default: 2809 cmn_err(CE_WARN, 2810 "schpc - mboxsc_getmsg unknown msg" 2811 " type=0x%x", type); 2812 break; 2813 } 2814 } 2815 /* this thread never exits */ 2816 } 2817 2818 2819 void 2820 schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd, 2821 uint64_t transid, uint32_t length) 2822 { 2823 schpc_replylist_t *entry; 2824 2825 mutex_enter(&schpc_replylist_mutex); 2826 entry = schpc_replylist_first; 2827 while (entry != NULL) { 2828 if (entry->transid == transid) { 2829 break; 2830 } else 2831 entry = entry->next; 2832 } 2833 if (entry) { 2834 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2835 "schpc_reply_handler() - 0x%lx transid reply " 2836 "received", transid); 2837 2838 mutex_enter(&entry->reply_lock); 2839 if (entry->reply_cexit == B_FALSE) { 2840 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2841 "schpc_reply_handler() - 0x%lx transid" 2842 " cv_signal waiting thread", transid); 2843 2844 /* 2845 * emulate mboxsc_getmsg by copying the reply 2846 */ 2847 entry->type = type; 2848 entry->cmd = cmd; 2849 entry->transid = transid; 2850 entry->length = length; 2851 bcopy((caddr_t)pmsg, &entry->reply, length); 2852 2853 /* reply was received */ 2854 entry->reply_recvd = B_TRUE; 2855 2856 /* 2857 * wake up thread waiting for reply with transid 2858 */ 2859 cv_signal(&entry->reply_cv); 2860 } 2861 mutex_exit(&entry->reply_lock); 2862 } else { 2863 cmn_err(CE_WARN, "schpc - no match for transid 0x%lx", 2864 transid); 2865 } 2866 mutex_exit(&schpc_replylist_mutex); 2867 } 2868 2869 2870 /* 2871 * schpc_putrequest 2872 * 2873 * A wrapper around the synchronous call mboxsc_putmsg(). 2874 */ 2875 int 2876 schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp, 2877 uint32_t length, void *datap, clock_t timeout, 2878 schpc_replylist_t **entryp) 2879 { 2880 int rval; 2881 2882 /* add the request to replylist to keep track of outstanding requests */ 2883 *entryp = schpc_replylist_link(cmd, *transidp, length); 2884 2885 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - " 2886 "0x%lx transid mboxsc_putmsg called", *transidp); 2887 2888 /* wait synchronously for request to be sent */ 2889 rval = mboxsc_putmsg(key, type, cmd, transidp, length, 2890 (void *)datap, timeout); 2891 2892 SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - " 2893 "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval); 2894 2895 /* if problem is encountered then remove the request from replylist */ 2896 if (rval) 2897 schpc_replylist_unlink(*entryp); 2898 2899 return (rval); 2900 } 2901 2902 2903 /* 2904 * schpc_getreply 2905 * 2906 * Wait for the schpc_msg_thread to respond that a matching reply has 2907 * arrived; otherwise, timeout and remove the entry from the schpc_replylist. 2908 */ 2909 /*ARGSUSED*/ 2910 int 2911 schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp, 2912 uint64_t *transidp, uint32_t *lengthp, void *datap, 2913 clock_t timeout, schpc_replylist_t *listp) 2914 { 2915 int rc = 0; 2916 2917 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2918 "schpc_getreply() - 0x%lx transid waiting for reply", 2919 *transidp); 2920 2921 /* 2922 * wait here until schpc_msg_thread because it's always 2923 * looking for reply messages 2924 */ 2925 mutex_enter(&listp->reply_lock); 2926 2927 while (listp->reply_recvd == B_FALSE) { 2928 /* 2929 * wait for reply or timeout 2930 */ 2931 rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock, 2932 ddi_get_lbolt() + drv_usectohz(timeout * 1000)); 2933 switch (rc) { 2934 case -1: /* most likely a timeout, but check anyway */ 2935 2936 /* message was received after all */ 2937 if (listp->reply_recvd == B_TRUE) 2938 break; 2939 2940 /* no, it's really a timeout */ 2941 listp->reply_cexit = B_TRUE; 2942 mutex_exit(&listp->reply_lock); 2943 cmn_err(CE_WARN, 2944 "schpc - 0x%lx transid reply timed out", *transidp); 2945 schpc_replylist_unlink(listp); 2946 return (ETIMEDOUT); 2947 2948 default: 2949 break; 2950 } 2951 } 2952 2953 *typep = listp->type; 2954 *cmdp = listp->cmd; 2955 *transidp = listp->transid; 2956 *lengthp = listp->length; 2957 bcopy((caddr_t)&listp->reply, datap, *lengthp); 2958 mutex_exit(&listp->reply_lock); 2959 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2960 "schpc_getreply() - 0x%lx transid received", *transidp); 2961 schpc_replylist_unlink(listp); 2962 return (0); 2963 } 2964 2965 2966 /* 2967 * schpc_replylist_unlink 2968 * 2969 * Deallocate a schpc_replylist_t element. 2970 */ 2971 void 2972 schpc_replylist_unlink(schpc_replylist_t *entry) 2973 { 2974 #if DEBUG 2975 schpc_replylist_t *dbg_entry; 2976 #endif /* DEBUG */ 2977 2978 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2979 "schpc_replylist_unlink() - 0x%lx transid deleted from replylist", 2980 entry->transid); 2981 2982 mutex_enter(&schpc_replylist_mutex); 2983 if (entry->prev) { 2984 entry->prev->next = entry->next; 2985 if (entry->next) 2986 entry->next->prev = entry->prev; 2987 } else { 2988 schpc_replylist_first = entry->next; 2989 if (entry->next) 2990 entry->next->prev = NULL; 2991 } 2992 if (entry == schpc_replylist_last) { 2993 schpc_replylist_last = entry->prev; 2994 } 2995 kmem_free(entry, sizeof (schpc_replylist_t)); 2996 schpc_replylist_count--; 2997 2998 #if DEBUG 2999 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) { 3000 dbg_entry = schpc_replylist_first; 3001 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist " 3002 "count = %d\n", schpc_replylist_count); 3003 while (dbg_entry != NULL) { 3004 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - " 3005 "0x%lx transid\n", dbg_entry->transid); 3006 dbg_entry = dbg_entry->next; 3007 } 3008 } 3009 #endif /* DEBUG */ 3010 3011 mutex_exit(&schpc_replylist_mutex); 3012 } 3013 3014 3015 /* 3016 * schpc_replylist_link 3017 * 3018 * Allocate and initialize a schpc_replylist_t element. 3019 */ 3020 schpc_replylist_t * 3021 schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length) 3022 { 3023 schpc_replylist_t *entry; 3024 #if DEBUG 3025 schpc_replylist_t *dbg_entry; 3026 #endif /* DEBUG */ 3027 3028 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 3029 "schpc_replylist_link() - 0x%lx transid inserting into replylist", 3030 transid); 3031 3032 entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP); 3033 mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL); 3034 cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL); 3035 entry->type = MBOXSC_MSG_REPLY; 3036 entry->cmd = cmd; 3037 entry->transid = transid; 3038 entry->length = length; 3039 entry->reply_recvd = B_FALSE; 3040 entry->reply_cexit = B_FALSE; 3041 3042 mutex_enter(&schpc_replylist_mutex); 3043 if (schpc_replylist_last) { 3044 entry->prev = schpc_replylist_last; 3045 schpc_replylist_last->next = entry; 3046 schpc_replylist_last = entry; 3047 } else { 3048 schpc_replylist_last = schpc_replylist_first = entry; 3049 } 3050 3051 schpc_replylist_count++; 3052 3053 #if DEBUG 3054 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) { 3055 dbg_entry = schpc_replylist_first; 3056 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist " 3057 "count = %d\n", schpc_replylist_count); 3058 while (dbg_entry != NULL) { 3059 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - " 3060 "0x%lx transid\n", dbg_entry->transid); 3061 dbg_entry = dbg_entry->next; 3062 } 3063 } 3064 #endif /* DEBUG */ 3065 3066 mutex_exit(&schpc_replylist_mutex); 3067 3068 return (entry); 3069 } 3070 3071 3072 /* 3073 * schpc_getslotstatus 3074 * 3075 * Issues a Get Slot Status command to the System Controller 3076 * for a specific slot. 3077 */ 3078 static int 3079 schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot, 3080 pci_getslot_t *slotstatus) 3081 { 3082 pcimsg_t request; 3083 pcimsg_t reply; 3084 int rval; 3085 uint32_t type, cmd, length; 3086 uint64_t transid; 3087 schpc_replylist_t *entry; 3088 3089 SCHPC_DEBUG4(D_GETSLOTSTATUS, 3090 "schpc_getslotstatus(expander=%d board=%d " 3091 "slot=%d slotstatus=0x%p", expander, board, 3092 SCHPC_SLOT_NUM(slot), (void *)slotstatus); 3093 3094 if (schpc_p == NULL) { 3095 return (1); 3096 } 3097 3098 bzero(&request, sizeof (pcimsg_t)); 3099 3100 request.pcimsg_node = expander; 3101 request.pcimsg_board = board; 3102 request.pcimsg_slot = SCHPC_SLOT_NUM(slot); 3103 request.pcimsg_revision = PCIMSG_REVISION; 3104 request.pcimsg_command = PCIMSG_GETSLOTSTATUS; 3105 3106 type = MBOXSC_MSG_REQUEST; 3107 cmd = PCIMSG_GETSLOTSTATUS; 3108 transid = schpc_gettransid(schpc_p, slot); 3109 length = sizeof (pcimsg_t); 3110 3111 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3112 "0x%lx transid schpc_putrequest called", transid); 3113 3114 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length, 3115 (void *)&request, schpc_timeout_putmsg, &entry); 3116 3117 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3118 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval); 3119 3120 if (rval) { 3121 return (rval); 3122 } 3123 3124 bzero(&reply, sizeof (pcimsg_t)); 3125 type = MBOXSC_MSG_REPLY; 3126 3127 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3128 "0x%lx transid schpc_getreply called", transid); 3129 3130 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length, 3131 (void *)&reply, schpc_timeout_getmsg, entry); 3132 3133 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3134 "0x%lx transid schpc_getreply returned 0x%x", transid, rval); 3135 3136 if (rval == 0) { 3137 *slotstatus = reply.pcimsg_type.pcimsg_getslot; 3138 3139 SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()"); 3140 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_power_on %x", 3141 reply.pcimsg_type.pcimsg_getslot.slot_power_on); 3142 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powergood %x", 3143 reply.pcimsg_type.pcimsg_getslot.slot_powergood); 3144 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powerfault %x", 3145 reply.pcimsg_type.pcimsg_getslot.slot_powerfault); 3146 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_empty %x", 3147 reply.pcimsg_type.pcimsg_getslot.slot_empty); 3148 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_cap %x", 3149 reply.pcimsg_type.pcimsg_getslot.slot_freq_cap); 3150 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_setting %x", 3151 reply.pcimsg_type.pcimsg_getslot.slot_freq_setting); 3152 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_condition %x", 3153 reply.pcimsg_type.pcimsg_getslot.slot_condition); 3154 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_HEALTHY %x", 3155 reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY); 3156 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_ENUM %x", 3157 reply.pcimsg_type.pcimsg_getslot.slot_ENUM); 3158 } 3159 3160 return (rval); 3161 } 3162 3163 3164 /* 3165 * schpc_setslotstatus 3166 * 3167 * Issues a Set Slot Status command to the System Controller 3168 * for a specific slot. 3169 */ 3170 static int 3171 schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot, 3172 pci_setslot_t *slotstatus) 3173 { 3174 pcimsg_t request; 3175 pcimsg_t reply; 3176 int rval; 3177 uint32_t type, cmd, length; 3178 uint64_t transid; 3179 schpc_replylist_t *entry; 3180 3181 SCHPC_DEBUG4(D_SETSLOTSTATUS, 3182 "schpc_setslotstatus(expander=%d board=%d " 3183 "slot=%d slotstatus=0x%p", expander, board, 3184 SCHPC_SLOT_NUM(slot), (void *)slotstatus); 3185 3186 bzero(&request, sizeof (pcimsg_t)); 3187 3188 if (schpc_p == NULL) { 3189 return (1); 3190 } 3191 3192 request.pcimsg_node = expander; 3193 request.pcimsg_board = board; 3194 request.pcimsg_slot = SCHPC_SLOT_NUM(slot); 3195 request.pcimsg_revision = PCIMSG_REVISION; 3196 request.pcimsg_command = PCIMSG_SETSLOTSTATUS; 3197 3198 request.pcimsg_type.pcimsg_setslot = *slotstatus; 3199 3200 SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change"); 3201 SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d", 3202 slotstatus->slot_led_power, 3203 slotstatus->slot_led_service, 3204 slotstatus->slot_led_fault); 3205 3206 type = MBOXSC_MSG_REQUEST; 3207 cmd = PCIMSG_SETSLOTSTATUS; 3208 transid = schpc_gettransid(schpc_p, slot); 3209 length = sizeof (pcimsg_t); 3210 3211 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3212 "0x%lx transid schpc_putrequest called", transid); 3213 3214 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length, 3215 (void *)&request, schpc_timeout_putmsg, &entry); 3216 3217 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3218 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval); 3219 3220 if (rval) { 3221 return (rval); 3222 } 3223 3224 bzero(&reply, sizeof (pcimsg_t)); 3225 type = MBOXSC_MSG_REPLY; 3226 3227 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3228 "0x%lx transid schpc_getreply called", transid); 3229 3230 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length, 3231 (void *)&reply, schpc_timeout_getmsg, entry); 3232 3233 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3234 "0x%lx transid schpc_getreply returned 0x%x", transid, rval); 3235 3236 if (rval == 0) { 3237 slotstatus->slot_replystatus = 3238 reply.pcimsg_type.pcimsg_setslot.slot_replystatus; 3239 } 3240 3241 return (rval); 3242 } 3243 3244 /* 3245 * schpc_setslotled 3246 * 3247 * Changes the attention indicators for a given slot. 3248 */ 3249 static void 3250 schpc_setslotled(int expander, int board, int slot, uint32_t led_state) 3251 { 3252 3253 pci_setslot_t setslot; 3254 3255 if (schpc_p == NULL) { 3256 return; 3257 } 3258 3259 schpc_init_setslot_message(&setslot); 3260 3261 if (led_state & POWER_LED_ON) { 3262 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON; 3263 } 3264 if (led_state & POWER_LED_OFF) { 3265 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF; 3266 } 3267 if (led_state & POWER_LED_FLASH) { 3268 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH; 3269 } 3270 if (led_state & SERVICE_LED_ON) { 3271 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON; 3272 } 3273 if (led_state & SERVICE_LED_OFF) { 3274 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF; 3275 } 3276 if (led_state & SERVICE_LED_FLASH) { 3277 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH; 3278 } 3279 if (led_state & FAULT_LED_ON) { 3280 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON; 3281 } 3282 if (led_state & FAULT_LED_OFF) { 3283 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF; 3284 } 3285 if (led_state & FAULT_LED_FLASH) { 3286 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH; 3287 } 3288 3289 switch (schpc_p->schpc_slot[slot].led.led_power) { 3290 case PCIMSG_LED_ON: 3291 setslot.slot_led_power = PCIMSG_LED_ON; 3292 break; 3293 case PCIMSG_LED_OFF: 3294 setslot.slot_led_power = PCIMSG_LED_OFF; 3295 break; 3296 case PCIMSG_LED_FLASH: 3297 setslot.slot_led_power = PCIMSG_LED_FLASH; 3298 break; 3299 } 3300 switch (schpc_p->schpc_slot[slot].led.led_service) { 3301 case PCIMSG_LED_ON: 3302 setslot.slot_led_service = PCIMSG_LED_ON; 3303 break; 3304 case PCIMSG_LED_OFF: 3305 setslot.slot_led_service = PCIMSG_LED_OFF; 3306 break; 3307 case PCIMSG_LED_FLASH: 3308 setslot.slot_led_service = PCIMSG_LED_FLASH; 3309 break; 3310 } 3311 switch (schpc_p->schpc_slot[slot].led.led_fault) { 3312 case PCIMSG_LED_ON: 3313 setslot.slot_led_fault = PCIMSG_LED_ON; 3314 break; 3315 case PCIMSG_LED_OFF: 3316 setslot.slot_led_fault = PCIMSG_LED_OFF; 3317 break; 3318 case PCIMSG_LED_FLASH: 3319 setslot.slot_led_fault = PCIMSG_LED_FLASH; 3320 break; 3321 } 3322 3323 (void) schpc_setslotstatus(expander, board, slot, &setslot); 3324 } 3325 3326 /* 3327 * schpc_init_setslot_message 3328 * 3329 * Initialize Set Slot Message before using it. 3330 */ 3331 static void 3332 schpc_init_setslot_message(pci_setslot_t *setslot) 3333 { 3334 /* 3335 * Initialize Set Slot Command. 3336 */ 3337 setslot->slot_power_on = PCIMSG_OFF; 3338 setslot->slot_power_off = PCIMSG_OFF; 3339 setslot->slot_led_power = PCIMSG_LED_OFF; 3340 setslot->slot_led_service = PCIMSG_LED_OFF; 3341 setslot->slot_led_fault = PCIMSG_LED_OFF; 3342 setslot->slot_disable_ENUM = PCIMSG_OFF; 3343 setslot->slot_enable_ENUM = PCIMSG_OFF; 3344 setslot->slot_disable_HEALTHY = PCIMSG_OFF; 3345 setslot->slot_enable_HEALTHY = PCIMSG_OFF; 3346 } 3347 3348 /* 3349 * schpc_gettransid 3350 * 3351 * Builds a unique transaction ID. 3352 */ 3353 static uint64_t 3354 schpc_gettransid(schpc_t *schpc_p, int slot) 3355 { 3356 uint64_t trans_id; 3357 3358 mutex_enter(&schpc_p->schpc_mutex); 3359 3360 if (++schpc_p->schpc_transid == 0) 3361 schpc_p->schpc_transid = 1; 3362 3363 trans_id = (schpc_p->schpc_slot[slot].expander<<24) | 3364 (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid; 3365 3366 mutex_exit(&schpc_p->schpc_mutex); 3367 3368 SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning", 3369 trans_id); 3370 3371 return (trans_id); 3372 } 3373 3374 /* 3375 * schpc_slot_get_index 3376 * 3377 * get slot table index from the slot handle 3378 */ 3379 static int 3380 schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot) 3381 { 3382 int i; 3383 int rval = -1; 3384 3385 ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex)); 3386 3387 for (i = 0; i < schpc_p->schpc_number_of_slots; i++) { 3388 if (schpc_p->schpc_slot[i].slot_handle == slot) 3389 return (i); 3390 } 3391 3392 return (rval); 3393 } 3394 3395 /* 3396 * schpc_register_all_slots 3397 * 3398 * Search device tree for pci nodes and register attachment points 3399 * for all hot pluggable slots. 3400 */ 3401 /*ARGSUSED*/ 3402 static void 3403 schpc_register_all_slots(schpc_t *schpc_p) 3404 { 3405 int slot = 0; 3406 char caddr[64]; 3407 dev_info_t *pci_dip = NULL; 3408 find_dev_t find_dev; 3409 int leaf, schizo, expander, portid, offset; 3410 3411 SCHPC_DEBUG1(D_ATTACH, 3412 "schpc_register_all_slots(schpc_p=%p)", (void *)schpc_p); 3413 3414 /* 3415 * Allow the event_handler to start processing unsolicited 3416 * events now that slots are about to be registered. 3417 */ 3418 slots_registered = B_TRUE; 3419 3420 for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) { 3421 3422 leaf = SCHPC_SLOT_LEAF(slot); 3423 schizo = SCHPC_SLOT_SCHIZO(slot); 3424 expander = SCHPC_SLOT_EXPANDER(slot); 3425 3426 if (schizo == 0) 3427 portid = 0x1c; 3428 else 3429 portid = 0x1d; 3430 3431 if (leaf == 0) 3432 offset = 0x600000; 3433 else 3434 offset = 0x700000; 3435 3436 portid = (expander << 5) | portid; 3437 3438 (void) sprintf(caddr, "%x,%x", portid, offset); 3439 3440 SCHPC_DEBUG3(D_ATTACH, 3441 "schpc_register_all_slots: searching for pci@%s" 3442 " schizo=%d, leaf=%d", caddr, schizo, leaf); 3443 3444 find_dev.cname = "pci"; 3445 find_dev.caddr = caddr; 3446 find_dev.schizo = schizo; 3447 find_dev.leaf = leaf; 3448 find_dev.dip = NULL; 3449 3450 /* root node doesn't have to be held */ 3451 ddi_walk_devs(ddi_root_node(), schpc_match_dip, 3452 &find_dev); 3453 3454 pci_dip = find_dev.dip; 3455 3456 if (pci_dip == NULL) { 3457 3458 SCHPC_DEBUG1(D_ATTACH, 3459 "schpc_register_all_slots: pci@%s NOT FOUND", 3460 caddr); 3461 3462 continue; 3463 } 3464 3465 SCHPC_DEBUG2(D_ATTACH, 3466 "schpc_register_all_slots: pci@%s FOUND dip=0x%p", 3467 caddr, (void *)pci_dip); 3468 3469 (void) schpc_add_pci(pci_dip); 3470 3471 /* 3472 * Release hold acquired in schpc_match_dip() 3473 */ 3474 ndi_rele_devi(pci_dip); 3475 } 3476 3477 SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit"); 3478 3479 thread_exit(); 3480 } 3481 3482 /* 3483 * schpc_add_pci 3484 * 3485 * Routine to add attachments points associated with a pci node. 3486 * Can be call externally by DR when configuring a PCI I/O Board. 3487 */ 3488 int 3489 schpc_add_pci(dev_info_t *bdip) 3490 { 3491 int portid; 3492 int expander, board, schizo, leaf, slot, status; 3493 char ap_id[MAXNAMELEN]; 3494 char caddr[64]; 3495 char *naddr; 3496 hpc_slot_info_t slot_info; 3497 hpc_slot_ops_t *slot_ops; 3498 dev_info_t *sdip = bdip; 3499 3500 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", (void *)sdip); 3501 3502 if (schpc_p == NULL) { 3503 /* 3504 * The schpc driver has not been attached yet. 3505 */ 3506 return (DDI_SUCCESS); 3507 } 3508 3509 if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) { 3510 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n", 3511 (void *)sdip); 3512 return (DDI_FAILURE); 3513 } 3514 3515 expander = schpc_getexpander(sdip); 3516 board = schpc_getboard(sdip); 3517 3518 switch (portid & 0x1f) { 3519 3520 case 0x1c: 3521 schizo = 0; 3522 break; 3523 case 0x1d: 3524 schizo = 1; 3525 break; 3526 default: 3527 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 3528 "Invalid pci portid 0x%x\n", (void *)sdip, portid); 3529 return (DDI_FAILURE); 3530 } 3531 3532 naddr = ddi_get_name_addr(sdip); 3533 if (naddr == NULL) { 3534 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr" 3535 "(0x%p) returns null", (void *)sdip); 3536 return (DDI_FAILURE); 3537 } 3538 3539 (void) sprintf(caddr, "%x,600000", portid); 3540 3541 if (strcmp(caddr, naddr) == 0) { 3542 leaf = 0; 3543 } else { 3544 (void) sprintf(caddr, "%x,700000", portid); 3545 if (strcmp(caddr, naddr) == 0) { 3546 char *name; 3547 3548 leaf = 1; 3549 name = ddi_binding_name(sdip); 3550 if ((strcmp(name, "pci108e,8002") == 0) && 3551 (schizo == 0)) { 3552 int circ; 3553 dev_info_t *cdip; 3554 /* 3555 * XMITS 0 Leaf B will have its hot 3556 * pluggable slot off a PCI-PCI bridge, 3557 * which is the only child. 3558 */ 3559 ndi_devi_enter(sdip, &circ); 3560 cdip = ddi_get_child(sdip); 3561 if (cdip == NULL) { 3562 cmn_err(CE_WARN, 3563 "schpc_add_pci(dip=0x%p) - " 3564 "Invalid pci name addr %s\n", 3565 (void *)sdip, naddr); 3566 ndi_devi_exit(sdip, circ); 3567 return (DDI_FAILURE); 3568 } 3569 ndi_devi_exit(sdip, circ); 3570 sdip = cdip; 3571 } 3572 } else { 3573 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 3574 "Invalid pci name addr %s\n", (void *)sdip, naddr); 3575 return (DDI_FAILURE); 3576 } 3577 } 3578 3579 /* create a slot table index */ 3580 slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf); 3581 3582 if (schpc_p->schpc_slot[slot].devi) { 3583 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 3584 "pci node already registered\n", (void *)sdip); 3585 return (DDI_FAILURE); 3586 } 3587 3588 /* 3589 * There is no need to hold the dip while saving it in 3590 * the devi field below. The dip is never dereferenced. 3591 * (If that changes, this code should be modified). 3592 * We want to avoid holding the dip here because it 3593 * prevents DR. 3594 * 3595 * NOTE: Even though the slot on XMITS0 Leaf-B 3596 * is connected to a pci_pci bridge, we will be saving 3597 * the busdip in this datastructure. This will make 3598 * it easier to identify the dip being removed in 3599 * schpc_remove_pci(). 3600 */ 3601 schpc_p->schpc_slot[slot].devi = bdip; 3602 3603 schpc_p->schpc_slot[slot].expander = expander; 3604 schpc_p->schpc_slot[slot].board = board; 3605 schpc_p->schpc_slot[slot].schizo = schizo; 3606 schpc_p->schpc_slot[slot].leaf = leaf; 3607 3608 /* 3609 * Starcat PCI slots are always PCI device 1. 3610 */ 3611 schpc_p->schpc_slot[slot].pci_id = 1; 3612 3613 schpc_buildapid(sdip, slot, (char *)&ap_id); 3614 3615 (void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id); 3616 3617 /* safe to call ddi_pathname(): bdip is held */ 3618 (void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path); 3619 3620 status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot)); 3621 switch (status) { 3622 case RSV_UNKNOWN: 3623 case RSV_PRESENT: 3624 case RSV_MISS: 3625 case RSV_PASS: 3626 case RSV_EMPTY_CASSETTE: 3627 3628 /* 3629 * Test the condition of the slot. 3630 */ 3631 schpc_test((caddr_t)schpc_p, slot, 0, 0); 3632 break; 3633 case RSV_BLACK: 3634 schpc_p->schpc_slot[slot].state = 0; 3635 cmn_err(CE_WARN, "schpc: PCI card blacklisted: " 3636 "expander=%d board=%d slot=%d\n", expander, 3637 board, SCHPC_SLOT_NUM(slot)); 3638 break; 3639 default: 3640 schpc_p->schpc_slot[slot].state = 0; 3641 cmn_err(CE_WARN, "schpc: PCI card failed by POST: " 3642 "expander=%d board=%d slot=%d failure=0x%x\n", 3643 expander, board, SCHPC_SLOT_NUM(slot), status); 3644 break; 3645 } 3646 3647 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) { 3648 3649 /* allocate slot ops */ 3650 3651 slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 3652 schpc_p->schpc_slot[slot].slot_ops = slot_ops; 3653 3654 /* 3655 * Default to Autoconfiguration disabled. 3656 */ 3657 schpc_p->schpc_slot[slot].state &= 3658 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 3659 3660 /* 3661 * Fill in the slot information structure that 3662 * describes the slot. 3663 */ 3664 slot_info.version = HPC_SLOT_OPS_VERSION; 3665 3666 if (schpc_p->schpc_hotplugmodel == 3667 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) 3668 slot_info.slot_type = HPC_SLOT_TYPE_PCI; 3669 else 3670 slot_info.slot_type = HPC_SLOT_TYPE_CPCI; 3671 3672 slot_info.slot.pci.device_number = 3673 schpc_p->schpc_slot[slot].pci_id; 3674 3675 slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS; 3676 3677 if (schpc_use_legacy_apid) 3678 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE; 3679 else 3680 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE | 3681 HPC_SLOT_CREATE_DEVLINK; 3682 3683 (void) strcpy(slot_info.slot.pci.slot_logical_name, 3684 schpc_p->schpc_slot[slot].ap_id); 3685 3686 /* 3687 * Fill in the slot ops structure that tells 3688 * the Hot Plug Services what function we 3689 * support. 3690 */ 3691 slot_ops->hpc_version = HPC_SLOT_OPS_VERSION; 3692 if (schpc_p->schpc_hotplugmodel == 3693 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) { 3694 slot_ops->hpc_op_connect = schpc_connect; 3695 slot_ops->hpc_op_disconnect = schpc_disconnect; 3696 slot_ops->hpc_op_insert = NULL; 3697 slot_ops->hpc_op_remove = NULL; 3698 slot_ops->hpc_op_control = schpc_pci_control; 3699 } else { 3700 slot_ops->hpc_op_connect = NULL; 3701 slot_ops->hpc_op_disconnect = NULL; 3702 slot_ops->hpc_op_insert = NULL; 3703 slot_ops->hpc_op_remove = NULL; 3704 slot_ops->hpc_op_control = schpc_cpci_control; 3705 } 3706 3707 SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC " 3708 "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s", 3709 schpc_p->schpc_slot[slot].nexus_path, 3710 (void *)schpc_p, SCHPC_SLOT_NUM(slot), 3711 slot_info.slot.pci.device_number, 3712 slot_info.slot.pci.slot_logical_name); 3713 3714 if (hpc_slot_register(schpc_p->schpc_devi, 3715 schpc_p->schpc_slot[slot].nexus_path, &slot_info, 3716 &schpc_p->schpc_slot[slot].slot_handle, 3717 slot_ops, (caddr_t)schpc_p, 0) != 0) { 3718 3719 /* 3720 * If the slot can not be registered, 3721 * then the slot_ops need to be freed. 3722 */ 3723 cmn_err(CE_WARN, "schpc%d Unable to Register " 3724 "Slot %s", schpc_p->schpc_instance, 3725 slot_info.slot.pci.slot_logical_name); 3726 3727 hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops); 3728 3729 schpc_p->schpc_slot[slot].slot_ops = NULL; 3730 3731 return (DDI_FAILURE); 3732 } 3733 3734 /* 3735 * We are ready to take commands from the HPC Services. 3736 */ 3737 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED; 3738 } 3739 3740 return (DDI_SUCCESS); 3741 } 3742 3743 /* 3744 * schpc_remove_pci 3745 * 3746 * Routine to remove attachments points associated with a pci node. 3747 * Can be call externally by DR when unconfiguring a PCI I/O Board. 3748 */ 3749 int 3750 schpc_remove_pci(dev_info_t *dip) 3751 { 3752 int slot; 3753 3754 SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", (void *)dip); 3755 3756 if (schpc_p == NULL) { 3757 /* 3758 * The schpc driver has not been attached yet. 3759 */ 3760 return (DDI_SUCCESS); 3761 } 3762 3763 for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) { 3764 if (schpc_p->schpc_slot[slot].devi == dip) { 3765 3766 if (schpc_p->schpc_slot[slot].slot_ops) { 3767 if (hpc_slot_unregister( 3768 &schpc_p->schpc_slot[slot].slot_handle)) { 3769 cmn_err(CE_WARN, 3770 "schpc_remove_pci(dip=0x%p) - " 3771 "unable to unregister pci slots\n", 3772 (void *)dip); 3773 return (DDI_FAILURE); 3774 } else { 3775 hpc_free_slot_ops( 3776 schpc_p->schpc_slot[slot].slot_ops); 3777 3778 schpc_p->schpc_slot[slot].slot_ops = 3779 NULL; 3780 3781 schpc_p->schpc_slot[slot].devi = NULL; 3782 3783 return (DDI_SUCCESS); 3784 } 3785 } else { 3786 schpc_p->schpc_slot[slot].devi = NULL; 3787 3788 return (DDI_SUCCESS); 3789 } 3790 } 3791 } 3792 3793 cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) " 3794 "dip not found\n", (void *)dip); 3795 3796 return (DDI_SUCCESS); 3797 } 3798 3799 /* 3800 * schpc_match_dip 3801 * 3802 * Used by ddi_walk_devs to find PCI Nexus nodes associated with 3803 * Hot Plug Controllers. 3804 */ 3805 static int 3806 schpc_match_dip(dev_info_t *dip, void *arg) 3807 { 3808 char *naddr; 3809 find_dev_t *find_dev = (find_dev_t *)arg; 3810 3811 if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 && 3812 ((((naddr = ddi_get_name_addr(dip)) != NULL) && 3813 (strcmp(find_dev->caddr, naddr) == 0)) || 3814 ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) { 3815 /* 3816 * While ddi_walk_devs() holds dips when invoking this 3817 * callback, this dip is being saved and will be accessible 3818 * to the caller outside ddi_walk_devs(). Therefore it must be 3819 * held. 3820 */ 3821 ndi_hold_devi(dip); 3822 find_dev->dip = dip; 3823 3824 SCHPC_DEBUG2(D_ATTACH, 3825 "schpc_match_dip: pci@%s FOUND dip=0x%p", 3826 find_dev->caddr, (void *)find_dev->dip); 3827 3828 return (DDI_WALK_TERMINATE); 3829 } 3830 3831 ASSERT(find_dev->dip == NULL); 3832 return (DDI_WALK_CONTINUE); 3833 } 3834 3835 /* 3836 * schpc_buildapid 3837 * 3838 * Takes a component address and translates it into a ap_id prefix. 3839 */ 3840 static void 3841 schpc_buildapid(dev_info_t *dip, int slot, char *ap_id) 3842 { 3843 int r, pci_id_cnt, pci_id_bit; 3844 int slots_before, found; 3845 unsigned char *slot_names_data, *s; 3846 int slot_names_size; 3847 int slot_num; 3848 unsigned int bit_mask; 3849 3850 slot_num = SCHPC_SLOT_NUM(slot); 3851 3852 if (schpc_use_legacy_apid) { 3853 SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot); 3854 3855 (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip), 3856 schpc_getboard(dip), slot_num); 3857 3858 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id); 3859 3860 return; 3861 } 3862 3863 r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3864 "slot-names", (caddr_t)&slot_names_data, 3865 &slot_names_size); 3866 3867 if (r == DDI_PROP_SUCCESS) { 3868 3869 /* 3870 * We can try to use the slot-names property to 3871 * build our ap-id. 3872 */ 3873 bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) | 3874 (slot_names_data[1] << 16) | (slot_names_data[0] << 24); 3875 3876 pci_id_bit = 1; 3877 pci_id_cnt = slots_before = found = 0; 3878 3879 SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x", 3880 slot, bit_mask); 3881 3882 /* 3883 * Walk the bit mask until we find the bit that corresponds 3884 * to our slots device number. We count how many bits 3885 * we find before we find our slot's bit. 3886 */ 3887 while (!found && (pci_id_cnt < 32)) { 3888 3889 while (schpc_p->schpc_slot[slot].pci_id 3890 != pci_id_cnt) { 3891 3892 /* 3893 * Find the next bit set. 3894 */ 3895 while (!(bit_mask & pci_id_bit) && 3896 (pci_id_cnt < 32)) { 3897 pci_id_bit = pci_id_bit << 1; 3898 pci_id_cnt++; 3899 } 3900 3901 if (schpc_p->schpc_slot[slot].pci_id != 3902 pci_id_cnt) 3903 slots_before++; 3904 else 3905 found = 1; 3906 } 3907 } 3908 3909 if (pci_id_cnt < 32) { 3910 3911 /* 3912 * Set ptr to first string. 3913 */ 3914 s = slot_names_data + 4; 3915 3916 /* 3917 * Increment past all the strings for the slots 3918 * before ours. 3919 */ 3920 while (slots_before) { 3921 while (*s != NULL) 3922 s++; 3923 s++; 3924 slots_before--; 3925 } 3926 3927 /* 3928 * We should be at our string. 3929 */ 3930 3931 (void) sprintf(ap_id, "IO%d_%s", 3932 schpc_getexpander(dip), s); 3933 3934 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", 3935 slot, ap_id); 3936 3937 kmem_free(slot_names_data, slot_names_size); 3938 return; 3939 } 3940 3941 SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found", 3942 slot); 3943 3944 kmem_free(slot_names_data, slot_names_size); 3945 } else 3946 SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found", 3947 slot); 3948 3949 /* 3950 * Build the ap-id using the legacy naming scheme. 3951 */ 3952 (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip), 3953 schpc_getboard(dip), slot_num); 3954 3955 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id); 3956 } 3957 3958 /* 3959 * schpc_getexpander 3960 * 3961 * Returns the Expander Number (0-17) for the dip passed in. The Expander 3962 * Number is extracted from the portid property of the pci node. Portid 3963 * consists of <Expbrd#><1110x>, where x is the schizo number. 3964 */ 3965 static int 3966 schpc_getexpander(dev_info_t *dip) 3967 { 3968 int id; 3969 3970 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1); 3971 3972 if (id != -1) 3973 return (id >> 5); 3974 else { 3975 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1); 3976 return (id); 3977 } 3978 } 3979 3980 /* 3981 * schpc_getboard 3982 * 3983 * Returns the board number (0 or 1) for the dip passed in. 3984 */ 3985 static int 3986 schpc_getboard(dev_info_t *dip) 3987 { 3988 _NOTE(ARGUNUSED(dip)) 3989 3990 /* 3991 * Hot Pluggable PCI/cPCI slots are only available on 3992 * Board 1 (half-bandwidth slot). 3993 */ 3994 return (1); 3995 } 3996 3997 /*ARGSUSED*/ 3998 static int 3999 schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot) 4000 { 4001 gdcd_t *gdcd; 4002 int prd_slot, status, bus; 4003 4004 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() " 4005 "exp=%d board=%d slot=%d", expander, board, slot); 4006 4007 if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t), 4008 KM_SLEEP)) == NULL) { 4009 return (RSV_UNDEFINED); 4010 } 4011 4012 /* 4013 * Get the Starcat Specific Global DCD Structure from the golden 4014 * IOSRAM. 4015 */ 4016 if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) { 4017 cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD " 4018 "From IOSRAM\n"); 4019 kmem_free(gdcd, sizeof (gdcd_t)); 4020 return (RSV_UNDEFINED); 4021 } 4022 4023 if (gdcd->h.dcd_magic != GDCD_MAGIC) { 4024 4025 cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n", 4026 gdcd->h.dcd_magic); 4027 4028 kmem_free(gdcd, sizeof (gdcd_t)); 4029 return (RSV_UNDEFINED); 4030 } 4031 4032 if (gdcd->h.dcd_version != DCD_VERSION) { 4033 cmn_err(CE_WARN, "schpc: GDCD Bad Version: " 4034 "GDCD Version 0x%x Expecting 0x%x\n", 4035 gdcd->h.dcd_version, DCD_VERSION); 4036 4037 kmem_free(gdcd, sizeof (gdcd_t)); 4038 return (RSV_UNDEFINED); 4039 } 4040 4041 if (slot < 2) 4042 prd_slot = 4; 4043 else 4044 prd_slot = 5; 4045 4046 bus = slot & 0x1; 4047 4048 status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0]; 4049 4050 kmem_free(gdcd, sizeof (gdcd_t)); 4051 4052 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() " 4053 "prd_slot=%d bus=%d status=%d", prd_slot, bus, status); 4054 4055 return (status); 4056 } 4057 4058 #define LEAF_SAVE_END 0xff 4059 4060 typedef struct { 4061 int reg; 4062 int offset; 4063 int access_size; 4064 int number; 4065 } save_reg_list_t; 4066 4067 /* 4068 * Save List Array. Describes the leaf registers that need to 4069 * be restored after a leaf reset. 4070 * 4071 * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space 4072 * Entry 2 - Offset Start 4073 * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit 4074 * Entry 4 - # of registers to be saved starting at offset, 4075 */ 4076 save_reg_list_t save_reg_list[] = { 0, 0x110, 8, 1, 4077 0, 0x200, 8, 2, 4078 0, 0x1000, 8, 0x18, 4079 0, 0x1a00, 8, 1, 4080 0, 0x2000, 8, 1, 4081 0, 0x2020, 8, 1, 4082 0, 0x2040, 8, 1, 4083 0, 0x2308, 8, 2, 4084 0, 0x2800, 8, 1, 4085 2, 0x04, 2, 1, /* Command */ 4086 2, 0x0d, 1, 1, /* Latency */ 4087 2, 0x40, 1, 1, /* Bus # */ 4088 2, 0x41, 1, 1, /* Sub. Bus # */ 4089 LEAF_SAVE_END, 0, 0, 0}; 4090 4091 static int 4092 schpc_save_leaf(int slot) 4093 { 4094 int save_entry, list_entry, reg; 4095 caddr_t leaf_regs; 4096 ddi_device_acc_attr_t attr; 4097 4098 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot); 4099 4100 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 4101 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 4102 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 4103 4104 /* 4105 * Map in the 3 addresses spaces defined for XMITS. 4106 */ 4107 for (reg = 0; reg < 3; reg++) { 4108 if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg, 4109 &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot]. 4110 saved_handle[reg]) != DDI_SUCCESS) { 4111 cmn_err(CE_WARN, "Mapin failed\n"); 4112 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL; 4113 return (1); 4114 } 4115 4116 schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs; 4117 } 4118 4119 4120 /* 4121 * Determine how many entries are in the list so we can 4122 * allocate the save space. 4123 */ 4124 list_entry = 0; 4125 save_entry = 0; 4126 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 4127 save_entry += save_reg_list[list_entry].number; 4128 list_entry++; 4129 } 4130 4131 schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t)); 4132 4133 if (schpc_p->schpc_slot[slot].saved_size == 0) 4134 return (0); 4135 4136 schpc_p->schpc_slot[slot].saved_regs = 4137 (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size, 4138 KM_SLEEP); 4139 4140 /* 4141 * Walk through the register list and save contents. 4142 */ 4143 list_entry = 0; 4144 save_entry = 0; 4145 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 4146 schpc_save_entry(slot, list_entry, save_entry); 4147 save_entry += save_reg_list[list_entry].number; 4148 list_entry ++; 4149 } 4150 4151 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot); 4152 4153 return (0); 4154 } 4155 4156 static void 4157 schpc_restore_leaf(int slot) 4158 { 4159 int save_entry, list_entry, reg; 4160 4161 if (schpc_p->schpc_slot[slot].saved_regs == NULL) 4162 return; 4163 4164 /* 4165 * Walk through the register list and restore contents. 4166 */ 4167 list_entry = 0; 4168 save_entry = 0; 4169 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 4170 4171 schpc_restore_entry(slot, list_entry, save_entry); 4172 4173 save_entry += save_reg_list[list_entry].number; 4174 list_entry ++; 4175 } 4176 4177 /* 4178 * Free the mapped in registers. 4179 */ 4180 for (reg = 0; reg < 3; reg++) { 4181 if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) { 4182 4183 ddi_regs_map_free( 4184 &schpc_p->schpc_slot[slot].saved_handle[reg]); 4185 4186 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL; 4187 } 4188 } 4189 4190 kmem_free(schpc_p->schpc_slot[slot].saved_regs, 4191 schpc_p->schpc_slot[slot].saved_size); 4192 4193 schpc_p->schpc_slot[slot].saved_size = 0; 4194 schpc_p->schpc_slot[slot].saved_regs = NULL; 4195 4196 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot); 4197 } 4198 4199 static void 4200 schpc_save_entry(int slot, int list_entry, int save_entry) 4201 { 4202 int reg, reads = 0; 4203 4204 reg = save_reg_list[list_entry].reg; 4205 4206 while (reads < save_reg_list[list_entry].number) { 4207 switch (save_reg_list[list_entry].access_size) { 4208 case 8: 4209 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4210 ddi_get64( 4211 schpc_p->schpc_slot[slot].saved_handle[reg], 4212 (uint64_t *)(schpc_p->schpc_slot[slot]. 4213 saved_regs_va[reg] 4214 + save_reg_list[list_entry].offset + 4215 (reads * sizeof (uint64_t)))); 4216 #ifdef DEBUG 4217 if (schpc_dump_save_regs) 4218 cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg, 4219 save_reg_list[list_entry].offset + 4220 (reads * sizeof (uint64_t)), 4221 schpc_p->schpc_slot[slot]. 4222 saved_regs[save_entry]); 4223 #endif 4224 4225 break; 4226 case 4: 4227 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4228 ddi_get32( 4229 schpc_p->schpc_slot[slot].saved_handle[reg], 4230 (uint32_t *)(schpc_p->schpc_slot[slot]. 4231 saved_regs_va[reg] 4232 + save_reg_list[list_entry].offset + 4233 (reads * sizeof (uint32_t)))); 4234 4235 #ifdef DEBUG 4236 if (schpc_dump_save_regs) 4237 cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg, 4238 save_reg_list[list_entry].offset + 4239 (reads * sizeof (uint32_t)), 4240 schpc_p->schpc_slot[slot]. 4241 saved_regs[save_entry]); 4242 #endif 4243 4244 break; 4245 case 2: 4246 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4247 ddi_get16( 4248 schpc_p->schpc_slot[slot].saved_handle[reg], 4249 (uint16_t *)(schpc_p->schpc_slot[slot]. 4250 saved_regs_va[reg] 4251 + save_reg_list[list_entry].offset + 4252 (reads * sizeof (uint16_t)))); 4253 4254 #ifdef DEBUG 4255 if (schpc_dump_save_regs) 4256 cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg, 4257 save_reg_list[list_entry].offset + 4258 (reads * sizeof (uint16_t)), 4259 schpc_p->schpc_slot[slot]. 4260 saved_regs[save_entry]); 4261 #endif 4262 4263 break; 4264 case 1: 4265 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4266 ddi_get8( 4267 schpc_p->schpc_slot[slot].saved_handle[reg], 4268 (uint8_t *)(schpc_p->schpc_slot[slot]. 4269 saved_regs_va[reg] 4270 + save_reg_list[list_entry].offset + 4271 (reads * sizeof (uint8_t)))); 4272 4273 #ifdef DEBUG 4274 if (schpc_dump_save_regs) 4275 cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg, 4276 save_reg_list[list_entry].offset + 4277 (reads * sizeof (uint8_t)), 4278 schpc_p->schpc_slot[slot]. 4279 saved_regs[save_entry]); 4280 #endif 4281 4282 break; 4283 default: 4284 cmn_err(CE_WARN, 4285 "schpc: Illegal List Entry\n"); 4286 } 4287 reads++; 4288 save_entry++; 4289 } 4290 } 4291 4292 static void 4293 schpc_restore_entry(int slot, int list_entry, int save_entry) 4294 { 4295 int reg, writes = 0; 4296 4297 reg = save_reg_list[list_entry].reg; 4298 4299 while (writes < save_reg_list[list_entry].number) { 4300 switch (save_reg_list[list_entry].access_size) { 4301 case 8: 4302 #ifdef DEBUG 4303 if (schpc_dump_save_regs) 4304 cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg, 4305 save_reg_list[list_entry].offset + 4306 (writes * sizeof (uint64_t)), 4307 schpc_p->schpc_slot[slot]. 4308 saved_regs[save_entry]); 4309 #endif 4310 4311 ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg], 4312 (uint64_t *)(schpc_p->schpc_slot[slot]. 4313 saved_regs_va[reg] 4314 + save_reg_list[list_entry].offset + 4315 (writes * sizeof (uint64_t))), 4316 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4317 4318 break; 4319 case 4: 4320 #ifdef DEBUG 4321 if (schpc_dump_save_regs) 4322 cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg, 4323 save_reg_list[list_entry].offset + 4324 (writes * sizeof (uint32_t)), 4325 schpc_p->schpc_slot[slot]. 4326 saved_regs[save_entry]); 4327 #endif 4328 4329 ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg], 4330 (uint32_t *)(schpc_p->schpc_slot[slot]. 4331 saved_regs_va[reg] 4332 + save_reg_list[list_entry].offset + 4333 (writes * sizeof (uint32_t))), 4334 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4335 4336 break; 4337 case 2: 4338 #ifdef DEBUG 4339 if (schpc_dump_save_regs) 4340 cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg, 4341 save_reg_list[list_entry].offset + 4342 (writes * sizeof (uint16_t)), 4343 schpc_p->schpc_slot[slot]. 4344 saved_regs[save_entry]); 4345 #endif 4346 4347 ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg], 4348 (uint16_t *)(schpc_p->schpc_slot[slot]. 4349 saved_regs_va[reg] 4350 + save_reg_list[list_entry].offset + 4351 (writes * sizeof (uint16_t))), 4352 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4353 4354 break; 4355 case 1: 4356 #ifdef DEBUG 4357 if (schpc_dump_save_regs) 4358 cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg, 4359 save_reg_list[list_entry].offset + 4360 (writes * sizeof (uint8_t)), 4361 schpc_p->schpc_slot[slot]. 4362 saved_regs[save_entry]); 4363 #endif 4364 4365 ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg], 4366 (uint8_t *)(schpc_p->schpc_slot[slot]. 4367 saved_regs_va[reg] 4368 + save_reg_list[list_entry].offset + 4369 (writes * sizeof (uint8_t))), 4370 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4371 4372 break; 4373 default: 4374 cmn_err(CE_WARN, 4375 "schpc: Illegal List Entry\n"); 4376 } 4377 writes++; 4378 save_entry++; 4379 } 4380 } 4381 4382 /* 4383 * Returns TRUE if a leaf reset is required to change frequencies/mode. 4384 */ 4385 static int 4386 schpc_is_leaf_reset_required(int slot) 4387 { 4388 char *name; 4389 int32_t mod_rev; 4390 4391 /* 4392 * Only XMITS 3.0 and greater connected slots will require a 4393 * reset to switch frequency and/or mode. 4394 */ 4395 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi); 4396 4397 if (strcmp(name, "pci108e,8002") == 0) { 4398 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY, 4399 schpc_p->schpc_slot[slot].devi, 4400 DDI_PROP_DONTPASS, "module-revision#", 0); 4401 4402 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev); 4403 4404 /* 4405 * Check for XMITS 3.0 or greater. 4406 */ 4407 if (mod_rev >= XMITS_30) { 4408 4409 /* 4410 * The leaf attached to C5V0 (slot 1) should 4411 * not be reset. 4412 */ 4413 if ((slot & 3) == 1) { 4414 4415 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset " 4416 "Not Required - C5V0", slot); 4417 4418 return (0); 4419 } 4420 4421 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset " 4422 "Required", slot); 4423 4424 return (1); 4425 } 4426 } 4427 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot); 4428 4429 return (0); 4430 } 4431 4432 /* 4433 * Returns TRUE if the bus can change frequencies. 4434 */ 4435 static int 4436 schpc_is_freq_switchable(int slot) 4437 { 4438 char *name; 4439 int32_t mod_rev; 4440 4441 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi); 4442 4443 if (strcmp(name, "pci108e,8002") == 0) { 4444 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY, 4445 schpc_p->schpc_slot[slot].devi, 4446 DDI_PROP_DONTPASS, "module-revision#", 0); 4447 4448 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev); 4449 4450 /* 4451 * We will only report back that XMITS 2.0 (mod_rev = 2) 4452 * or greater will have the ability to switch frequencies. 4453 */ 4454 if (mod_rev >= XMITS_20) { 4455 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - " 4456 "Frequency is switchable", slot); 4457 return (1); 4458 } 4459 } 4460 4461 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot); 4462 return (0); 4463 } 4464 4465 /* 4466 * schpc_slot_freq 4467 * 4468 * Convert the slot frequency setting to integer value. 4469 */ 4470 static int 4471 schpc_slot_freq(pci_getslot_t *getslotp) 4472 { 4473 switch (getslotp->slot_freq_setting) { 4474 case PCIMSG_FREQ_33MHZ: 4475 return (SCHPC_33MHZ); 4476 case PCIMSG_FREQ_66MHZ: 4477 return (SCHPC_66MHZ); 4478 case PCIMSG_FREQ_90MHZ: 4479 return (SCHPC_90MHZ); 4480 case PCIMSG_FREQ_133MHZ: 4481 return (SCHPC_133MHZ); 4482 default: 4483 return (0); 4484 } 4485 } 4486 4487 /* 4488 * schpc_find_dip 4489 * 4490 * Used by ddi_walk_devs to find the dip which belongs 4491 * to a certain slot. 4492 * 4493 * When this function returns, the dip is held. It is the 4494 * responsibility of the caller to release the dip. 4495 */ 4496 static int 4497 schpc_find_dip(dev_info_t *dip, void *arg) 4498 { 4499 find_dev_t *find_dev = (find_dev_t *)arg; 4500 char *pathname = find_dev->caddr; 4501 4502 (void) ddi_pathname(dip, pathname); 4503 if (strcmp(find_dev->cname, pathname) == 0) { 4504 ndi_hold_devi(dip); 4505 find_dev->dip = dip; 4506 return (DDI_WALK_TERMINATE); 4507 } 4508 return (DDI_WALK_CONTINUE); 4509 } 4510