1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * 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 ops_arg, 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 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)", ops_arg, slot_hdl); 973 974 mutex_enter(&schpc_p->schpc_mutex); 975 976 slot = schpc_slot_get_index(schpc_p, slot_hdl); 977 978 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 979 SCHPC_DEBUG0(D_IOC_CONNECT, 980 "schpc_disconnect - HPC Not Inited"); 981 mutex_exit(&schpc_p->schpc_mutex); 982 return (HPC_ERR_FAILED); 983 } 984 985 /* 986 * Check to see if we are already disconnected. 987 */ 988 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) { 989 mutex_exit(&schpc_p->schpc_mutex); 990 return (0); 991 } 992 993 /* 994 * Block if another thread is executing a HPC command. 995 */ 996 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 997 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 998 } 999 1000 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 1001 1002 mutex_exit(&schpc_p->schpc_mutex); 1003 1004 expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 1005 board = schpc_p->schpc_slot[slot].board; /* get board */ 1006 1007 /* 1008 * If a leaf reset is going to be asserted due to a mode/freq. 1009 * change, then the leaf registers of the XMITS bridge will need 1010 * to be saved off prior to the connect. 1011 */ 1012 if (schpc_is_leaf_reset_required(slot)) { 1013 if (schpc_save_leaf(slot) != 0) { 1014 1015 cmn_err(CE_WARN, "schpc - Unable to save leaf regs on " 1016 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ", 1017 expander, board, slot & 3, 1018 schpc_p->schpc_slot[slot].ap_id); 1019 1020 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 1021 1022 goto failed; 1023 } 1024 } 1025 1026 /* 1027 * Initialize Set Slot Command. 1028 */ 1029 schpc_init_setslot_message(&setslot); 1030 1031 setslot.slot_power_off = PCIMSG_ON; /* Turn Power Off */ 1032 1033 setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */ 1034 1035 setslot.slot_disable_ENUM = PCIMSG_ON; /* Mask the ENUM# signal */ 1036 setslot.slot_disable_HEALTHY = PCIMSG_ON; /* Mask the HEALTHY# sig */ 1037 1038 rval = schpc_setslotstatus(expander, board, slot, &setslot); 1039 1040 SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - " 1041 "setslotstatus returned 0x%x", rval); 1042 1043 if (rval != 0) { 1044 /* 1045 * System Controller/Mailbox failure. 1046 */ 1047 cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on " 1048 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 1049 "Communicate with System Controller", expander, board, 1050 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 1051 1052 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 1053 1054 goto failed; 1055 } 1056 1057 SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - " 1058 "slot_replystatus returned 0x%x", setslot.slot_replystatus); 1059 1060 if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) { 1061 1062 /* 1063 * The Request was successfully completed. 1064 */ 1065 schpc_p->schpc_slot[slot].state &= 1066 ~SCHPC_SLOTSTATE_CONNECTED; 1067 1068 schpc_setslotled(expander, board, slot, 1069 (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF)); 1070 1071 SCHPC_DEBUG0(D_IOC_CONNECT, 1072 "schpc_disconnect() - setslotstatus succeeded"); 1073 1074 mutex_enter(&schpc_p->schpc_mutex); 1075 schpc_p->schpc_slot[slot].state &= 1076 ~SCHPC_SLOTSTATE_EXECUTING; 1077 cv_signal(&schpc_p->schpc_cv); 1078 mutex_exit(&schpc_p->schpc_mutex); 1079 1080 return (0); 1081 } 1082 /* 1083 * System Controller/Mailbox failure. 1084 */ 1085 cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on " 1086 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller " 1087 "failed disconnection request", expander, board, 1088 SCHPC_SLOT_NUM(slot), 1089 schpc_p->schpc_slot[slot].ap_id); 1090 1091 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 1092 1093 failed: 1094 schpc_restore_leaf(slot); 1095 mutex_enter(&schpc_p->schpc_mutex); 1096 schpc_p->schpc_slot[slot].state &= 1097 ~SCHPC_SLOTSTATE_EXECUTING; 1098 cv_signal(&schpc_p->schpc_cv); 1099 mutex_exit(&schpc_p->schpc_mutex); 1100 1101 return (HPC_ERR_FAILED); 1102 } 1103 1104 /* 1105 * schpc_cpci_control 1106 * 1107 * Called by Hot Plug Services to perform a attachment point specific 1108 * on a Hot Pluggable Compact PCI Slot. 1109 */ 1110 /*ARGSUSED*/ 1111 static int 1112 schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 1113 caddr_t arg) 1114 { 1115 int rval; 1116 int expander, board, slot; 1117 pci_setslot_t setslot; 1118 pci_getslot_t slotstatus; 1119 hpc_led_info_t *hpc_led_info; 1120 1121 SCHPC_DEBUG3(D_IOC_CONTROL, 1122 "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)", 1123 ops_arg, slot_hdl, request); 1124 1125 mutex_enter(&schpc_p->schpc_mutex); 1126 1127 slot = schpc_slot_get_index(schpc_p, slot_hdl); 1128 1129 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 1130 SCHPC_DEBUG0(D_IOC_CONNECT, 1131 "schpc_disconnect - HPC Not Inited"); 1132 mutex_exit(&schpc_p->schpc_mutex); 1133 return (HPC_ERR_FAILED); 1134 } 1135 1136 /* 1137 * Block if another thread is executing a HPC command. 1138 */ 1139 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 1140 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 1141 } 1142 1143 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 1144 1145 mutex_exit(&schpc_p->schpc_mutex); 1146 1147 expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 1148 board = schpc_p->schpc_slot[slot].board; /* get board */ 1149 1150 /* 1151 * Initialize Set Slot Command. 1152 */ 1153 schpc_init_setslot_message(&setslot); 1154 1155 /* 1156 * Initialize LED to last know state. 1157 */ 1158 switch (schpc_p->schpc_slot[slot].led.led_power) { 1159 case LED_ON: 1160 setslot.slot_led_power = PCIMSG_LED_ON; 1161 break; 1162 case LED_OFF: 1163 setslot.slot_led_power = PCIMSG_LED_OFF; 1164 break; 1165 case LED_FLASH: 1166 setslot.slot_led_power = PCIMSG_LED_FLASH; 1167 break; 1168 } 1169 1170 switch (schpc_p->schpc_slot[slot].led.led_service) { 1171 case LED_ON: 1172 setslot.slot_led_service = PCIMSG_LED_ON; 1173 break; 1174 case LED_OFF: 1175 setslot.slot_led_service = PCIMSG_LED_OFF; 1176 break; 1177 case LED_FLASH: 1178 setslot.slot_led_service = PCIMSG_LED_FLASH; 1179 break; 1180 } 1181 1182 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1183 case LED_ON: 1184 setslot.slot_led_fault = PCIMSG_LED_ON; 1185 break; 1186 case LED_OFF: 1187 setslot.slot_led_fault = PCIMSG_LED_OFF; 1188 break; 1189 case LED_FLASH: 1190 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1191 break; 1192 } 1193 1194 switch (request) { 1195 1196 case HPC_CTRL_GET_LED_STATE: 1197 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1198 "HPC_CTRL_GET_LED_STATE"); 1199 hpc_led_info = (hpc_led_info_t *)arg; 1200 1201 switch (hpc_led_info->led) { 1202 case HPC_FAULT_LED: 1203 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1204 case LED_OFF: 1205 hpc_led_info->state = HPC_LED_OFF; 1206 break; 1207 case LED_ON: 1208 hpc_led_info->state = HPC_LED_ON; 1209 break; 1210 case LED_FLASH: 1211 hpc_led_info->state = HPC_LED_BLINK; 1212 break; 1213 } 1214 break; 1215 1216 case HPC_POWER_LED: 1217 switch (schpc_p->schpc_slot[slot].led.led_power) { 1218 case LED_OFF: 1219 hpc_led_info->state = HPC_LED_OFF; 1220 break; 1221 case LED_ON: 1222 hpc_led_info->state = HPC_LED_ON; 1223 break; 1224 case LED_FLASH: 1225 hpc_led_info->state = HPC_LED_BLINK; 1226 break; 1227 } 1228 break; 1229 case HPC_ATTN_LED: 1230 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1231 case LED_OFF: 1232 hpc_led_info->state = HPC_LED_OFF; 1233 break; 1234 case LED_ON: 1235 hpc_led_info->state = HPC_LED_OFF; 1236 break; 1237 case LED_FLASH: 1238 hpc_led_info->state = HPC_LED_ON; 1239 break; 1240 } 1241 break; 1242 case HPC_ACTIVE_LED: 1243 switch (schpc_p->schpc_slot[slot].led.led_service) { 1244 case LED_OFF: 1245 hpc_led_info->state = HPC_LED_OFF; 1246 break; 1247 case LED_ON: 1248 hpc_led_info->state = HPC_LED_ON; 1249 break; 1250 case LED_FLASH: 1251 hpc_led_info->state = HPC_LED_BLINK; 1252 break; 1253 } 1254 break; 1255 default: 1256 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 1257 "Invalid LED %x", hpc_led_info->led); 1258 1259 mutex_enter(&schpc_p->schpc_mutex); 1260 schpc_p->schpc_slot[slot].state &= 1261 ~SCHPC_SLOTSTATE_EXECUTING; 1262 cv_signal(&schpc_p->schpc_cv); 1263 mutex_exit(&schpc_p->schpc_mutex); 1264 1265 return (HPC_ERR_FAILED); 1266 } 1267 1268 mutex_enter(&schpc_p->schpc_mutex); 1269 schpc_p->schpc_slot[slot].state &= 1270 ~SCHPC_SLOTSTATE_EXECUTING; 1271 cv_signal(&schpc_p->schpc_cv); 1272 mutex_exit(&schpc_p->schpc_mutex); 1273 1274 return (0); 1275 1276 case HPC_CTRL_SET_LED_STATE: 1277 hpc_led_info = (hpc_led_info_t *)arg; 1278 1279 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 1280 "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", hpc_led_info); 1281 1282 switch (hpc_led_info->led) { 1283 case HPC_FAULT_LED: 1284 switch (hpc_led_info->state) { 1285 case HPC_LED_OFF: 1286 schpc_p->schpc_slot[slot].led.led_fault = 1287 LED_OFF; 1288 setslot.slot_led_fault = PCIMSG_LED_OFF; 1289 break; 1290 case HPC_LED_ON: 1291 schpc_p->schpc_slot[slot].led.led_fault = 1292 LED_ON; 1293 setslot.slot_led_fault = PCIMSG_LED_ON; 1294 break; 1295 case HPC_LED_BLINK: 1296 schpc_p->schpc_slot[slot].led.led_fault = 1297 LED_FLASH; 1298 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1299 break; 1300 } 1301 break; 1302 case HPC_POWER_LED: 1303 switch (hpc_led_info->state) { 1304 case HPC_LED_OFF: 1305 schpc_p->schpc_slot[slot].led.led_power = 1306 LED_OFF; 1307 setslot.slot_led_power = PCIMSG_LED_OFF; 1308 break; 1309 case HPC_LED_ON: 1310 schpc_p->schpc_slot[slot].led.led_power = 1311 LED_ON; 1312 setslot.slot_led_power = PCIMSG_LED_ON; 1313 break; 1314 case HPC_LED_BLINK: 1315 schpc_p->schpc_slot[slot].led.led_power = 1316 LED_FLASH; 1317 setslot.slot_led_power = PCIMSG_LED_FLASH; 1318 break; 1319 } 1320 break; 1321 case HPC_ATTN_LED: 1322 switch (hpc_led_info->state) { 1323 case HPC_LED_OFF: 1324 schpc_p->schpc_slot[slot].led.led_fault = 1325 LED_OFF; 1326 setslot.slot_led_fault = PCIMSG_LED_OFF; 1327 break; 1328 case HPC_LED_ON: 1329 schpc_p->schpc_slot[slot].led.led_fault = 1330 LED_FLASH; 1331 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1332 break; 1333 case HPC_LED_BLINK: 1334 schpc_p->schpc_slot[slot].led.led_fault = 1335 LED_FLASH; 1336 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1337 break; 1338 } 1339 break; 1340 case HPC_ACTIVE_LED: 1341 switch (hpc_led_info->state) { 1342 case HPC_LED_OFF: 1343 schpc_p->schpc_slot[slot].led.led_service = 1344 LED_OFF; 1345 setslot.slot_led_service = PCIMSG_LED_OFF; 1346 break; 1347 case HPC_LED_ON: 1348 schpc_p->schpc_slot[slot].led.led_service = 1349 LED_ON; 1350 setslot.slot_led_service = PCIMSG_LED_ON; 1351 break; 1352 case HPC_LED_BLINK: 1353 schpc_p->schpc_slot[slot].led.led_service = 1354 LED_FLASH; 1355 setslot.slot_led_service = PCIMSG_LED_FLASH; 1356 break; 1357 } 1358 break; 1359 default: 1360 mutex_enter(&schpc_p->schpc_mutex); 1361 schpc_p->schpc_slot[slot].state &= 1362 ~SCHPC_SLOTSTATE_EXECUTING; 1363 cv_signal(&schpc_p->schpc_cv); 1364 mutex_exit(&schpc_p->schpc_mutex); 1365 1366 return (0); 1367 } 1368 1369 (void) schpc_setslotstatus(expander, board, slot, &setslot); 1370 1371 mutex_enter(&schpc_p->schpc_mutex); 1372 schpc_p->schpc_slot[slot].state &= 1373 ~SCHPC_SLOTSTATE_EXECUTING; 1374 cv_signal(&schpc_p->schpc_cv); 1375 mutex_exit(&schpc_p->schpc_mutex); 1376 1377 return (0); 1378 1379 case HPC_CTRL_GET_SLOT_STATE: { 1380 hpc_slot_state_t *hpc_slot_state; 1381 1382 hpc_slot_state = (hpc_slot_state_t *)arg; 1383 1384 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - " 1385 "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p", 1386 hpc_slot_state); 1387 1388 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 1389 1390 if (!rval) { 1391 1392 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 1393 return (HPC_ERR_FAILED); 1394 } 1395 1396 if (slotstatus.slot_empty == PCIMSG_ON) { 1397 *hpc_slot_state = HPC_SLOT_EMPTY; 1398 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty"); 1399 } else if (slotstatus.slot_power_on == PCIMSG_ON) { 1400 *hpc_slot_state = HPC_SLOT_CONNECTED; 1401 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected"); 1402 schpc_p->schpc_slot[slot].state |= 1403 SCHPC_SLOTSTATE_CONNECTED; 1404 } else { 1405 *hpc_slot_state = HPC_SLOT_DISCONNECTED; 1406 SCHPC_DEBUG0(D_IOC_CONTROL, 1407 "Slot Disconnected"); 1408 schpc_p->schpc_slot[slot].state &= 1409 ~SCHPC_SLOTSTATE_CONNECTED; 1410 } 1411 } else { 1412 SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed"); 1413 1414 mutex_enter(&schpc_p->schpc_mutex); 1415 schpc_p->schpc_slot[slot].state &= 1416 ~SCHPC_SLOTSTATE_EXECUTING; 1417 cv_signal(&schpc_p->schpc_cv); 1418 mutex_exit(&schpc_p->schpc_mutex); 1419 1420 return (HPC_ERR_FAILED); 1421 } 1422 1423 mutex_enter(&schpc_p->schpc_mutex); 1424 schpc_p->schpc_slot[slot].state &= 1425 ~SCHPC_SLOTSTATE_EXECUTING; 1426 cv_signal(&schpc_p->schpc_cv); 1427 mutex_exit(&schpc_p->schpc_mutex); 1428 1429 return (0); 1430 } 1431 case HPC_CTRL_GET_BOARD_TYPE: { 1432 hpc_board_type_t *hpc_board_type; 1433 1434 hpc_board_type = (hpc_board_type_t *)arg; 1435 1436 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1437 "HPC_CTRL_GET_BOARD_TYPE"); 1438 1439 /* 1440 * The HPC driver does not know what board type 1441 * is plugged in. 1442 */ 1443 *hpc_board_type = HPC_BOARD_CPCI_HS; 1444 1445 mutex_enter(&schpc_p->schpc_mutex); 1446 schpc_p->schpc_slot[slot].state &= 1447 ~SCHPC_SLOTSTATE_EXECUTING; 1448 cv_signal(&schpc_p->schpc_cv); 1449 mutex_exit(&schpc_p->schpc_mutex); 1450 1451 return (0); 1452 1453 } 1454 case HPC_CTRL_DEV_CONFIGURED: 1455 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1456 "HPC_CTRL_DEV_CONFIGURED"); 1457 1458 mutex_enter(&schpc_p->schpc_mutex); 1459 schpc_p->schpc_slot[slot].state &= 1460 ~SCHPC_SLOTSTATE_EXECUTING; 1461 cv_signal(&schpc_p->schpc_cv); 1462 mutex_exit(&schpc_p->schpc_mutex); 1463 1464 return (0); 1465 1466 case HPC_CTRL_DEV_UNCONFIGURED: 1467 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1468 "HPC_CTRL_DEV_UNCONFIGURED"); 1469 1470 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) { 1471 /* 1472 * When the occupant is unconfigured, power 1473 * down the slot. 1474 */ 1475 rval = schpc_disconnect((caddr_t)schpc_p, 1476 schpc_p->schpc_slot[slot].slot_handle, 1477 0, 0); 1478 1479 schpc_p->schpc_slot[slot].state &= 1480 ~SCHPC_SLOTSTATE_ENUM; 1481 } 1482 1483 mutex_enter(&schpc_p->schpc_mutex); 1484 schpc_p->schpc_slot[slot].state &= 1485 ~SCHPC_SLOTSTATE_EXECUTING; 1486 cv_signal(&schpc_p->schpc_cv); 1487 mutex_exit(&schpc_p->schpc_mutex); 1488 1489 return (0); 1490 1491 case HPC_CTRL_ENABLE_AUTOCFG: 1492 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1493 "HPC_CTRL_ENABLE_AUTOCFG"); 1494 1495 schpc_p->schpc_slot[slot].state |= 1496 SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1497 1498 mutex_enter(&schpc_p->schpc_mutex); 1499 schpc_p->schpc_slot[slot].state &= 1500 ~SCHPC_SLOTSTATE_EXECUTING; 1501 cv_signal(&schpc_p->schpc_cv); 1502 mutex_exit(&schpc_p->schpc_mutex); 1503 1504 return (0); 1505 1506 case HPC_CTRL_DISABLE_AUTOCFG: 1507 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1508 "HPC_CTRL_DISABLE_AUTOCFG"); 1509 schpc_p->schpc_slot[slot].state &= 1510 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1511 1512 mutex_enter(&schpc_p->schpc_mutex); 1513 schpc_p->schpc_slot[slot].state &= 1514 ~SCHPC_SLOTSTATE_EXECUTING; 1515 cv_signal(&schpc_p->schpc_cv); 1516 mutex_exit(&schpc_p->schpc_mutex); 1517 1518 return (0); 1519 1520 case HPC_CTRL_DISABLE_ENUM: 1521 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1522 "HPC_CTRL_DISABLE_ENUM"); 1523 1524 setslot.slot_disable_ENUM = PCIMSG_ON; 1525 1526 rval = schpc_setslotstatus(expander, board, slot, &setslot); 1527 1528 if (rval) 1529 rval = HPC_ERR_FAILED; 1530 1531 mutex_enter(&schpc_p->schpc_mutex); 1532 schpc_p->schpc_slot[slot].state &= 1533 ~SCHPC_SLOTSTATE_EXECUTING; 1534 cv_signal(&schpc_p->schpc_cv); 1535 mutex_exit(&schpc_p->schpc_mutex); 1536 1537 return (rval); 1538 1539 case HPC_CTRL_ENABLE_ENUM: 1540 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1541 "HPC_CTRL_ENABLE_ENUM"); 1542 1543 setslot.slot_enable_ENUM = PCIMSG_ON; 1544 1545 rval = schpc_setslotstatus(expander, board, slot, &setslot); 1546 1547 if (rval) 1548 rval = HPC_ERR_FAILED; 1549 1550 mutex_enter(&schpc_p->schpc_mutex); 1551 schpc_p->schpc_slot[slot].state &= 1552 ~SCHPC_SLOTSTATE_EXECUTING; 1553 cv_signal(&schpc_p->schpc_cv); 1554 mutex_exit(&schpc_p->schpc_mutex); 1555 1556 return (rval); 1557 1558 default: 1559 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - " 1560 "****NOT SUPPORTED CONTROL CMD"); 1561 1562 mutex_enter(&schpc_p->schpc_mutex); 1563 schpc_p->schpc_slot[slot].state &= 1564 ~SCHPC_SLOTSTATE_EXECUTING; 1565 cv_signal(&schpc_p->schpc_cv); 1566 mutex_exit(&schpc_p->schpc_mutex); 1567 1568 return (HPC_ERR_NOTSUPPORTED); 1569 } 1570 } 1571 1572 /* 1573 * schpc_pci_control 1574 * 1575 * Called by Hot Plug Services to perform a attachment point specific 1576 * on a Hot Pluggable Standard PCI Slot. 1577 */ 1578 /*ARGSUSED*/ 1579 static int 1580 schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, 1581 caddr_t arg) 1582 { 1583 int rval; 1584 int expander, board, slot; 1585 pci_setslot_t setslot; 1586 pci_getslot_t slotstatus; 1587 hpc_led_info_t *hpc_led_info; 1588 1589 SCHPC_DEBUG3(D_IOC_CONTROL, 1590 "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)", 1591 ops_arg, slot_hdl, request); 1592 1593 mutex_enter(&schpc_p->schpc_mutex); 1594 1595 slot = schpc_slot_get_index(schpc_p, slot_hdl); 1596 1597 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 1598 SCHPC_DEBUG0(D_IOC_CONNECT, 1599 "schpc_disconnect - HPC Not Inited"); 1600 mutex_exit(&schpc_p->schpc_mutex); 1601 return (HPC_ERR_FAILED); 1602 } 1603 1604 /* 1605 * Block if another thread is executing a HPC command. 1606 */ 1607 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 1608 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 1609 } 1610 1611 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 1612 1613 mutex_exit(&schpc_p->schpc_mutex); 1614 1615 expander = schpc_p->schpc_slot[slot].expander; /* get expander */ 1616 board = schpc_p->schpc_slot[slot].board; /* get board */ 1617 1618 /* 1619 * Initialize Set Slot Command. 1620 */ 1621 schpc_init_setslot_message(&setslot); 1622 1623 /* 1624 * Initialize LED to last know state. 1625 */ 1626 switch (schpc_p->schpc_slot[slot].led.led_power) { 1627 case LED_ON: 1628 setslot.slot_led_power = PCIMSG_LED_ON; 1629 break; 1630 case LED_OFF: 1631 setslot.slot_led_power = PCIMSG_LED_OFF; 1632 break; 1633 case LED_FLASH: 1634 setslot.slot_led_power = PCIMSG_LED_FLASH; 1635 break; 1636 } 1637 1638 switch (schpc_p->schpc_slot[slot].led.led_service) { 1639 case LED_ON: 1640 setslot.slot_led_service = PCIMSG_LED_ON; 1641 break; 1642 case LED_OFF: 1643 setslot.slot_led_service = PCIMSG_LED_OFF; 1644 break; 1645 case LED_FLASH: 1646 setslot.slot_led_service = PCIMSG_LED_FLASH; 1647 break; 1648 } 1649 1650 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1651 case LED_ON: 1652 setslot.slot_led_fault = PCIMSG_LED_ON; 1653 break; 1654 case LED_OFF: 1655 setslot.slot_led_fault = PCIMSG_LED_OFF; 1656 break; 1657 case LED_FLASH: 1658 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1659 break; 1660 } 1661 1662 switch (request) { 1663 1664 1665 case HPC_CTRL_GET_SLOT_STATE: { 1666 hpc_slot_state_t *hpc_slot_state; 1667 1668 hpc_slot_state = (hpc_slot_state_t *)arg; 1669 1670 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 1671 "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p", 1672 hpc_slot_state); 1673 1674 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 1675 1676 if (!rval) { 1677 1678 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 1679 1680 mutex_enter(&schpc_p->schpc_mutex); 1681 schpc_p->schpc_slot[slot].state &= 1682 ~SCHPC_SLOTSTATE_EXECUTING; 1683 cv_signal(&schpc_p->schpc_cv); 1684 mutex_exit(&schpc_p->schpc_mutex); 1685 1686 return (HPC_ERR_FAILED); 1687 } 1688 1689 if (slotstatus.slot_empty == PCIMSG_ON) { 1690 *hpc_slot_state = HPC_SLOT_EMPTY; 1691 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty"); 1692 } else if (slotstatus.slot_power_on == PCIMSG_ON) { 1693 *hpc_slot_state = HPC_SLOT_CONNECTED; 1694 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected"); 1695 schpc_p->schpc_slot[slot].state |= 1696 SCHPC_SLOTSTATE_CONNECTED; 1697 } else { 1698 *hpc_slot_state = HPC_SLOT_DISCONNECTED; 1699 SCHPC_DEBUG0(D_IOC_CONTROL, 1700 "Slot Disconnected"); 1701 schpc_p->schpc_slot[slot].state &= 1702 ~SCHPC_SLOTSTATE_CONNECTED; 1703 } 1704 } else { 1705 SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed"); 1706 1707 mutex_enter(&schpc_p->schpc_mutex); 1708 schpc_p->schpc_slot[slot].state &= 1709 ~SCHPC_SLOTSTATE_EXECUTING; 1710 cv_signal(&schpc_p->schpc_cv); 1711 mutex_exit(&schpc_p->schpc_mutex); 1712 1713 return (HPC_ERR_FAILED); 1714 } 1715 1716 mutex_enter(&schpc_p->schpc_mutex); 1717 schpc_p->schpc_slot[slot].state &= 1718 ~SCHPC_SLOTSTATE_EXECUTING; 1719 cv_signal(&schpc_p->schpc_cv); 1720 mutex_exit(&schpc_p->schpc_mutex); 1721 1722 return (0); 1723 } 1724 case HPC_CTRL_GET_BOARD_TYPE: { 1725 hpc_board_type_t *hpc_board_type; 1726 1727 hpc_board_type = (hpc_board_type_t *)arg; 1728 1729 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1730 "HPC_CTRL_GET_BOARD_TYPE"); 1731 1732 1733 /* 1734 * The HPC driver does not know what board type 1735 * is plugged in. 1736 */ 1737 *hpc_board_type = HPC_BOARD_PCI_HOTPLUG; 1738 1739 mutex_enter(&schpc_p->schpc_mutex); 1740 schpc_p->schpc_slot[slot].state &= 1741 ~SCHPC_SLOTSTATE_EXECUTING; 1742 cv_signal(&schpc_p->schpc_cv); 1743 mutex_exit(&schpc_p->schpc_mutex); 1744 1745 return (0); 1746 1747 } 1748 case HPC_CTRL_DEV_UNCONFIG_START: 1749 case HPC_CTRL_DEV_CONFIG_START: 1750 case HPC_CTRL_DEV_CONFIGURED: 1751 case HPC_CTRL_DEV_UNCONFIGURED: 1752 mutex_enter(&schpc_p->schpc_mutex); 1753 schpc_p->schpc_slot[slot].state &= 1754 ~SCHPC_SLOTSTATE_EXECUTING; 1755 cv_signal(&schpc_p->schpc_cv); 1756 mutex_exit(&schpc_p->schpc_mutex); 1757 1758 return (0); 1759 1760 case HPC_CTRL_GET_LED_STATE: 1761 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1762 "HPC_CTRL_GET_LED_STATE"); 1763 hpc_led_info = (hpc_led_info_t *)arg; 1764 1765 switch (hpc_led_info->led) { 1766 case HPC_FAULT_LED: 1767 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1768 case LED_OFF: 1769 hpc_led_info->state = HPC_LED_OFF; 1770 break; 1771 case LED_ON: 1772 hpc_led_info->state = HPC_LED_ON; 1773 break; 1774 case LED_FLASH: 1775 hpc_led_info->state = HPC_LED_BLINK; 1776 break; 1777 } 1778 break; 1779 1780 case HPC_POWER_LED: 1781 switch (schpc_p->schpc_slot[slot].led.led_power) { 1782 case LED_OFF: 1783 hpc_led_info->state = HPC_LED_OFF; 1784 break; 1785 case LED_ON: 1786 hpc_led_info->state = HPC_LED_ON; 1787 break; 1788 case LED_FLASH: 1789 hpc_led_info->state = HPC_LED_BLINK; 1790 break; 1791 } 1792 break; 1793 case HPC_ATTN_LED: 1794 switch (schpc_p->schpc_slot[slot].led.led_fault) { 1795 case LED_OFF: 1796 hpc_led_info->state = HPC_LED_OFF; 1797 break; 1798 case LED_ON: 1799 hpc_led_info->state = HPC_LED_OFF; 1800 break; 1801 case LED_FLASH: 1802 hpc_led_info->state = HPC_LED_ON; 1803 break; 1804 } 1805 break; 1806 case HPC_ACTIVE_LED: 1807 switch (schpc_p->schpc_slot[slot].led.led_service) { 1808 case LED_OFF: 1809 hpc_led_info->state = HPC_LED_OFF; 1810 break; 1811 case LED_ON: 1812 hpc_led_info->state = HPC_LED_ON; 1813 break; 1814 case LED_FLASH: 1815 hpc_led_info->state = HPC_LED_BLINK; 1816 break; 1817 } 1818 break; 1819 default: 1820 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 1821 "Invalid LED %x", hpc_led_info->led); 1822 1823 mutex_enter(&schpc_p->schpc_mutex); 1824 schpc_p->schpc_slot[slot].state &= 1825 ~SCHPC_SLOTSTATE_EXECUTING; 1826 cv_signal(&schpc_p->schpc_cv); 1827 mutex_exit(&schpc_p->schpc_mutex); 1828 1829 return (HPC_ERR_FAILED); 1830 } 1831 1832 mutex_enter(&schpc_p->schpc_mutex); 1833 schpc_p->schpc_slot[slot].state &= 1834 ~SCHPC_SLOTSTATE_EXECUTING; 1835 cv_signal(&schpc_p->schpc_cv); 1836 mutex_exit(&schpc_p->schpc_mutex); 1837 1838 return (0); 1839 1840 case HPC_CTRL_SET_LED_STATE: 1841 hpc_led_info = (hpc_led_info_t *)arg; 1842 1843 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - " 1844 "HPC_CTRL_SET_LED_STATE hpc_led_info=%p", hpc_led_info); 1845 1846 switch (hpc_led_info->led) { 1847 case HPC_FAULT_LED: 1848 switch (hpc_led_info->state) { 1849 case HPC_LED_OFF: 1850 schpc_p->schpc_slot[slot].led.led_fault = 1851 LED_OFF; 1852 setslot.slot_led_fault = PCIMSG_LED_OFF; 1853 break; 1854 case HPC_LED_ON: 1855 schpc_p->schpc_slot[slot].led.led_fault = 1856 LED_ON; 1857 setslot.slot_led_fault = PCIMSG_LED_ON; 1858 break; 1859 case HPC_LED_BLINK: 1860 schpc_p->schpc_slot[slot].led.led_fault = 1861 LED_FLASH; 1862 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1863 break; 1864 } 1865 break; 1866 case HPC_POWER_LED: 1867 switch (hpc_led_info->state) { 1868 case HPC_LED_OFF: 1869 schpc_p->schpc_slot[slot].led.led_power = 1870 LED_OFF; 1871 setslot.slot_led_power = PCIMSG_LED_OFF; 1872 break; 1873 case HPC_LED_ON: 1874 schpc_p->schpc_slot[slot].led.led_power = 1875 LED_ON; 1876 setslot.slot_led_power = PCIMSG_LED_ON; 1877 break; 1878 case HPC_LED_BLINK: 1879 schpc_p->schpc_slot[slot].led.led_power = 1880 LED_FLASH; 1881 setslot.slot_led_power = PCIMSG_LED_FLASH; 1882 break; 1883 } 1884 break; 1885 case HPC_ATTN_LED: 1886 switch (hpc_led_info->state) { 1887 case HPC_LED_OFF: 1888 schpc_p->schpc_slot[slot].led.led_fault = 1889 LED_OFF; 1890 setslot.slot_led_fault = PCIMSG_LED_OFF; 1891 break; 1892 case HPC_LED_ON: 1893 schpc_p->schpc_slot[slot].led.led_fault = 1894 LED_FLASH; 1895 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1896 break; 1897 case HPC_LED_BLINK: 1898 schpc_p->schpc_slot[slot].led.led_fault = 1899 LED_FLASH; 1900 setslot.slot_led_fault = PCIMSG_LED_FLASH; 1901 break; 1902 } 1903 break; 1904 case HPC_ACTIVE_LED: 1905 switch (hpc_led_info->state) { 1906 case HPC_LED_OFF: 1907 schpc_p->schpc_slot[slot].led.led_service = 1908 LED_OFF; 1909 setslot.slot_led_service = PCIMSG_LED_OFF; 1910 break; 1911 case HPC_LED_ON: 1912 schpc_p->schpc_slot[slot].led.led_service = 1913 LED_ON; 1914 setslot.slot_led_service = PCIMSG_LED_ON; 1915 break; 1916 case HPC_LED_BLINK: 1917 schpc_p->schpc_slot[slot].led.led_service = 1918 LED_FLASH; 1919 setslot.slot_led_service = PCIMSG_LED_FLASH; 1920 break; 1921 } 1922 break; 1923 default: 1924 mutex_enter(&schpc_p->schpc_mutex); 1925 schpc_p->schpc_slot[slot].state &= 1926 ~SCHPC_SLOTSTATE_EXECUTING; 1927 cv_signal(&schpc_p->schpc_cv); 1928 mutex_exit(&schpc_p->schpc_mutex); 1929 1930 return (0); 1931 } 1932 1933 (void) schpc_setslotstatus(expander, board, slot, &setslot); 1934 1935 mutex_enter(&schpc_p->schpc_mutex); 1936 schpc_p->schpc_slot[slot].state &= 1937 ~SCHPC_SLOTSTATE_EXECUTING; 1938 cv_signal(&schpc_p->schpc_cv); 1939 mutex_exit(&schpc_p->schpc_mutex); 1940 1941 return (0); 1942 1943 case HPC_CTRL_ENABLE_AUTOCFG: 1944 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1945 "HPC_CTRL_ENABLE_AUTOCFG"); 1946 1947 schpc_p->schpc_slot[slot].state |= 1948 SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1949 1950 mutex_enter(&schpc_p->schpc_mutex); 1951 schpc_p->schpc_slot[slot].state &= 1952 ~SCHPC_SLOTSTATE_EXECUTING; 1953 cv_signal(&schpc_p->schpc_cv); 1954 mutex_exit(&schpc_p->schpc_mutex); 1955 1956 return (0); 1957 1958 case HPC_CTRL_DISABLE_AUTOCFG: 1959 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - " 1960 "HPC_CTRL_DISABLE_AUTOCFG"); 1961 schpc_p->schpc_slot[slot].state &= 1962 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 1963 1964 mutex_enter(&schpc_p->schpc_mutex); 1965 schpc_p->schpc_slot[slot].state &= 1966 ~SCHPC_SLOTSTATE_EXECUTING; 1967 cv_signal(&schpc_p->schpc_cv); 1968 mutex_exit(&schpc_p->schpc_mutex); 1969 1970 return (0); 1971 1972 case HPC_CTRL_DISABLE_ENUM: 1973 case HPC_CTRL_ENABLE_ENUM: 1974 default: 1975 mutex_enter(&schpc_p->schpc_mutex); 1976 schpc_p->schpc_slot[slot].state &= 1977 ~SCHPC_SLOTSTATE_EXECUTING; 1978 cv_signal(&schpc_p->schpc_cv); 1979 mutex_exit(&schpc_p->schpc_mutex); 1980 1981 return (HPC_ERR_NOTSUPPORTED); 1982 } 1983 } 1984 1985 /* 1986 * schpc_test 1987 * 1988 * Tests the slot. 1989 */ 1990 /*ARGSUSED*/ 1991 static void 1992 schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags) 1993 { 1994 pci_getslot_t slotstatus; 1995 pci_setslot_t setslot; 1996 int expander, board; 1997 int rval; 1998 int retry = 1; 1999 2000 SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)", 2001 ops_arg, SCHPC_SLOT_NUM(slot)); 2002 2003 SCHPC_DEBUG3(D_IOC_TEST, 2004 " schpc_test() Expander=%d Board=%d Slot=%d", 2005 schpc_p->schpc_slot[slot].expander, 2006 schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot)); 2007 2008 expander = schpc_p->schpc_slot[slot].expander; 2009 board = schpc_p->schpc_slot[slot].board; 2010 2011 restart_test: 2012 /* 2013 * Initial the slot with its occupant and receptacle in good condition. 2014 */ 2015 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_REC_GOOD; 2016 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_OCC_GOOD; 2017 2018 2019 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 2020 2021 if (rval) { 2022 /* 2023 * System Controller/Mailbox failure. 2024 */ 2025 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2026 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to " 2027 "Communicate with System Controller", expander, board, 2028 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id); 2029 2030 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 2031 return; 2032 } 2033 2034 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 2035 2036 cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d " 2037 "is not hot pluggable\n", expander, board, 2038 SCHPC_SLOT_NUM(slot)); 2039 2040 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 2041 return; 2042 } 2043 2044 switch (slotstatus.slot_condition) { 2045 case PCIMSG_SLOTCOND_OCC_FAIL: 2046 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2047 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2048 "System Controller/Occupant Failed", 2049 expander, board, SCHPC_SLOT_NUM(slot), 2050 schpc_p->schpc_slot[slot].ap_id); 2051 2052 schpc_setslotled(expander, board, slot, 2053 (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON)); 2054 2055 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_OCC_GOOD; 2056 return; 2057 case PCIMSG_SLOTCOND_REC_FAIL: 2058 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2059 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2060 "System Controller/Receptacle Failed", 2061 expander, board, SCHPC_SLOT_NUM(slot), 2062 schpc_p->schpc_slot[slot].ap_id); 2063 2064 schpc_setslotled(expander, board, slot, 2065 (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON)); 2066 2067 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 2068 return; 2069 case PCIMSG_SLOTCOND_NOHOTPLUG: 2070 cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d " 2071 "is not hot pluggable\n", expander, board, 2072 SCHPC_SLOT_NUM(slot)); 2073 2074 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD; 2075 return; 2076 } 2077 2078 if (slotstatus.slot_power_on) { 2079 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON; 2080 2081 if (!slotstatus.slot_HEALTHY) { 2082 /* 2083 * cPCI Adapter is not asserting HEALTHY#. 2084 */ 2085 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2086 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2087 "PCI adapter not HEALTHY", expander, board, 2088 SCHPC_SLOT_NUM(slot), 2089 schpc_p->schpc_slot[slot].ap_id); 2090 2091 schpc_setslotled(expander, board, slot, 2092 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 2093 2094 schpc_p->schpc_slot[slot].state &= 2095 ~SCHPC_SLOTSTATE_OCC_GOOD; 2096 2097 return; 2098 } 2099 2100 if (!slotstatus.slot_powergood) { 2101 /* 2102 * PCI Power Input is not good. 2103 */ 2104 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2105 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2106 "System Controller PCI Power Input Not Good", 2107 expander, board, SCHPC_SLOT_NUM(slot), 2108 schpc_p->schpc_slot[slot].ap_id); 2109 2110 schpc_setslotled(expander, board, slot, 2111 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 2112 2113 schpc_p->schpc_slot[slot].state &= 2114 ~SCHPC_SLOTSTATE_OCC_GOOD; 2115 2116 return; 2117 } 2118 2119 if (slotstatus.slot_powerfault) { 2120 /* 2121 * PCI Power Fault. 2122 */ 2123 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on " 2124 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : " 2125 "System Controller PCI Power Fault", 2126 expander, board, SCHPC_SLOT_NUM(slot), 2127 schpc_p->schpc_slot[slot].ap_id); 2128 2129 schpc_setslotled(expander, board, slot, 2130 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON)); 2131 2132 schpc_p->schpc_slot[slot].state &= 2133 ~SCHPC_SLOTSTATE_OCC_GOOD; 2134 2135 return; 2136 } 2137 } 2138 2139 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0"); 2140 2141 /* 2142 * Is the slot empty? 2143 */ 2144 if (slotstatus.slot_empty) { 2145 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty"); 2146 2147 schpc_p->schpc_slot[slot].state &= 2148 ~SCHPC_SLOTSTATE_PRESENT; 2149 2150 if (slotstatus.slot_power_on) { 2151 2152 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot " 2153 "is powered ON"); 2154 2155 /* 2156 * Tests will be retried once after powering off 2157 * an empty slot. 2158 */ 2159 if (retry) { 2160 2161 /* 2162 * Turn off the slot and restart test. 2163 */ 2164 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() " 2165 "Turning Empty Slot OFF"); 2166 2167 schpc_init_setslot_message(&setslot); 2168 setslot.slot_power_off = PCIMSG_ON; 2169 (void) schpc_setslotstatus( 2170 expander, board, slot, &setslot); 2171 2172 retry = 0; 2173 2174 goto restart_test; 2175 } 2176 } 2177 } else { 2178 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present"); 2179 2180 if (!slotstatus.slot_power_on) { 2181 if (retry) { 2182 /* 2183 * If there is a cassette present and the 2184 * power is off, try turning the power on and 2185 * restart the test. This allows access to 2186 * the FRUID when an empty cassette is 2187 * installed. 2188 */ 2189 SCHPC_DEBUG0(D_IOC_TEST, 2190 "schpc_test() Power On Adapter"); 2191 schpc_init_setslot_message(&setslot); 2192 setslot.slot_power_on = PCIMSG_ON; 2193 (void) schpc_setslotstatus( 2194 expander, board, slot, &setslot); 2195 retry = 0; 2196 goto restart_test; 2197 } 2198 } 2199 2200 schpc_p->schpc_slot[slot].state |= 2201 SCHPC_SLOTSTATE_PRESENT; 2202 } 2203 2204 /* 2205 * Is the slot powered up? 2206 */ 2207 schpc_init_setslot_message(&setslot); 2208 2209 if (slotstatus.slot_power_on) { 2210 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On"); 2211 2212 schpc_p->schpc_slot[slot].state |= 2213 SCHPC_SLOTSTATE_CONNECTED; 2214 2215 setslot.slot_led_power = PCIMSG_LED_ON; 2216 setslot.slot_led_service = PCIMSG_LED_OFF; 2217 setslot.slot_enable_ENUM = PCIMSG_ON; 2218 setslot.slot_enable_HEALTHY = PCIMSG_ON; 2219 } else { 2220 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off"); 2221 2222 schpc_p->schpc_slot[slot].state &= 2223 ~SCHPC_SLOTSTATE_CONNECTED; 2224 2225 setslot.slot_led_power = PCIMSG_LED_OFF; 2226 setslot.slot_led_service = PCIMSG_LED_ON; 2227 setslot.slot_disable_ENUM = PCIMSG_ON; 2228 setslot.slot_disable_HEALTHY = PCIMSG_ON; 2229 } 2230 2231 setslot.slot_led_fault = PCIMSG_LED_OFF; 2232 2233 (void) schpc_setslotstatus(expander, board, slot, &setslot); 2234 2235 /* 2236 * Save LED State. 2237 */ 2238 switch (setslot.slot_led_power) { 2239 case PCIMSG_LED_ON: 2240 schpc_p->schpc_slot[slot].led.led_power = LED_ON; 2241 break; 2242 case PCIMSG_LED_OFF: 2243 schpc_p->schpc_slot[slot].led.led_power = LED_OFF; 2244 break; 2245 case PCIMSG_LED_FLASH: 2246 schpc_p->schpc_slot[slot].led.led_power = LED_FLASH; 2247 break; 2248 } 2249 switch (setslot.slot_led_service) { 2250 case PCIMSG_LED_ON: 2251 schpc_p->schpc_slot[slot].led.led_service = LED_ON; 2252 break; 2253 case PCIMSG_LED_OFF: 2254 schpc_p->schpc_slot[slot].led.led_service = LED_OFF; 2255 break; 2256 case PCIMSG_LED_FLASH: 2257 schpc_p->schpc_slot[slot].led.led_service = LED_FLASH; 2258 break; 2259 } 2260 switch (setslot.slot_led_fault) { 2261 case PCIMSG_LED_ON: 2262 schpc_p->schpc_slot[slot].led.led_fault = LED_ON; 2263 break; 2264 case PCIMSG_LED_OFF: 2265 schpc_p->schpc_slot[slot].led.led_fault = LED_OFF; 2266 break; 2267 case PCIMSG_LED_FLASH: 2268 schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH; 2269 break; 2270 } 2271 } 2272 2273 2274 /* 2275 * schpc_event_handler 2276 * 2277 * Placed on the schpc_event_taskq by schpc_event_filter when an 2278 * unsolicited MBOXSC_MSG_EVENT is received from the SC. It handles 2279 * things like power insertion/removal, ENUM#, etc. 2280 */ 2281 static void 2282 schpc_event_handler(void *arg) 2283 { 2284 pci_getslot_t slotstatus; 2285 uint8_t expander, board, slot; 2286 int rval; 2287 pcimsg_t *event = (pcimsg_t *)arg; 2288 2289 /* 2290 * OK, we got an event message. Since the event message only tells 2291 * us something has changed and not changed to what, we need to get 2292 * the current slot status to find how WHAT was change to WHAT. 2293 */ 2294 2295 slot = event->pcimsg_slot; 2296 expander = event->pcimsg_node; /* get expander */ 2297 board = event->pcimsg_board; /* get board */ 2298 2299 SCHPC_DEBUG3(D_EVENT, 2300 "schpc_event_handler() - exp=%d board=%d slot=%d", 2301 expander, board, slot); 2302 2303 /* create a slot table index */ 2304 slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot); 2305 2306 SCHPC_DEBUG1(D_EVENT, 2307 "schpc_event_handler() - expanded slot %d", slot); 2308 2309 if (schpc_p == NULL) { 2310 cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc"); 2311 kmem_free(event, sizeof (pcimsg_t)); 2312 return; 2313 } 2314 2315 mutex_enter(&schpc_p->schpc_mutex); 2316 2317 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) { 2318 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited"); 2319 mutex_exit(&schpc_p->schpc_mutex); 2320 kmem_free(event, sizeof (pcimsg_t)); 2321 return; 2322 } 2323 /* 2324 * Block if another thread is executing a HPC command. 2325 */ 2326 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) { 2327 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy"); 2328 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex); 2329 } 2330 2331 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING; 2332 2333 mutex_exit(&schpc_p->schpc_mutex); 2334 2335 rval = schpc_getslotstatus(expander, board, slot, &slotstatus); 2336 2337 if (rval) { 2338 cmn_err(CE_WARN, "schpc/Event Handler - Can not get status " 2339 "for expander=%d board=%d slot=%d\n", 2340 expander, board, SCHPC_SLOT_NUM(slot)); 2341 2342 mutex_enter(&schpc_p->schpc_mutex); 2343 schpc_p->schpc_slot[slot].state &= 2344 ~SCHPC_SLOTSTATE_EXECUTING; 2345 cv_signal(&schpc_p->schpc_cv); 2346 mutex_exit(&schpc_p->schpc_mutex); 2347 kmem_free(event, sizeof (pcimsg_t)); 2348 return; 2349 } 2350 2351 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) { 2352 cmn_err(CE_WARN, "schpc/Event Handler - Can not get good " 2353 "status for expander=%d board=%d slot=%d\n", 2354 expander, board, SCHPC_SLOT_NUM(slot)); 2355 2356 mutex_enter(&schpc_p->schpc_mutex); 2357 schpc_p->schpc_slot[slot].state &= 2358 ~SCHPC_SLOTSTATE_EXECUTING; 2359 cv_signal(&schpc_p->schpc_cv); 2360 mutex_exit(&schpc_p->schpc_mutex); 2361 2362 kmem_free(event, sizeof (pcimsg_t)); 2363 return; 2364 } 2365 2366 SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d", 2367 expander, board, SCHPC_SLOT_NUM(slot)); 2368 2369 if (schpc_p->schpc_slot[slot].slot_ops == NULL) { 2370 SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event " 2371 "for unregistered slot for expander=%d board=%d slot=%d", 2372 expander, board, SCHPC_SLOT_NUM(slot)); 2373 2374 mutex_enter(&schpc_p->schpc_mutex); 2375 schpc_p->schpc_slot[slot].state &= 2376 ~SCHPC_SLOTSTATE_EXECUTING; 2377 cv_signal(&schpc_p->schpc_cv); 2378 mutex_exit(&schpc_p->schpc_mutex); 2379 2380 kmem_free(event, sizeof (pcimsg_t)); 2381 return; 2382 } 2383 2384 /* Slot Power Event */ 2385 2386 if (event->pcimsg_type.pcimsg_slotevent.slot_power) { 2387 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event"); 2388 /* 2389 * The SC may have changed to slot power status. 2390 */ 2391 if (slotstatus.slot_power_on) { 2392 schpc_p->schpc_slot[slot].state |= 2393 SCHPC_SLOTSTATE_CONNECTED; 2394 2395 hpc_slot_event_notify( 2396 schpc_p->schpc_slot[slot].slot_handle, 2397 HPC_EVENT_SLOT_POWER_ON, 0); 2398 } else { 2399 schpc_p->schpc_slot[slot].state &= 2400 ~SCHPC_SLOTSTATE_CONNECTED; 2401 2402 hpc_slot_event_notify( 2403 schpc_p->schpc_slot[slot].slot_handle, 2404 HPC_EVENT_SLOT_POWER_OFF, 0); 2405 } 2406 } 2407 2408 /* Adapter Insertion/Removal Event */ 2409 2410 if (event->pcimsg_type.pcimsg_slotevent.slot_presence) { 2411 if (slotstatus.slot_empty == PCIMSG_ON) { 2412 2413 /* Adapter Removed */ 2414 2415 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed"); 2416 2417 if (schpc_p->schpc_slot[slot].state & 2418 SCHPC_SLOTSTATE_CONNECTED) { 2419 /* 2420 * If the adapter has been removed while 2421 * there the slot is connected, it could be 2422 * due to a ENUM handling. 2423 */ 2424 cmn_err(CE_WARN, "Card removed from " 2425 "powered on slot at " 2426 "expander=%d board=%d slot=%d\n", 2427 expander, board, SCHPC_SLOT_NUM(slot)); 2428 2429 schpc_p->schpc_slot[slot].state &= 2430 ~SCHPC_SLOTSTATE_EXECUTING; 2431 rval = schpc_disconnect((caddr_t)schpc_p, 2432 schpc_p->schpc_slot[slot].slot_handle, 2433 0, 0); 2434 mutex_enter(&schpc_p->schpc_mutex); 2435 while (schpc_p->schpc_slot[slot].state & 2436 SCHPC_SLOTSTATE_EXECUTING) { 2437 SCHPC_DEBUG0(D_EVENT, 2438 "schpc_event_handler - " 2439 "Slot is busy"); 2440 cv_wait(&schpc_p->schpc_cv, 2441 &schpc_p->schpc_mutex); 2442 } 2443 2444 schpc_p->schpc_slot[slot].state |= 2445 SCHPC_SLOTSTATE_EXECUTING; 2446 2447 mutex_exit(&schpc_p->schpc_mutex); 2448 } 2449 schpc_p->schpc_slot[slot].state |= 2450 SCHPC_SLOTSTATE_OCC_GOOD; 2451 2452 schpc_p->schpc_slot[slot].state &= 2453 ~SCHPC_SLOTSTATE_PRESENT; 2454 2455 hpc_slot_event_notify( 2456 schpc_p->schpc_slot[slot].slot_handle, 2457 HPC_EVENT_SLOT_REMOVAL, 0); 2458 } else { 2459 2460 /* Adapter Inserted */ 2461 2462 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted"); 2463 2464 if (schpc_p->schpc_slot[slot].state & 2465 SCHPC_SLOTSTATE_PRESENT) { 2466 /* 2467 * If the adapter is already present 2468 * throw the this event away. 2469 */ 2470 2471 SCHPC_DEBUG0(D_EVENT, 2472 "Adapter is already present"); 2473 2474 mutex_enter(&schpc_p->schpc_mutex); 2475 schpc_p->schpc_slot[slot].state &= 2476 ~SCHPC_SLOTSTATE_EXECUTING; 2477 cv_signal(&schpc_p->schpc_cv); 2478 mutex_exit(&schpc_p->schpc_mutex); 2479 2480 kmem_free(event, sizeof (pcimsg_t)); 2481 return; 2482 } 2483 2484 schpc_p->schpc_slot[slot].state |= 2485 SCHPC_SLOTSTATE_PRESENT; 2486 2487 schpc_p->schpc_slot[slot].state &= 2488 ~SCHPC_SLOTSTATE_CONNECTED; 2489 2490 hpc_slot_event_notify( 2491 schpc_p->schpc_slot[slot].slot_handle, 2492 HPC_EVENT_SLOT_INSERTION, 0); 2493 2494 if (schpc_p->schpc_slot[slot].state & 2495 SCHPC_SLOTSTATE_AUTOCFG_ENABLE) { 2496 SCHPC_DEBUG0(D_EVENT, "Auto Configuration " 2497 "(Connect/Configure) Started"); 2498 2499 schpc_p->schpc_slot[slot].state &= 2500 ~SCHPC_SLOTSTATE_EXECUTING; 2501 2502 rval = schpc_connect((caddr_t)schpc_p, 2503 schpc_p->schpc_slot[slot].slot_handle, 2504 0, 0); 2505 2506 if (rval) { 2507 cmn_err(CE_WARN, "schpc/Event Handler -" 2508 " Can not connect"); 2509 2510 mutex_enter(&schpc_p->schpc_mutex); 2511 schpc_p->schpc_slot[slot].state &= 2512 ~SCHPC_SLOTSTATE_EXECUTING; 2513 cv_signal(&schpc_p->schpc_cv); 2514 mutex_exit(&schpc_p->schpc_mutex); 2515 2516 kmem_free(event, sizeof (pcimsg_t)); 2517 return; 2518 } 2519 mutex_enter(&schpc_p->schpc_mutex); 2520 while (schpc_p->schpc_slot[slot].state & 2521 SCHPC_SLOTSTATE_EXECUTING) { 2522 SCHPC_DEBUG0(D_EVENT, 2523 "schpc_event_handler - " 2524 "Slot is busy"); 2525 cv_wait(&schpc_p->schpc_cv, 2526 &schpc_p->schpc_mutex); 2527 } 2528 2529 schpc_p->schpc_slot[slot].state |= 2530 SCHPC_SLOTSTATE_EXECUTING; 2531 2532 mutex_exit(&schpc_p->schpc_mutex); 2533 2534 hpc_slot_event_notify( 2535 schpc_p->schpc_slot[slot].slot_handle, 2536 HPC_EVENT_SLOT_CONFIGURE, 0); 2537 } else { 2538 schpc_setslotled(expander, board, slot, 2539 SERVICE_LED_ON); 2540 } 2541 } 2542 } 2543 2544 /* ENUM# signal change event */ 2545 2546 if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) { 2547 /* 2548 * ENUM should only be received to the adapter remove 2549 * procedure. 2550 */ 2551 2552 SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted"); 2553 2554 schpc_setslotled(expander, board, slot, FAULT_LED_FLASH); 2555 2556 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM; 2557 2558 hpc_slot_event_notify( 2559 schpc_p->schpc_slot[slot].slot_handle, 2560 HPC_EVENT_SLOT_ENUM, 0); 2561 } 2562 2563 /* HEALTHY# signal change event */ 2564 2565 if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) { 2566 2567 if (!slotstatus.slot_HEALTHY) { 2568 2569 SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED"); 2570 2571 schpc_p->schpc_slot[slot].state &= 2572 ~SCHPC_SLOTSTATE_OCC_GOOD; 2573 2574 hpc_slot_event_notify( 2575 schpc_p->schpc_slot[slot].slot_handle, 2576 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 2577 2578 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 2579 } else { 2580 SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK"); 2581 2582 schpc_p->schpc_slot[slot].state |= 2583 SCHPC_SLOTSTATE_OCC_GOOD; 2584 2585 hpc_slot_event_notify( 2586 schpc_p->schpc_slot[slot].slot_handle, 2587 HPC_EVENT_SLOT_HEALTHY_OK, 0); 2588 2589 schpc_setslotled(expander, board, slot, 2590 FAULT_LED_OFF); 2591 } 2592 } 2593 2594 /* Good Power change event */ 2595 2596 if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) { 2597 if (slotstatus.slot_powergood == PCIMSG_ON) { 2598 2599 SCHPC_DEBUG0(D_EVENT, 2600 "Event Type: Slot Power Good Detected"); 2601 2602 schpc_p->schpc_slot[slot].state |= 2603 SCHPC_SLOTSTATE_OCC_GOOD; 2604 2605 hpc_slot_event_notify( 2606 schpc_p->schpc_slot[slot].slot_handle, 2607 HPC_EVENT_SLOT_HEALTHY_OK, 0); 2608 2609 schpc_setslotled(expander, board, slot, 2610 FAULT_LED_OFF); 2611 } else { 2612 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good " 2613 "Detected"); 2614 2615 if (schpc_p->schpc_slot[slot].state & 2616 SCHPC_SLOTSTATE_CONNECTED) { 2617 2618 SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: " 2619 "power failed"); 2620 2621 schpc_p->schpc_slot[slot].state &= 2622 ~SCHPC_SLOTSTATE_OCC_GOOD; 2623 2624 hpc_slot_event_notify( 2625 schpc_p->schpc_slot[slot].slot_handle, 2626 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 2627 2628 schpc_setslotled(expander, board, slot, 2629 FAULT_LED_ON); 2630 } 2631 } 2632 } 2633 2634 /* Power Fault change event */ 2635 2636 if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) { 2637 if (slotstatus.slot_powerfault == PCIMSG_ON) { 2638 2639 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault " 2640 "Detected"); 2641 2642 schpc_p->schpc_slot[slot].state &= 2643 ~SCHPC_SLOTSTATE_OCC_GOOD; 2644 2645 hpc_slot_event_notify( 2646 schpc_p->schpc_slot[slot].slot_handle, 2647 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 2648 2649 schpc_setslotled(expander, board, slot, FAULT_LED_ON); 2650 } else { 2651 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault " 2652 "Cleared"); 2653 2654 schpc_p->schpc_slot[slot].state |= 2655 SCHPC_SLOTSTATE_OCC_GOOD; 2656 2657 hpc_slot_event_notify( 2658 schpc_p->schpc_slot[slot].slot_handle, 2659 HPC_EVENT_SLOT_HEALTHY_OK, 0); 2660 2661 schpc_setslotled(expander, board, slot, 2662 FAULT_LED_OFF); 2663 } 2664 } 2665 mutex_enter(&schpc_p->schpc_mutex); 2666 schpc_p->schpc_slot[slot].state &= 2667 ~SCHPC_SLOTSTATE_EXECUTING; 2668 cv_signal(&schpc_p->schpc_cv); 2669 mutex_exit(&schpc_p->schpc_mutex); 2670 2671 kmem_free(event, sizeof (pcimsg_t)); 2672 } 2673 2674 2675 /* 2676 * schpc_event_filter 2677 * 2678 * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the 2679 * schpc_event_taskq for processing by the schpc_event_handler _if_ 2680 * hotpluggable pci slots have been registered; otherwise, the 2681 * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox 2682 * open for future messages. 2683 */ 2684 static void 2685 schpc_event_filter(pcimsg_t *pmsg) 2686 { 2687 if (slots_registered == B_TRUE) { 2688 2689 pcimsg_t *pevent; 2690 2691 /* 2692 * If hotpluggable pci slots have been registered then enqueue 2693 * the event onto the schpc_event_taskq for processing. 2694 */ 2695 2696 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 2697 "slots_registered = B_TRUE"); 2698 2699 pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP); 2700 bcopy(pmsg, pevent, sizeof (pcimsg_t)); 2701 2702 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 2703 "event alloc'd"); 2704 2705 if (taskq_dispatch(schpc_event_taskq, schpc_event_handler, 2706 (void *)pevent, TQ_SLEEP) == NULL) { 2707 cmn_err(CE_WARN, "schpc: schpc_event_filter - " 2708 "taskq_dispatch failed to enqueue event"); 2709 kmem_free(pevent, sizeof (pcimsg_t)); 2710 return; 2711 } 2712 2713 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - " 2714 "event was taskq_dispatch'ed to schpc_event_handler"); 2715 } else { 2716 /* 2717 * Oops, schpc received an event _before_ the slots have been 2718 * registered. In that case there is no choice but to toss 2719 * the event. 2720 */ 2721 cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding " 2722 "premature event"); 2723 } 2724 } 2725 2726 2727 /* 2728 * schpc_msg_thread 2729 * A stand-alone thread that monitors the incoming mailbox for 2730 * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from 2731 * the mailbox for processing. 2732 * 2733 * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the 2734 * schpc_replylist, and the waiting thread is notified that its REPLY 2735 * message has arrived; otherwise, if no REPLY match is found, then it is 2736 * discarded. 2737 * 2738 * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed 2739 * by the schpc_event_handler. 2740 * 2741 * The schpc_msg_thread is started in _init(). 2742 */ 2743 void 2744 schpc_msg_thread(void) 2745 { 2746 int err; 2747 uint32_t type; 2748 uint32_t cmd; 2749 uint64_t transid; 2750 uint32_t length; 2751 pcimsg_t msg; 2752 2753 SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running"); 2754 2755 /* CONSTCOND */ 2756 while (1) { 2757 2758 /* setup wildcard arguments */ 2759 type = 0; 2760 cmd = 0; 2761 transid = 0; 2762 length = sizeof (pcimsg_t); 2763 bzero(&msg, sizeof (pcimsg_t)); 2764 2765 err = mboxsc_getmsg(KEY_SCPC, &type, &cmd, 2766 &transid, &length, (void *)&msg, 2767 schpc_timeout_getmsg); 2768 2769 if (err) { 2770 switch (err) { 2771 2772 /*FALLTHROUGH*/ 2773 case ETIMEDOUT: 2774 case EAGAIN: 2775 continue; 2776 2777 default: 2778 /* 2779 * unfortunately, we can't do very much here 2780 * because we're wildcarding mboxsc_getmsg 2781 * so if it encounters an error, we can't 2782 * identify which transid it belongs to. 2783 */ 2784 cmn_err(CE_WARN, 2785 "schpc - mboxsc_getmsg failed, err=0x%x", err); 2786 delay(drv_usectohz(100000)); 2787 continue; 2788 } 2789 } 2790 2791 if (msg.pcimsg_revision != PCIMSG_REVISION) { 2792 /* 2793 * This version of the schpc driver only understands 2794 * version 1.0 of the PCI Hot Plug Message format. 2795 */ 2796 cmn_err(CE_WARN, " schpc: schpc_msg_thread - " 2797 "discarding event w/ unknown message version %x", 2798 msg.pcimsg_revision); 2799 continue; 2800 } 2801 2802 switch (type) { 2803 2804 case MBOXSC_MSG_EVENT: 2805 schpc_event_filter(&msg); 2806 break; 2807 2808 case MBOXSC_MSG_REPLY: 2809 schpc_reply_handler(&msg, type, cmd, transid, length); 2810 break; 2811 2812 default: 2813 cmn_err(CE_WARN, 2814 "schpc - mboxsc_getmsg unknown msg" 2815 " type=0x%x", type); 2816 break; 2817 } 2818 } 2819 /* this thread never exits */ 2820 } 2821 2822 2823 void 2824 schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd, 2825 uint64_t transid, uint32_t length) 2826 { 2827 schpc_replylist_t *entry; 2828 2829 mutex_enter(&schpc_replylist_mutex); 2830 entry = schpc_replylist_first; 2831 while (entry != NULL) { 2832 if (entry->transid == transid) { 2833 break; 2834 } else 2835 entry = entry->next; 2836 } 2837 if (entry) { 2838 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2839 "schpc_reply_handler() - 0x%lx transid reply " 2840 "received", transid); 2841 2842 mutex_enter(&entry->reply_lock); 2843 if (entry->reply_cexit == B_FALSE) { 2844 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2845 "schpc_reply_handler() - 0x%lx transid" 2846 " cv_signal waiting thread", transid); 2847 2848 /* 2849 * emulate mboxsc_getmsg by copying the reply 2850 */ 2851 entry->type = type; 2852 entry->cmd = cmd; 2853 entry->transid = transid; 2854 entry->length = length; 2855 bcopy((caddr_t)pmsg, &entry->reply, length); 2856 2857 /* reply was received */ 2858 entry->reply_recvd = B_TRUE; 2859 2860 /* 2861 * wake up thread waiting for reply with transid 2862 */ 2863 cv_signal(&entry->reply_cv); 2864 } 2865 mutex_exit(&entry->reply_lock); 2866 } else { 2867 cmn_err(CE_WARN, "schpc - no match for transid 0x%lx", 2868 transid); 2869 } 2870 mutex_exit(&schpc_replylist_mutex); 2871 } 2872 2873 2874 /* 2875 * schpc_putrequest 2876 * 2877 * A wrapper around the synchronous call mboxsc_putmsg(). 2878 */ 2879 int 2880 schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp, 2881 uint32_t length, void *datap, clock_t timeout, 2882 schpc_replylist_t **entryp) 2883 { 2884 int rval; 2885 2886 /* add the request to replylist to keep track of outstanding requests */ 2887 *entryp = schpc_replylist_link(cmd, *transidp, length); 2888 2889 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - " 2890 "0x%lx transid mboxsc_putmsg called", *transidp); 2891 2892 /* wait synchronously for request to be sent */ 2893 rval = mboxsc_putmsg(key, type, cmd, transidp, length, 2894 (void *)datap, timeout); 2895 2896 SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - " 2897 "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval); 2898 2899 /* if problem is encountered then remove the request from replylist */ 2900 if (rval) 2901 schpc_replylist_unlink(*entryp); 2902 2903 return (rval); 2904 } 2905 2906 2907 /* 2908 * schpc_getreply 2909 * 2910 * Wait for the schpc_msg_thread to respond that a matching reply has 2911 * arrived; otherwise, timeout and remove the entry from the schpc_replylist. 2912 */ 2913 /*ARGSUSED*/ 2914 int 2915 schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp, 2916 uint64_t *transidp, uint32_t *lengthp, void *datap, 2917 clock_t timeout, schpc_replylist_t *listp) 2918 { 2919 int rc = 0; 2920 2921 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2922 "schpc_getreply() - 0x%lx transid waiting for reply", 2923 *transidp); 2924 2925 /* 2926 * wait here until schpc_msg_thread because it's always 2927 * looking for reply messages 2928 */ 2929 mutex_enter(&listp->reply_lock); 2930 2931 while (listp->reply_recvd == B_FALSE) { 2932 /* 2933 * wait for reply or timeout 2934 */ 2935 rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock, 2936 ddi_get_lbolt() + drv_usectohz(timeout * 1000)); 2937 switch (rc) { 2938 case -1: /* most likely a timeout, but check anyway */ 2939 2940 /* message was received after all */ 2941 if (listp->reply_recvd == B_TRUE) 2942 break; 2943 2944 /* no, it's really a timeout */ 2945 listp->reply_cexit = B_TRUE; 2946 mutex_exit(&listp->reply_lock); 2947 cmn_err(CE_WARN, 2948 "schpc - 0x%lx transid reply timed out", *transidp); 2949 schpc_replylist_unlink(listp); 2950 return (ETIMEDOUT); 2951 2952 default: 2953 break; 2954 } 2955 } 2956 2957 *typep = listp->type; 2958 *cmdp = listp->cmd; 2959 *transidp = listp->transid; 2960 *lengthp = listp->length; 2961 bcopy((caddr_t)&listp->reply, datap, *lengthp); 2962 mutex_exit(&listp->reply_lock); 2963 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2964 "schpc_getreply() - 0x%lx transid received", *transidp); 2965 schpc_replylist_unlink(listp); 2966 return (0); 2967 } 2968 2969 2970 /* 2971 * schpc_replylist_unlink 2972 * 2973 * Deallocate a schpc_replylist_t element. 2974 */ 2975 void 2976 schpc_replylist_unlink(schpc_replylist_t *entry) 2977 { 2978 #if DEBUG 2979 schpc_replylist_t *dbg_entry; 2980 #endif /* DEBUG */ 2981 2982 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 2983 "schpc_replylist_unlink() - 0x%lx transid deleted from replylist", 2984 entry->transid); 2985 2986 mutex_enter(&schpc_replylist_mutex); 2987 if (entry->prev) { 2988 entry->prev->next = entry->next; 2989 if (entry->next) 2990 entry->next->prev = entry->prev; 2991 } else { 2992 schpc_replylist_first = entry->next; 2993 if (entry->next) 2994 entry->next->prev = NULL; 2995 } 2996 if (entry == schpc_replylist_last) { 2997 schpc_replylist_last = entry->prev; 2998 } 2999 kmem_free(entry, sizeof (schpc_replylist_t)); 3000 schpc_replylist_count--; 3001 3002 #if DEBUG 3003 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) { 3004 dbg_entry = schpc_replylist_first; 3005 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist " 3006 "count = %d\n", schpc_replylist_count); 3007 while (dbg_entry != NULL) { 3008 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - " 3009 "0x%lx transid\n", dbg_entry->transid); 3010 dbg_entry = dbg_entry->next; 3011 } 3012 } 3013 #endif /* DEBUG */ 3014 3015 mutex_exit(&schpc_replylist_mutex); 3016 } 3017 3018 3019 /* 3020 * schpc_replylist_link 3021 * 3022 * Allocate and initialize a schpc_replylist_t element. 3023 */ 3024 schpc_replylist_t * 3025 schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length) 3026 { 3027 schpc_replylist_t *entry; 3028 #if DEBUG 3029 schpc_replylist_t *dbg_entry; 3030 #endif /* DEBUG */ 3031 3032 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, 3033 "schpc_replylist_link() - 0x%lx transid inserting into replylist", 3034 transid); 3035 3036 entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP); 3037 mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL); 3038 cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL); 3039 entry->type = MBOXSC_MSG_REPLY; 3040 entry->cmd = cmd; 3041 entry->transid = transid; 3042 entry->length = length; 3043 entry->reply_recvd = B_FALSE; 3044 entry->reply_cexit = B_FALSE; 3045 3046 mutex_enter(&schpc_replylist_mutex); 3047 if (schpc_replylist_last) { 3048 entry->prev = schpc_replylist_last; 3049 schpc_replylist_last->next = entry; 3050 schpc_replylist_last = entry; 3051 } else { 3052 schpc_replylist_last = schpc_replylist_first = entry; 3053 } 3054 3055 schpc_replylist_count++; 3056 3057 #if DEBUG 3058 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) { 3059 dbg_entry = schpc_replylist_first; 3060 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist " 3061 "count = %d\n", schpc_replylist_count); 3062 while (dbg_entry != NULL) { 3063 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - " 3064 "0x%lx transid\n", dbg_entry->transid); 3065 dbg_entry = dbg_entry->next; 3066 } 3067 } 3068 #endif /* DEBUG */ 3069 3070 mutex_exit(&schpc_replylist_mutex); 3071 3072 return (entry); 3073 } 3074 3075 3076 /* 3077 * schpc_getslotstatus 3078 * 3079 * Issues a Get Slot Status command to the System Controller 3080 * for a specific slot. 3081 */ 3082 static int 3083 schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot, 3084 pci_getslot_t *slotstatus) 3085 { 3086 pcimsg_t request; 3087 pcimsg_t reply; 3088 int rval; 3089 uint32_t type, cmd, length; 3090 uint64_t transid; 3091 schpc_replylist_t *entry; 3092 3093 SCHPC_DEBUG4(D_GETSLOTSTATUS, 3094 "schpc_getslotstatus(expander=%d board=%d " 3095 "slot=%d slotstatus=0x%p", expander, board, 3096 SCHPC_SLOT_NUM(slot), slotstatus); 3097 3098 if (schpc_p == NULL) { 3099 return (1); 3100 } 3101 3102 bzero(&request, sizeof (pcimsg_t)); 3103 3104 request.pcimsg_node = expander; 3105 request.pcimsg_board = board; 3106 request.pcimsg_slot = SCHPC_SLOT_NUM(slot); 3107 request.pcimsg_revision = PCIMSG_REVISION; 3108 request.pcimsg_command = PCIMSG_GETSLOTSTATUS; 3109 3110 type = MBOXSC_MSG_REQUEST; 3111 cmd = PCIMSG_GETSLOTSTATUS; 3112 transid = schpc_gettransid(schpc_p, slot); 3113 length = sizeof (pcimsg_t); 3114 3115 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3116 "0x%lx transid schpc_putrequest called", transid); 3117 3118 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length, 3119 (void *)&request, schpc_timeout_putmsg, &entry); 3120 3121 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3122 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval); 3123 3124 if (rval) { 3125 return (rval); 3126 } 3127 3128 bzero(&reply, sizeof (pcimsg_t)); 3129 type = MBOXSC_MSG_REPLY; 3130 3131 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3132 "0x%lx transid schpc_getreply called", transid); 3133 3134 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length, 3135 (void *)&reply, schpc_timeout_getmsg, entry); 3136 3137 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - " 3138 "0x%lx transid schpc_getreply returned 0x%x", transid, rval); 3139 3140 if (rval == 0) { 3141 *slotstatus = reply.pcimsg_type.pcimsg_getslot; 3142 3143 SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()"); 3144 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_power_on %x", 3145 reply.pcimsg_type.pcimsg_getslot.slot_power_on); 3146 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powergood %x", 3147 reply.pcimsg_type.pcimsg_getslot.slot_powergood); 3148 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powerfault %x", 3149 reply.pcimsg_type.pcimsg_getslot.slot_powerfault); 3150 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_empty %x", 3151 reply.pcimsg_type.pcimsg_getslot.slot_empty); 3152 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_cap %x", 3153 reply.pcimsg_type.pcimsg_getslot.slot_freq_cap); 3154 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_setting %x", 3155 reply.pcimsg_type.pcimsg_getslot.slot_freq_setting); 3156 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_condition %x", 3157 reply.pcimsg_type.pcimsg_getslot.slot_condition); 3158 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_HEALTHY %x", 3159 reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY); 3160 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_ENUM %x", 3161 reply.pcimsg_type.pcimsg_getslot.slot_ENUM); 3162 } 3163 3164 return (rval); 3165 } 3166 3167 3168 /* 3169 * schpc_setslotstatus 3170 * 3171 * Issues a Set Slot Status command to the System Controller 3172 * for a specific slot. 3173 */ 3174 static int 3175 schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot, 3176 pci_setslot_t *slotstatus) 3177 { 3178 pcimsg_t request; 3179 pcimsg_t reply; 3180 int rval; 3181 uint32_t type, cmd, length; 3182 uint64_t transid; 3183 schpc_replylist_t *entry; 3184 3185 SCHPC_DEBUG4(D_SETSLOTSTATUS, 3186 "schpc_setslotstatus(expander=%d board=%d " 3187 "slot=%d slotstatus=0x%p", expander, board, 3188 SCHPC_SLOT_NUM(slot), slotstatus); 3189 3190 bzero(&request, sizeof (pcimsg_t)); 3191 3192 if (schpc_p == NULL) { 3193 return (1); 3194 } 3195 3196 request.pcimsg_node = expander; 3197 request.pcimsg_board = board; 3198 request.pcimsg_slot = SCHPC_SLOT_NUM(slot); 3199 request.pcimsg_revision = PCIMSG_REVISION; 3200 request.pcimsg_command = PCIMSG_SETSLOTSTATUS; 3201 3202 request.pcimsg_type.pcimsg_setslot = *slotstatus; 3203 3204 SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change"); 3205 SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d", 3206 slotstatus->slot_led_power, 3207 slotstatus->slot_led_service, 3208 slotstatus->slot_led_fault); 3209 3210 type = MBOXSC_MSG_REQUEST; 3211 cmd = PCIMSG_SETSLOTSTATUS; 3212 transid = schpc_gettransid(schpc_p, slot); 3213 length = sizeof (pcimsg_t); 3214 3215 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3216 "0x%lx transid schpc_putrequest called", transid); 3217 3218 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length, 3219 (void *)&request, schpc_timeout_putmsg, &entry); 3220 3221 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3222 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval); 3223 3224 if (rval) { 3225 return (rval); 3226 } 3227 3228 bzero(&reply, sizeof (pcimsg_t)); 3229 type = MBOXSC_MSG_REPLY; 3230 3231 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3232 "0x%lx transid schpc_getreply called", transid); 3233 3234 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length, 3235 (void *)&reply, schpc_timeout_getmsg, entry); 3236 3237 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - " 3238 "0x%lx transid schpc_getreply returned 0x%x", transid, rval); 3239 3240 if (rval == 0) { 3241 slotstatus->slot_replystatus = 3242 reply.pcimsg_type.pcimsg_setslot.slot_replystatus; 3243 } 3244 3245 return (rval); 3246 } 3247 3248 /* 3249 * schpc_setslotled 3250 * 3251 * Changes the attention indicators for a given slot. 3252 */ 3253 static void 3254 schpc_setslotled(int expander, int board, int slot, uint32_t led_state) 3255 { 3256 3257 pci_setslot_t setslot; 3258 3259 if (schpc_p == NULL) { 3260 return; 3261 } 3262 3263 schpc_init_setslot_message(&setslot); 3264 3265 if (led_state & POWER_LED_ON) { 3266 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON; 3267 } 3268 if (led_state & POWER_LED_OFF) { 3269 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF; 3270 } 3271 if (led_state & POWER_LED_FLASH) { 3272 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH; 3273 } 3274 if (led_state & SERVICE_LED_ON) { 3275 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON; 3276 } 3277 if (led_state & SERVICE_LED_OFF) { 3278 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF; 3279 } 3280 if (led_state & SERVICE_LED_FLASH) { 3281 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH; 3282 } 3283 if (led_state & FAULT_LED_ON) { 3284 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON; 3285 } 3286 if (led_state & FAULT_LED_OFF) { 3287 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF; 3288 } 3289 if (led_state & FAULT_LED_FLASH) { 3290 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH; 3291 } 3292 3293 switch (schpc_p->schpc_slot[slot].led.led_power) { 3294 case PCIMSG_LED_ON: 3295 setslot.slot_led_power = PCIMSG_LED_ON; 3296 break; 3297 case PCIMSG_LED_OFF: 3298 setslot.slot_led_power = PCIMSG_LED_OFF; 3299 break; 3300 case PCIMSG_LED_FLASH: 3301 setslot.slot_led_power = PCIMSG_LED_FLASH; 3302 break; 3303 } 3304 switch (schpc_p->schpc_slot[slot].led.led_service) { 3305 case PCIMSG_LED_ON: 3306 setslot.slot_led_service = PCIMSG_LED_ON; 3307 break; 3308 case PCIMSG_LED_OFF: 3309 setslot.slot_led_service = PCIMSG_LED_OFF; 3310 break; 3311 case PCIMSG_LED_FLASH: 3312 setslot.slot_led_service = PCIMSG_LED_FLASH; 3313 break; 3314 } 3315 switch (schpc_p->schpc_slot[slot].led.led_fault) { 3316 case PCIMSG_LED_ON: 3317 setslot.slot_led_fault = PCIMSG_LED_ON; 3318 break; 3319 case PCIMSG_LED_OFF: 3320 setslot.slot_led_fault = PCIMSG_LED_OFF; 3321 break; 3322 case PCIMSG_LED_FLASH: 3323 setslot.slot_led_fault = PCIMSG_LED_FLASH; 3324 break; 3325 } 3326 3327 (void) schpc_setslotstatus(expander, board, slot, &setslot); 3328 } 3329 3330 /* 3331 * schpc_init_setslot_message 3332 * 3333 * Initialize Set Slot Message before using it. 3334 */ 3335 static void 3336 schpc_init_setslot_message(pci_setslot_t *setslot) 3337 { 3338 /* 3339 * Initialize Set Slot Command. 3340 */ 3341 setslot->slot_power_on = PCIMSG_OFF; 3342 setslot->slot_power_off = PCIMSG_OFF; 3343 setslot->slot_led_power = PCIMSG_LED_OFF; 3344 setslot->slot_led_service = PCIMSG_LED_OFF; 3345 setslot->slot_led_fault = PCIMSG_LED_OFF; 3346 setslot->slot_disable_ENUM = PCIMSG_OFF; 3347 setslot->slot_enable_ENUM = PCIMSG_OFF; 3348 setslot->slot_disable_HEALTHY = PCIMSG_OFF; 3349 setslot->slot_enable_HEALTHY = PCIMSG_OFF; 3350 } 3351 3352 /* 3353 * schpc_gettransid 3354 * 3355 * Builds a unique transaction ID. 3356 */ 3357 static uint64_t 3358 schpc_gettransid(schpc_t *schpc_p, int slot) 3359 { 3360 uint64_t trans_id; 3361 3362 mutex_enter(&schpc_p->schpc_mutex); 3363 3364 if (++schpc_p->schpc_transid == 0) 3365 schpc_p->schpc_transid = 1; 3366 3367 trans_id = (schpc_p->schpc_slot[slot].expander<<24) | 3368 (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid; 3369 3370 mutex_exit(&schpc_p->schpc_mutex); 3371 3372 SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning", 3373 trans_id); 3374 3375 return (trans_id); 3376 } 3377 3378 /* 3379 * schpc_slot_get_index 3380 * 3381 * get slot table index from the slot handle 3382 */ 3383 static int 3384 schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot) 3385 { 3386 int i; 3387 int rval = -1; 3388 3389 ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex)); 3390 3391 for (i = 0; i < schpc_p->schpc_number_of_slots; i++) { 3392 if (schpc_p->schpc_slot[i].slot_handle == slot) 3393 return (i); 3394 } 3395 3396 return (rval); 3397 } 3398 3399 /* 3400 * schpc_register_all_slots 3401 * 3402 * Search device tree for pci nodes and register attachment points 3403 * for all hot pluggable slots. 3404 */ 3405 /*ARGSUSED*/ 3406 static void 3407 schpc_register_all_slots(schpc_t *schpc_p) 3408 { 3409 int slot = 0; 3410 char caddr[64]; 3411 dev_info_t *pci_dip = NULL; 3412 find_dev_t find_dev; 3413 int leaf, schizo, expander, portid, offset; 3414 3415 SCHPC_DEBUG1(D_ATTACH, 3416 "schpc_register_all_slots(schpc_p=%p)", schpc_p); 3417 3418 /* 3419 * Allow the event_handler to start processing unsolicited 3420 * events now that slots are about to be registered. 3421 */ 3422 slots_registered = B_TRUE; 3423 3424 for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) { 3425 3426 leaf = SCHPC_SLOT_LEAF(slot); 3427 schizo = SCHPC_SLOT_SCHIZO(slot); 3428 expander = SCHPC_SLOT_EXPANDER(slot); 3429 3430 if (schizo == 0) 3431 portid = 0x1c; 3432 else 3433 portid = 0x1d; 3434 3435 if (leaf == 0) 3436 offset = 0x600000; 3437 else 3438 offset = 0x700000; 3439 3440 portid = (expander << 5) | portid; 3441 3442 (void) sprintf(caddr, "%x,%x", portid, offset); 3443 3444 SCHPC_DEBUG3(D_ATTACH, 3445 "schpc_register_all_slots: searching for pci@%s" 3446 " schizo=%d, leaf=%d", caddr, schizo, leaf); 3447 3448 find_dev.cname = "pci"; 3449 find_dev.caddr = caddr; 3450 find_dev.schizo = schizo; 3451 find_dev.leaf = leaf; 3452 find_dev.dip = NULL; 3453 3454 /* root node doesn't have to be held */ 3455 ddi_walk_devs(ddi_root_node(), schpc_match_dip, 3456 &find_dev); 3457 3458 pci_dip = find_dev.dip; 3459 3460 if (pci_dip == NULL) { 3461 3462 SCHPC_DEBUG1(D_ATTACH, 3463 "schpc_register_all_slots: pci@%s NOT FOUND", 3464 caddr); 3465 3466 continue; 3467 } 3468 3469 SCHPC_DEBUG2(D_ATTACH, 3470 "schpc_register_all_slots: pci@%s FOUND dip=0x%p", 3471 caddr, pci_dip); 3472 3473 (void) schpc_add_pci(pci_dip); 3474 3475 /* 3476 * Release hold acquired in schpc_match_dip() 3477 */ 3478 ndi_rele_devi(pci_dip); 3479 } 3480 3481 SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit"); 3482 3483 thread_exit(); 3484 } 3485 3486 /* 3487 * schpc_add_pci 3488 * 3489 * Routine to add attachments points associated with a pci node. 3490 * Can be call externally by DR when configuring a PCI I/O Board. 3491 */ 3492 int 3493 schpc_add_pci(dev_info_t *bdip) 3494 { 3495 int portid; 3496 int expander, board, schizo, leaf, slot, status; 3497 char ap_id[MAXNAMELEN]; 3498 char caddr[64]; 3499 char *naddr; 3500 hpc_slot_info_t slot_info; 3501 hpc_slot_ops_t *slot_ops; 3502 dev_info_t *sdip = bdip; 3503 3504 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", sdip); 3505 3506 if (schpc_p == NULL) { 3507 /* 3508 * The schpc driver has not been attached yet. 3509 */ 3510 return (DDI_SUCCESS); 3511 } 3512 3513 if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) { 3514 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n", sdip); 3515 return (DDI_FAILURE); 3516 } 3517 3518 expander = schpc_getexpander(sdip); 3519 board = schpc_getboard(sdip); 3520 3521 switch (portid & 0x1f) { 3522 3523 case 0x1c: 3524 schizo = 0; 3525 break; 3526 case 0x1d: 3527 schizo = 1; 3528 break; 3529 default: 3530 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 3531 "Invalid pci portid 0x%x\n", sdip, portid); 3532 return (DDI_FAILURE); 3533 } 3534 3535 naddr = ddi_get_name_addr(sdip); 3536 if (naddr == NULL) { 3537 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr" 3538 "(0x%p) returns null", sdip); 3539 return (DDI_FAILURE); 3540 } 3541 3542 (void) sprintf(caddr, "%x,600000", portid); 3543 3544 if (strcmp(caddr, naddr) == 0) { 3545 leaf = 0; 3546 } else { 3547 (void) sprintf(caddr, "%x,700000", portid); 3548 if (strcmp(caddr, naddr) == 0) { 3549 char *name; 3550 3551 leaf = 1; 3552 name = ddi_binding_name(sdip); 3553 if ((strcmp(name, "pci108e,8002") == 0) && 3554 (schizo == 0)) { 3555 int circ; 3556 dev_info_t *cdip; 3557 /* 3558 * XMITS 0 Leaf B will have its hot 3559 * pluggable slot off a PCI-PCI bridge, 3560 * which is the only child. 3561 */ 3562 ndi_devi_enter(sdip, &circ); 3563 cdip = ddi_get_child(sdip); 3564 if (cdip == NULL) { 3565 cmn_err(CE_WARN, 3566 "schpc_add_pci(dip=0x%p) - " 3567 "Invalid pci name addr %s\n", 3568 sdip, naddr); 3569 ndi_devi_exit(sdip, circ); 3570 return (DDI_FAILURE); 3571 } 3572 ndi_devi_exit(sdip, circ); 3573 sdip = cdip; 3574 } 3575 } else { 3576 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 3577 "Invalid pci name addr %s\n", sdip, naddr); 3578 return (DDI_FAILURE); 3579 } 3580 } 3581 3582 /* create a slot table index */ 3583 slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf); 3584 3585 if (schpc_p->schpc_slot[slot].devi) { 3586 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - " 3587 "pci node already registered\n", sdip); 3588 return (DDI_FAILURE); 3589 } 3590 3591 /* 3592 * There is no need to hold the dip while saving it in 3593 * the devi field below. The dip is never dereferenced. 3594 * (If that changes, this code should be modified). 3595 * We want to avoid holding the dip here because it 3596 * prevents DR. 3597 * 3598 * NOTE: Even though the slot on XMITS0 Leaf-B 3599 * is connected to a pci_pci bridge, we will be saving 3600 * the busdip in this datastructure. This will make 3601 * it easier to identify the dip being removed in 3602 * schpc_remove_pci(). 3603 */ 3604 schpc_p->schpc_slot[slot].devi = bdip; 3605 3606 schpc_p->schpc_slot[slot].expander = expander; 3607 schpc_p->schpc_slot[slot].board = board; 3608 schpc_p->schpc_slot[slot].schizo = schizo; 3609 schpc_p->schpc_slot[slot].leaf = leaf; 3610 3611 /* 3612 * Starcat PCI slots are always PCI device 1. 3613 */ 3614 schpc_p->schpc_slot[slot].pci_id = 1; 3615 3616 schpc_buildapid(sdip, slot, (char *)&ap_id); 3617 3618 (void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id); 3619 3620 /* safe to call ddi_pathname(): bdip is held */ 3621 (void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path); 3622 3623 status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot)); 3624 switch (status) { 3625 case RSV_UNKNOWN: 3626 case RSV_PRESENT: 3627 case RSV_MISS: 3628 case RSV_PASS: 3629 case RSV_EMPTY_CASSETTE: 3630 3631 /* 3632 * Test the condition of the slot. 3633 */ 3634 schpc_test((caddr_t)schpc_p, slot, 0, 0); 3635 break; 3636 case RSV_BLACK: 3637 schpc_p->schpc_slot[slot].state = 0; 3638 cmn_err(CE_WARN, "schpc: PCI card blacklisted: " 3639 "expander=%d board=%d slot=%d\n", expander, 3640 board, SCHPC_SLOT_NUM(slot)); 3641 break; 3642 default: 3643 schpc_p->schpc_slot[slot].state = 0; 3644 cmn_err(CE_WARN, "schpc: PCI card failed by POST: " 3645 "expander=%d board=%d slot=%d failure=0x%x\n", 3646 expander, board, SCHPC_SLOT_NUM(slot), status); 3647 break; 3648 } 3649 3650 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) { 3651 3652 /* allocate slot ops */ 3653 3654 slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 3655 schpc_p->schpc_slot[slot].slot_ops = slot_ops; 3656 3657 /* 3658 * Default to Autoconfiguration disabled. 3659 */ 3660 schpc_p->schpc_slot[slot].state &= 3661 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE; 3662 3663 /* 3664 * Fill in the slot information structure that 3665 * describes the slot. 3666 */ 3667 slot_info.version = HPC_SLOT_OPS_VERSION; 3668 3669 if (schpc_p->schpc_hotplugmodel == 3670 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) 3671 slot_info.slot_type = HPC_SLOT_TYPE_PCI; 3672 else 3673 slot_info.slot_type = HPC_SLOT_TYPE_CPCI; 3674 3675 slot_info.slot.pci.device_number = 3676 schpc_p->schpc_slot[slot].pci_id; 3677 3678 slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS; 3679 3680 if (schpc_use_legacy_apid) 3681 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE; 3682 else 3683 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE | 3684 HPC_SLOT_CREATE_DEVLINK; 3685 3686 strcpy(slot_info.slot.pci.slot_logical_name, 3687 schpc_p->schpc_slot[slot].ap_id); 3688 3689 /* 3690 * Fill in the slot ops structure that tells 3691 * the Hot Plug Services what function we 3692 * support. 3693 */ 3694 slot_ops->hpc_version = HPC_SLOT_OPS_VERSION; 3695 if (schpc_p->schpc_hotplugmodel == 3696 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) { 3697 slot_ops->hpc_op_connect = schpc_connect; 3698 slot_ops->hpc_op_disconnect = schpc_disconnect; 3699 slot_ops->hpc_op_insert = NULL; 3700 slot_ops->hpc_op_remove = NULL; 3701 slot_ops->hpc_op_control = schpc_pci_control; 3702 } else { 3703 slot_ops->hpc_op_connect = NULL; 3704 slot_ops->hpc_op_disconnect = NULL; 3705 slot_ops->hpc_op_insert = NULL; 3706 slot_ops->hpc_op_remove = NULL; 3707 slot_ops->hpc_op_control = schpc_cpci_control; 3708 } 3709 3710 SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC " 3711 "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s", 3712 schpc_p->schpc_slot[slot].nexus_path, 3713 schpc_p, SCHPC_SLOT_NUM(slot), 3714 slot_info.slot.pci.device_number, 3715 slot_info.slot.pci.slot_logical_name); 3716 3717 if (hpc_slot_register(schpc_p->schpc_devi, 3718 schpc_p->schpc_slot[slot].nexus_path, &slot_info, 3719 &schpc_p->schpc_slot[slot].slot_handle, 3720 slot_ops, (caddr_t)schpc_p, 0) != 0) { 3721 3722 /* 3723 * If the slot can not be registered, 3724 * then the slot_ops need to be freed. 3725 */ 3726 cmn_err(CE_WARN, "schpc%d Unable to Register " 3727 "Slot %s", schpc_p->schpc_instance, 3728 slot_info.slot.pci.slot_logical_name); 3729 3730 hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops); 3731 3732 schpc_p->schpc_slot[slot].slot_ops = NULL; 3733 3734 return (DDI_FAILURE); 3735 } 3736 3737 /* 3738 * We are ready to take commands from the HPC Services. 3739 */ 3740 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED; 3741 } 3742 3743 return (DDI_SUCCESS); 3744 } 3745 3746 /* 3747 * schpc_remove_pci 3748 * 3749 * Routine to remove attachments points associated with a pci node. 3750 * Can be call externally by DR when unconfiguring a PCI I/O Board. 3751 */ 3752 int 3753 schpc_remove_pci(dev_info_t *dip) 3754 { 3755 int slot; 3756 3757 SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", dip); 3758 3759 if (schpc_p == NULL) { 3760 /* 3761 * The schpc driver has not been attached yet. 3762 */ 3763 return (DDI_SUCCESS); 3764 } 3765 3766 for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) { 3767 if (schpc_p->schpc_slot[slot].devi == dip) { 3768 3769 if (schpc_p->schpc_slot[slot].slot_ops) { 3770 if (hpc_slot_unregister( 3771 &schpc_p->schpc_slot[slot].slot_handle)) { 3772 cmn_err(CE_WARN, 3773 "schpc_remove_pci(dip=0x%p) - " 3774 "unable to unregister pci slots\n", 3775 dip); 3776 return (DDI_FAILURE); 3777 } else { 3778 hpc_free_slot_ops( 3779 schpc_p->schpc_slot[slot].slot_ops); 3780 3781 schpc_p->schpc_slot[slot].slot_ops = 3782 NULL; 3783 3784 schpc_p->schpc_slot[slot].devi = NULL; 3785 3786 return (DDI_SUCCESS); 3787 } 3788 } else { 3789 schpc_p->schpc_slot[slot].devi = NULL; 3790 3791 return (DDI_SUCCESS); 3792 } 3793 } 3794 } 3795 3796 cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) " 3797 "dip not found\n", dip); 3798 3799 return (DDI_SUCCESS); 3800 } 3801 3802 /* 3803 * schpc_match_dip 3804 * 3805 * Used by ddi_walk_devs to find PCI Nexus nodes associated with 3806 * Hot Plug Controllers. 3807 */ 3808 static int 3809 schpc_match_dip(dev_info_t *dip, void *arg) 3810 { 3811 char *naddr; 3812 find_dev_t *find_dev = (find_dev_t *)arg; 3813 3814 if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 && 3815 ((((naddr = ddi_get_name_addr(dip)) != NULL) && 3816 (strcmp(find_dev->caddr, naddr) == 0)) || 3817 ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) { 3818 /* 3819 * While ddi_walk_devs() holds dips when invoking this 3820 * callback, this dip is being saved and will be accessible 3821 * to the caller outside ddi_walk_devs(). Therefore it must be 3822 * held. 3823 */ 3824 ndi_hold_devi(dip); 3825 find_dev->dip = dip; 3826 3827 SCHPC_DEBUG2(D_ATTACH, 3828 "schpc_match_dip: pci@%s FOUND dip=0x%p", 3829 find_dev->caddr, find_dev->dip); 3830 3831 return (DDI_WALK_TERMINATE); 3832 } 3833 3834 ASSERT(find_dev->dip == NULL); 3835 return (DDI_WALK_CONTINUE); 3836 } 3837 3838 /* 3839 * schpc_buildapid 3840 * 3841 * Takes a component address and translates it into a ap_id prefix. 3842 */ 3843 static void 3844 schpc_buildapid(dev_info_t *dip, int slot, char *ap_id) 3845 { 3846 int r, pci_id_cnt, pci_id_bit; 3847 int slots_before, found; 3848 unsigned char *slot_names_data, *s; 3849 int slot_names_size; 3850 int slot_num; 3851 unsigned int bit_mask; 3852 3853 slot_num = SCHPC_SLOT_NUM(slot); 3854 3855 if (schpc_use_legacy_apid) { 3856 SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot); 3857 3858 sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip), 3859 schpc_getboard(dip), slot_num); 3860 3861 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id); 3862 3863 return; 3864 } 3865 3866 r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3867 "slot-names", (caddr_t)&slot_names_data, 3868 &slot_names_size); 3869 3870 if (r == DDI_PROP_SUCCESS) { 3871 3872 /* 3873 * We can try to use the slot-names property to 3874 * build our ap-id. 3875 */ 3876 bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) | 3877 (slot_names_data[1] << 16) | (slot_names_data[0] << 24); 3878 3879 pci_id_bit = 1; 3880 pci_id_cnt = slots_before = found = 0; 3881 3882 SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x", 3883 slot, bit_mask); 3884 3885 /* 3886 * Walk the bit mask until we find the bit that corresponds 3887 * to our slots device number. We count how many bits 3888 * we find before we find our slot's bit. 3889 */ 3890 while (!found && (pci_id_cnt < 32)) { 3891 3892 while (schpc_p->schpc_slot[slot].pci_id 3893 != pci_id_cnt) { 3894 3895 /* 3896 * Find the next bit set. 3897 */ 3898 while (!(bit_mask & pci_id_bit) && 3899 (pci_id_cnt < 32)) { 3900 pci_id_bit = pci_id_bit << 1; 3901 pci_id_cnt++; 3902 } 3903 3904 if (schpc_p->schpc_slot[slot].pci_id != 3905 pci_id_cnt) 3906 slots_before++; 3907 else 3908 found = 1; 3909 } 3910 } 3911 3912 if (pci_id_cnt < 32) { 3913 3914 /* 3915 * Set ptr to first string. 3916 */ 3917 s = slot_names_data + 4; 3918 3919 /* 3920 * Increment past all the strings for the slots 3921 * before ours. 3922 */ 3923 while (slots_before) { 3924 while (*s != NULL) 3925 s++; 3926 s++; 3927 slots_before--; 3928 } 3929 3930 /* 3931 * We should be at our string. 3932 */ 3933 3934 sprintf(ap_id, "IO%d_%s", schpc_getexpander(dip), s); 3935 3936 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", 3937 slot, ap_id); 3938 3939 kmem_free(slot_names_data, slot_names_size); 3940 return; 3941 } 3942 3943 SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found", 3944 slot); 3945 3946 kmem_free(slot_names_data, slot_names_size); 3947 } else 3948 SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found", 3949 slot); 3950 3951 /* 3952 * Build the ap-id using the legacy naming scheme. 3953 */ 3954 sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip), 3955 schpc_getboard(dip), slot_num); 3956 3957 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id); 3958 } 3959 3960 /* 3961 * schpc_getexpander 3962 * 3963 * Returns the Expander Number (0-17) for the dip passed in. The Expander 3964 * Number is extracted from the portid property of the pci node. Portid 3965 * consists of <Expbrd#><1110x>, where x is the schizo number. 3966 */ 3967 static int 3968 schpc_getexpander(dev_info_t *dip) 3969 { 3970 int id; 3971 3972 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1); 3973 3974 if (id != -1) 3975 return (id >> 5); 3976 else { 3977 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1); 3978 return (id); 3979 } 3980 } 3981 3982 /* 3983 * schpc_getboard 3984 * 3985 * Returns the board number (0 or 1) for the dip passed in. 3986 */ 3987 static int 3988 schpc_getboard(dev_info_t *dip) 3989 { 3990 _NOTE(ARGUNUSED(dip)) 3991 3992 /* 3993 * Hot Pluggable PCI/cPCI slots are only available on 3994 * Board 1 (half-bandwidth slot). 3995 */ 3996 return (1); 3997 } 3998 3999 /*ARGSUSED*/ 4000 static int 4001 schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot) 4002 { 4003 gdcd_t *gdcd; 4004 int prd_slot, status, bus; 4005 4006 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() " 4007 "exp=%d board=%d slot=%d", expander, board, slot); 4008 4009 if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t), 4010 KM_SLEEP)) == NULL) { 4011 return (RSV_UNDEFINED); 4012 } 4013 4014 /* 4015 * Get the Starcat Specific Global DCD Structure from the golden 4016 * IOSRAM. 4017 */ 4018 if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) { 4019 cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD " 4020 "From IOSRAM\n"); 4021 kmem_free(gdcd, sizeof (gdcd_t)); 4022 return (RSV_UNDEFINED); 4023 } 4024 4025 if (gdcd->h.dcd_magic != GDCD_MAGIC) { 4026 4027 cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n", 4028 gdcd->h.dcd_magic); 4029 4030 kmem_free(gdcd, sizeof (gdcd_t)); 4031 return (RSV_UNDEFINED); 4032 } 4033 4034 if (gdcd->h.dcd_version != DCD_VERSION) { 4035 cmn_err(CE_WARN, "schpc: GDCD Bad Version: " 4036 "GDCD Version 0x%x Expecting 0x%x\n", 4037 gdcd->h.dcd_version, DCD_VERSION); 4038 4039 kmem_free(gdcd, sizeof (gdcd_t)); 4040 return (RSV_UNDEFINED); 4041 } 4042 4043 if (slot < 2) 4044 prd_slot = 4; 4045 else 4046 prd_slot = 5; 4047 4048 bus = slot & 0x1; 4049 4050 status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0]; 4051 4052 kmem_free(gdcd, sizeof (gdcd_t)); 4053 4054 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() " 4055 "prd_slot=%d bus=%d status=%d", prd_slot, bus, status); 4056 4057 return (status); 4058 } 4059 4060 #define LEAF_SAVE_END 0xff 4061 4062 typedef struct { 4063 int reg; 4064 int offset; 4065 int access_size; 4066 int number; 4067 } save_reg_list_t; 4068 4069 /* 4070 * Save List Array. Describes the leaf registers that need to 4071 * be restored after a leaf reset. 4072 * 4073 * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space 4074 * Entry 2 - Offset Start 4075 * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit 4076 * Entry 4 - # of registers to be saved starting at offset, 4077 */ 4078 save_reg_list_t save_reg_list[] = { 0, 0x110, 8, 1, 4079 0, 0x200, 8, 2, 4080 0, 0x1000, 8, 0x18, 4081 0, 0x1a00, 8, 1, 4082 0, 0x2000, 8, 1, 4083 0, 0x2020, 8, 1, 4084 0, 0x2040, 8, 1, 4085 0, 0x2308, 8, 2, 4086 0, 0x2800, 8, 1, 4087 2, 0x04, 2, 1, /* Command */ 4088 2, 0x0d, 1, 1, /* Latency */ 4089 2, 0x40, 1, 1, /* Bus # */ 4090 2, 0x41, 1, 1, /* Sub. Bus # */ 4091 LEAF_SAVE_END, 0, 0, 0}; 4092 4093 static int 4094 schpc_save_leaf(int slot) 4095 { 4096 int save_entry, list_entry, reg; 4097 caddr_t leaf_regs; 4098 ddi_device_acc_attr_t attr; 4099 4100 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot); 4101 4102 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 4103 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 4104 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 4105 4106 /* 4107 * Map in the 3 addresses spaces defined for XMITS. 4108 */ 4109 for (reg = 0; reg < 3; reg++) { 4110 if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg, 4111 &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot]. 4112 saved_handle[reg]) != DDI_SUCCESS) { 4113 cmn_err(CE_WARN, "Mapin failed\n"); 4114 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL; 4115 return (1); 4116 } 4117 4118 schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs; 4119 } 4120 4121 4122 /* 4123 * Determine how many entries are in the list so we can 4124 * allocate the save space. 4125 */ 4126 list_entry = 0; 4127 save_entry = 0; 4128 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 4129 save_entry += save_reg_list[list_entry].number; 4130 list_entry++; 4131 } 4132 4133 schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t)); 4134 4135 if (schpc_p->schpc_slot[slot].saved_size == 0) 4136 return (0); 4137 4138 schpc_p->schpc_slot[slot].saved_regs = 4139 (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size, 4140 KM_SLEEP); 4141 4142 /* 4143 * Walk through the register list and save contents. 4144 */ 4145 list_entry = 0; 4146 save_entry = 0; 4147 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 4148 schpc_save_entry(slot, list_entry, save_entry); 4149 save_entry += save_reg_list[list_entry].number; 4150 list_entry ++; 4151 } 4152 4153 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot); 4154 4155 return (0); 4156 } 4157 4158 static void 4159 schpc_restore_leaf(int slot) 4160 { 4161 int save_entry, list_entry, reg; 4162 4163 if (schpc_p->schpc_slot[slot].saved_regs == NULL) 4164 return; 4165 4166 /* 4167 * Walk through the register list and restore contents. 4168 */ 4169 list_entry = 0; 4170 save_entry = 0; 4171 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) { 4172 4173 schpc_restore_entry(slot, list_entry, save_entry); 4174 4175 save_entry += save_reg_list[list_entry].number; 4176 list_entry ++; 4177 } 4178 4179 /* 4180 * Free the mapped in registers. 4181 */ 4182 for (reg = 0; reg < 3; reg++) { 4183 if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) { 4184 4185 ddi_regs_map_free( 4186 &schpc_p->schpc_slot[slot].saved_handle[reg]); 4187 4188 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL; 4189 } 4190 } 4191 4192 kmem_free(schpc_p->schpc_slot[slot].saved_regs, 4193 schpc_p->schpc_slot[slot].saved_size); 4194 4195 schpc_p->schpc_slot[slot].saved_size = 0; 4196 schpc_p->schpc_slot[slot].saved_regs = NULL; 4197 4198 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot); 4199 } 4200 4201 static void 4202 schpc_save_entry(int slot, int list_entry, int save_entry) 4203 { 4204 int reg, reads = 0; 4205 4206 reg = save_reg_list[list_entry].reg; 4207 4208 while (reads < save_reg_list[list_entry].number) { 4209 switch (save_reg_list[list_entry].access_size) { 4210 case 8: 4211 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4212 ddi_get64( 4213 schpc_p->schpc_slot[slot].saved_handle[reg], 4214 (uint64_t *)(schpc_p->schpc_slot[slot]. 4215 saved_regs_va[reg] 4216 + save_reg_list[list_entry].offset + 4217 (reads * sizeof (uint64_t)))); 4218 #ifdef DEBUG 4219 if (schpc_dump_save_regs) 4220 cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg, 4221 save_reg_list[list_entry].offset + 4222 (reads * sizeof (uint64_t)), 4223 schpc_p->schpc_slot[slot]. 4224 saved_regs[save_entry]); 4225 #endif 4226 4227 break; 4228 case 4: 4229 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4230 ddi_get32( 4231 schpc_p->schpc_slot[slot].saved_handle[reg], 4232 (uint32_t *)(schpc_p->schpc_slot[slot]. 4233 saved_regs_va[reg] 4234 + save_reg_list[list_entry].offset + 4235 (reads * sizeof (uint32_t)))); 4236 4237 #ifdef DEBUG 4238 if (schpc_dump_save_regs) 4239 cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg, 4240 save_reg_list[list_entry].offset + 4241 (reads * sizeof (uint32_t)), 4242 schpc_p->schpc_slot[slot]. 4243 saved_regs[save_entry]); 4244 #endif 4245 4246 break; 4247 case 2: 4248 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4249 ddi_get16( 4250 schpc_p->schpc_slot[slot].saved_handle[reg], 4251 (uint16_t *)(schpc_p->schpc_slot[slot]. 4252 saved_regs_va[reg] 4253 + save_reg_list[list_entry].offset + 4254 (reads * sizeof (uint16_t)))); 4255 4256 #ifdef DEBUG 4257 if (schpc_dump_save_regs) 4258 cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg, 4259 save_reg_list[list_entry].offset + 4260 (reads * sizeof (uint16_t)), 4261 schpc_p->schpc_slot[slot]. 4262 saved_regs[save_entry]); 4263 #endif 4264 4265 break; 4266 case 1: 4267 schpc_p->schpc_slot[slot].saved_regs[save_entry] = 4268 ddi_get8( 4269 schpc_p->schpc_slot[slot].saved_handle[reg], 4270 (uint8_t *)(schpc_p->schpc_slot[slot]. 4271 saved_regs_va[reg] 4272 + save_reg_list[list_entry].offset + 4273 (reads * sizeof (uint8_t)))); 4274 4275 #ifdef DEBUG 4276 if (schpc_dump_save_regs) 4277 cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg, 4278 save_reg_list[list_entry].offset + 4279 (reads * sizeof (uint8_t)), 4280 schpc_p->schpc_slot[slot]. 4281 saved_regs[save_entry]); 4282 #endif 4283 4284 break; 4285 default: 4286 cmn_err(CE_WARN, 4287 "schpc: Illegal List Entry\n"); 4288 } 4289 reads++; 4290 save_entry++; 4291 } 4292 } 4293 4294 static void 4295 schpc_restore_entry(int slot, int list_entry, int save_entry) 4296 { 4297 int reg, writes = 0; 4298 4299 reg = save_reg_list[list_entry].reg; 4300 4301 while (writes < save_reg_list[list_entry].number) { 4302 switch (save_reg_list[list_entry].access_size) { 4303 case 8: 4304 #ifdef DEBUG 4305 if (schpc_dump_save_regs) 4306 cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg, 4307 save_reg_list[list_entry].offset + 4308 (writes * sizeof (uint64_t)), 4309 schpc_p->schpc_slot[slot]. 4310 saved_regs[save_entry]); 4311 #endif 4312 4313 ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg], 4314 (uint64_t *)(schpc_p->schpc_slot[slot]. 4315 saved_regs_va[reg] 4316 + save_reg_list[list_entry].offset + 4317 (writes * sizeof (uint64_t))), 4318 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4319 4320 break; 4321 case 4: 4322 #ifdef DEBUG 4323 if (schpc_dump_save_regs) 4324 cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg, 4325 save_reg_list[list_entry].offset + 4326 (writes * sizeof (uint32_t)), 4327 schpc_p->schpc_slot[slot]. 4328 saved_regs[save_entry]); 4329 #endif 4330 4331 ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg], 4332 (uint32_t *)(schpc_p->schpc_slot[slot]. 4333 saved_regs_va[reg] 4334 + save_reg_list[list_entry].offset + 4335 (writes * sizeof (uint32_t))), 4336 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4337 4338 break; 4339 case 2: 4340 #ifdef DEBUG 4341 if (schpc_dump_save_regs) 4342 cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg, 4343 save_reg_list[list_entry].offset + 4344 (writes * sizeof (uint16_t)), 4345 schpc_p->schpc_slot[slot]. 4346 saved_regs[save_entry]); 4347 #endif 4348 4349 ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg], 4350 (uint16_t *)(schpc_p->schpc_slot[slot]. 4351 saved_regs_va[reg] 4352 + save_reg_list[list_entry].offset + 4353 (writes * sizeof (uint16_t))), 4354 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4355 4356 break; 4357 case 1: 4358 #ifdef DEBUG 4359 if (schpc_dump_save_regs) 4360 cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg, 4361 save_reg_list[list_entry].offset + 4362 (writes * sizeof (uint8_t)), 4363 schpc_p->schpc_slot[slot]. 4364 saved_regs[save_entry]); 4365 #endif 4366 4367 ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg], 4368 (uint8_t *)(schpc_p->schpc_slot[slot]. 4369 saved_regs_va[reg] 4370 + save_reg_list[list_entry].offset + 4371 (writes * sizeof (uint8_t))), 4372 schpc_p->schpc_slot[slot].saved_regs[save_entry]); 4373 4374 break; 4375 default: 4376 cmn_err(CE_WARN, 4377 "schpc: Illegal List Entry\n"); 4378 } 4379 writes++; 4380 save_entry++; 4381 } 4382 } 4383 4384 /* 4385 * Returns TRUE if a leaf reset is required to change frequencies/mode. 4386 */ 4387 static int 4388 schpc_is_leaf_reset_required(int slot) 4389 { 4390 char *name; 4391 int32_t mod_rev; 4392 4393 /* 4394 * Only XMITS 3.0 and greater connected slots will require a 4395 * reset to switch frequency and/or mode. 4396 */ 4397 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi); 4398 4399 if (strcmp(name, "pci108e,8002") == 0) { 4400 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY, 4401 schpc_p->schpc_slot[slot].devi, 4402 DDI_PROP_DONTPASS, "module-revision#", 0); 4403 4404 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev); 4405 4406 /* 4407 * Check for XMITS 3.0 or greater. 4408 */ 4409 if (mod_rev >= XMITS_30) { 4410 4411 /* 4412 * The leaf attached to C5V0 (slot 1) should 4413 * not be reset. 4414 */ 4415 if ((slot & 3) == 1) { 4416 4417 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset " 4418 "Not Required - C5V0", slot); 4419 4420 return (0); 4421 } 4422 4423 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset " 4424 "Required", slot); 4425 4426 return (1); 4427 } 4428 } 4429 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot); 4430 4431 return (0); 4432 } 4433 4434 /* 4435 * Returns TRUE if the bus can change frequencies. 4436 */ 4437 static int 4438 schpc_is_freq_switchable(int slot) 4439 { 4440 char *name; 4441 int32_t mod_rev; 4442 4443 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi); 4444 4445 if (strcmp(name, "pci108e,8002") == 0) { 4446 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY, 4447 schpc_p->schpc_slot[slot].devi, 4448 DDI_PROP_DONTPASS, "module-revision#", 0); 4449 4450 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev); 4451 4452 /* 4453 * We will only report back that XMITS 2.0 (mod_rev = 2) 4454 * or greater will have the ability to switch frequencies. 4455 */ 4456 if (mod_rev >= XMITS_20) { 4457 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - " 4458 "Frequency is switchable", slot); 4459 return (1); 4460 } 4461 } 4462 4463 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot); 4464 return (0); 4465 } 4466 4467 /* 4468 * schpc_slot_freq 4469 * 4470 * Convert the slot frequency setting to integer value. 4471 */ 4472 static int 4473 schpc_slot_freq(pci_getslot_t *getslotp) 4474 { 4475 switch (getslotp->slot_freq_setting) { 4476 case PCIMSG_FREQ_33MHZ: 4477 return (SCHPC_33MHZ); 4478 case PCIMSG_FREQ_66MHZ: 4479 return (SCHPC_66MHZ); 4480 case PCIMSG_FREQ_90MHZ: 4481 return (SCHPC_90MHZ); 4482 case PCIMSG_FREQ_133MHZ: 4483 return (SCHPC_133MHZ); 4484 default: 4485 return (0); 4486 } 4487 } 4488 4489 /* 4490 * schpc_find_dip 4491 * 4492 * Used by ddi_walk_devs to find the dip which belongs 4493 * to a certain slot. 4494 * 4495 * When this function returns, the dip is held. It is the 4496 * responsibility of the caller to release the dip. 4497 */ 4498 static int 4499 schpc_find_dip(dev_info_t *dip, void *arg) 4500 { 4501 find_dev_t *find_dev = (find_dev_t *)arg; 4502 char *pathname = find_dev->caddr; 4503 4504 (void) ddi_pathname(dip, pathname); 4505 if (strcmp(find_dev->cname, pathname) == 0) { 4506 ndi_hold_devi(dip); 4507 find_dev->dip = dip; 4508 return (DDI_WALK_TERMINATE); 4509 } 4510 return (DDI_WALK_CONTINUE); 4511 } 4512