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