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