1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * MonteCarlo HotSwap Controller functionality 29 */ 30 31 #include <sys/types.h> 32 #include <sys/stropts.h> 33 #include <sys/stream.h> 34 #include <sys/strsun.h> 35 #include <sys/kmem.h> 36 #include <sys/cmn_err.h> 37 #include <sys/errno.h> 38 #include <sys/cpuvar.h> 39 #include <sys/open.h> 40 #include <sys/stat.h> 41 #include <sys/conf.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/modctl.h> 45 #include <sys/promif.h> 46 #include <sys/hotplug/hpcsvc.h> 47 48 #include <sys/hscimpl.h> 49 #include <sys/hsc.h> 50 51 #include <sys/mct_topology.h> 52 #include <sys/scsbioctl.h> 53 #include <sys/scsb.h> 54 55 #define HOTSWAP_MODE_PROP "hotswap-mode" 56 #define ALARM_CARD_ON_SLOT 1 57 #define SCSB_HSC_FORCE_REMOVE 1 /* force remove enum intr handler */ 58 59 /* TUNABLE PARAMETERS. Some are Debug Only. Please take care when using. */ 60 61 /* 62 * Set this flag to 1, to enable full hotswap mode at boot time. 63 * Since HPS is threaded, it is not recommended that we set this flag 64 * to 1 because enabling full hotswap interrupt can invoke the ENUM 65 * event handler accessing the slot data structure which may have not 66 * been initialized in the hotplug framework since the HPS may not yet 67 * have called the slot registration function with the bus nexus. 68 */ 69 static int scsb_hsc_enable_fhs = 0; 70 71 /* 72 * Every time a slot is registered with the hotswap framework, the 73 * framework calls back. This variable keeps a count on how many 74 * callbacks are done. 75 */ 76 static int scsb_hsc_numReg = 0; 77 /* 78 * When this flag is set, the board is taken offline (put in reset) after 79 * a unconfigure operation, in Basic Hotswap mode. 80 */ 81 static int scsb_hsc_bhs_slot_reset = 1; 82 /* 83 * When this flag is set, we take the board to reset after unconfigure 84 * operation when operating in full hotswap mode. 85 */ 86 static int scsb_hsc_fhs_slot_reset = 1; 87 /* 88 * Implementation of this counter will work only on Montecarlo since 89 * the ENUM# Interrupt line is not shared with other interrupts. 90 * When the hardware routing changes, then there may be need to remove 91 * or change this functionality. 92 * This functionality is provided so that a bad or non friendly full hotswap 93 * board does not hang the system in full hotswap mode. Atleast the 94 * intent is that! Eventually Solaris kernel will provide similar support 95 * for recovering from a stuck interrupt line. Till then, lets do this. 96 */ 97 static int scsb_hsc_max_intr_count = 8; 98 /* 99 * Since the hardware does not support enabling/disabling ENUM#, the 100 * following flag can be used for imitating that behaviour. 101 * Currently we can set this flag and use the remove op to remove the 102 * interrupt handler from the system. Care must be taken when using this 103 * function since trying to remove the interrupt handler when the interrupts 104 * are pending may hang the system permanently. 105 * Since the hardware does not support this functionality, we adopt this 106 * approach for debugs. 107 */ 108 static int scsb_hsc_enum_switch = 0; 109 110 /* 111 * When the board loses Healthy# at runtime (with the board being configured), 112 * cPCI specs states that a Reset has to be asserted immediately. 113 * We dont do this currently, until satellite processor support is given 114 * and the implications of such a act is fully understood. 115 * To adopt the cPCI specs recommendation, set this flag to 1. 116 */ 117 static int scsb_hsc_healthy_reset = 0; 118 119 /* 120 * According to PCI 2.2 specification, once a board comes out of PCI_RST#, 121 * it may take upto 2^25 clock cycles to respond to config cycles. For 122 * montecarlo using a 33MHz cPCI bus, it's around 1.024 s. The variable 123 * will specify the time in ms to wait before attempting config access. 124 */ 125 static int scsb_connect_delay = 1025; 126 127 /* 128 * slot map property for MC should be 129 * 130 * hsc-slot-map="/pci@1f,0/pci@1/pci@1","15","2", 131 * "/pci@1f,0/pci@1/pci@1","14","3", 132 * "/pci@1f,0/pci@1/pci@1","13","4", 133 * "/pci@1f,0/pci@1/pci@1","12","5" 134 * "/pci@1f,0/pci@1/pci@1","11","6" 135 * "/pci@1f,0/pci@1/pci@1","10","7" 136 * "/pci@1f,0/pci@1/pci@1","8","8"; 137 * 138 * slot map property for Tonga should be 139 * hsc-slot-map="/pci@1f,0/pci@1/pci@1","8","1" 140 * "/pci@1f,0/pci@1/pci@1", "15", "2" 141 * "/pci@1f,0/pci@1/pci@1", "14", "4" 142 * "/pci@1f,0/pci@1/pci@1", "13", "5" 143 * 144 * Please note that the CPU slot number is 3 for Tonga. 145 */ 146 147 /* 148 * Services we require from the SCSB 149 */ 150 extern int scsb_get_slot_state(void *, int, int *); 151 extern int scsb_read_bhealthy(scsb_state_t *scsb); 152 extern int scsb_read_slot_health(scsb_state_t *scsb, int pslotnum); 153 extern int scsb_connect_slot(void *, int, int); 154 extern int scsb_disconnect_slot(void *, int, int); 155 156 static void *hsc_state; 157 158 static uint_t hsc_enum_intr(char *); 159 static hsc_slot_t *hsc_get_slot_info(hsc_state_t *, int); 160 static int scsb_enable_enum(hsc_state_t *); 161 static int scsb_disable_enum(hsc_state_t *, int); 162 static int atoi(const char *); 163 static int isdigit(int); 164 static hsc_slot_t *hsc_find_slot(int); 165 static void hsc_led_op(hsc_slot_t *, int, hpc_led_t, hpc_led_state_t); 166 static int hsc_led_state(hsc_slot_t *, int, hpc_led_info_t *); 167 static int scsb_hsc_disable_slot(hsc_slot_t *); 168 static int scsb_hsc_enable_slot(hsc_slot_t *); 169 #ifndef lint 170 static int hsc_clear_all_enum(hsc_state_t *); 171 #endif 172 static int hsc_slot_register(hsc_state_t *, char *, uint16_t, uint_t, 173 boolean_t); 174 static int hsc_slot_unregister(int); 175 static int scsb_hsc_init_slot_state(hsc_state_t *, hsc_slot_t *); 176 static int hsc_slot_autoconnect(hsc_slot_t *); 177 178 static hpc_slot_ops_t *hsc_slotops; 179 static hsc_slot_t *hsc_slot_list; /* linked list of slots */ 180 181 /* 182 * This mutex protects the following variables: 183 * hsc_slot_list 184 */ 185 static kmutex_t hsc_mutex; 186 187 188 /* ARGSUSED */ 189 static int 190 hsc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 191 { 192 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 193 int rc, rstate; 194 hsc_state_t *hsc; 195 196 DEBUG2("hsc_connect: slot %d, healthy %d", hsp->hs_slot_number, 197 hsp->hs_board_healthy); 198 199 if (!(hsp->hs_flags & (HSC_ENABLED|HSC_SLOT_ENABLED))) 200 return (HPC_ERR_FAILED); 201 /* if SCB hotswapped, do not allow connect operations */ 202 if (hsp->hs_flags & HSC_SCB_HOTSWAPPED) 203 return (HPC_ERR_FAILED); 204 /* 205 * if previous occupant stayed configured, do not allow another 206 * occupant to be connected. 207 * This behaviour is an indication that the slot state 208 * is not clean. 209 */ 210 if (hsp->hs_flags & HSC_SLOT_BAD_STATE) { 211 /* 212 * In the current implementation, we turn both fault 213 * and active LEDs to ON state in this situation. 214 */ 215 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 216 HPC_LED_ON); 217 return (HPC_ERR_FAILED); 218 } 219 /* 220 * Get the actual status from the i2c bus 221 */ 222 rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number, 223 &rstate); 224 if (rc != DDI_SUCCESS) 225 return (HPC_ERR_FAILED); 226 227 hsp->hs_slot_state = rstate; 228 if (hsp->hs_slot_state == HPC_SLOT_EMPTY) { 229 #ifdef DEBUG 230 cmn_err(CE_CONT, 231 "?hsc_connect: slot %d is empty\n", 232 hsp->hs_slot_number); 233 #endif 234 return (HPC_ERR_FAILED); 235 } 236 237 if (hsp->hs_slot_state == HPC_SLOT_CONNECTED) 238 return (HPC_SUCCESS); 239 240 rc = HPC_SUCCESS; 241 /* 242 * call scsb to connect the slot. This also makes sure board is healthy 243 */ 244 if (scsb_connect_slot(hsp->hs_hpchandle, hsp->hs_slot_number, 245 hsp->hs_board_healthy) != DDI_SUCCESS) { 246 DEBUG1("hsc_connect: slot %d connection failed", 247 hsp->hs_slot_number); 248 rc = HPC_ERR_FAILED; 249 } else { 250 if (hsp->hs_slot_state != HPC_SLOT_CONNECTED) { 251 if (hsp->hs_board_healthy == B_FALSE) { 252 cmn_err(CE_NOTE, "HEALTHY# not asserted on " 253 " slot %d", hsp->hs_slot_number); 254 return (HPC_ERR_FAILED); 255 } 256 hsc = hsp->hsc; 257 hsc->hsp_last = hsp; 258 if (scsb_reset_slot(hsp->hs_hpchandle, 259 hsp->hs_slot_number, SCSB_UNRESET_SLOT) != 0) { 260 261 return (HPC_ERR_FAILED); 262 } 263 /* 264 * Unresetting a board may have caused an interrupt 265 * burst in case of non friendly boards. So it is 266 * important to make sure that the ISR has not 267 * put this board back to disconnect state. 268 */ 269 delay(1); 270 if (hsp->hs_flags & HSC_ENUM_FAILED) { 271 hsp->hs_flags &= ~HSC_ENUM_FAILED; 272 return (HPC_ERR_FAILED); 273 } 274 DEBUG1("hsc_connect: slot %d connected", 275 hsp->hs_slot_number); 276 rc = HPC_SUCCESS; 277 hsp->hs_slot_state = HPC_SLOT_CONNECTED; 278 (void) hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 279 HPC_FAULT_LED, HPC_LED_OFF); 280 } 281 } 282 283 /* 284 * PCI 2.2 specs recommend that the probe software wait 285 * for upto 2^25 PCI clock cycles after deassertion of 286 * PCI_RST# before the board is able to respond to config 287 * cycles. So, before we return, we wait for ~1 sec. 288 */ 289 delay(drv_usectohz(scsb_connect_delay * 1000)); 290 return (rc); 291 } 292 293 294 /* ARGSUSED */ 295 static int 296 hsc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 297 { 298 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 299 hsc_state_t *hsc; 300 #ifdef DEBUG 301 static const char func[] = "hsc_disconnect"; 302 #endif 303 304 DEBUG1("hsc_disconnect: slot %d", hsp->hs_slot_number); 305 306 if (hsp->hs_board_configured) { 307 #ifdef DEBUG 308 cmn_err(CE_NOTE, 309 "%s: cannot disconnect configured board in slot %d", 310 func, hsp->hs_slot_number); 311 #endif 312 return (HPC_ERR_FAILED); 313 } 314 315 if (hsp->hs_slot_state == HPC_SLOT_EMPTY) { 316 #ifdef DEBUG 317 cmn_err(CE_NOTE, "%s: slot %d is empty", 318 func, hsp->hs_slot_number); 319 #endif 320 return (HPC_SUCCESS); 321 } 322 323 if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) { 324 /* 325 * if already disconnected, just return success 326 * Duplicate disconnect messages should not be failed! 327 */ 328 return (HPC_SUCCESS); 329 } 330 /* if SCB hotswapped, do not allow disconnect operations */ 331 if (hsp->hs_flags & HSC_SCB_HOTSWAPPED) 332 return (HPC_ERR_FAILED); 333 334 /* call scsb to disconnect the slot */ 335 if (scsb_disconnect_slot(hsp->hs_hpchandle, B_TRUE, hsp->hs_slot_number) 336 != DDI_SUCCESS) 337 return (HPC_ERR_FAILED); 338 hsc = hsp->hsc; 339 if (hsc->hsp_last == hsp) 340 hsc->hsp_last = NULL; 341 342 return (HPC_SUCCESS); 343 } 344 345 346 /* 347 * In the cPCI world, this operation is not applicable. 348 * However, we use this function to enable full hotswap mode in debug mode. 349 */ 350 /* ARGSUSED */ 351 static int 352 hsc_insert(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 353 { 354 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 355 356 if (scsb_hsc_enum_switch && 357 (scsb_enable_enum(hsp->hsc) == DDI_SUCCESS)) { 358 return (HPC_SUCCESS); 359 } 360 return (HPC_ERR_NOTSUPPORTED); 361 } 362 363 364 /* 365 * In the cPCI world, this operation is not applicable. 366 * However, we use this function to disable full hotswap mode in debug mode. 367 */ 368 /* ARGSUSED */ 369 static int 370 hsc_remove(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 371 { 372 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 373 374 if (scsb_hsc_enum_switch && 375 (scsb_disable_enum(hsp->hsc, SCSB_HSC_FORCE_REMOVE) 376 == DDI_SUCCESS)) { 377 hsp->hs_flags &= ~HSC_ENUM_FAILED; 378 return (HPC_SUCCESS); 379 } 380 return (HPC_ERR_NOTSUPPORTED); 381 } 382 383 static void 384 hsc_led_op(hsc_slot_t *hsp, int cmd, hpc_led_t led, hpc_led_state_t led_state) 385 { 386 hpc_led_info_t ledinfo; 387 388 ledinfo.led = led; 389 ledinfo.state = led_state; 390 (void) hsc_led_state(hsp, cmd, &ledinfo); 391 } 392 393 static int 394 hsc_led_state(hsc_slot_t *hsp, int cmd, hpc_led_info_t *hlip) 395 { 396 hpc_led_state_t *hlsp; 397 scsb_uinfo_t sunit; 398 int res; 399 400 DEBUG3("hsc_led_state: slot %d, led %x, state %x", 401 hsp->hs_slot_number, hlip->led, hlip->state); 402 403 sunit.unit_type = SLOT; 404 sunit.unit_number = hsp->hs_slot_number; 405 /* 406 * We ignore operations on LEDs that we don't support 407 */ 408 switch (hlip->led) { 409 case HPC_FAULT_LED: 410 sunit.led_type = NOK; 411 hlsp = &hsp->hs_fault_led_state; 412 break; 413 case HPC_ACTIVE_LED: 414 sunit.led_type = OK; 415 hlsp = &hsp->hs_active_led_state; 416 break; 417 default: 418 return (HPC_ERR_NOTSUPPORTED); 419 } 420 421 switch (hlip->state) { 422 case HPC_LED_BLINK: 423 sunit.unit_state = BLINK; 424 if (hlip->led != HPC_ACTIVE_LED) 425 return (HPC_ERR_NOTSUPPORTED); 426 break; 427 case HPC_LED_ON: 428 sunit.unit_state = ON; 429 break; 430 case HPC_LED_OFF: 431 sunit.unit_state = OFF; 432 break; 433 default: 434 break; 435 } 436 437 switch (cmd) { 438 case HPC_CTRL_SET_LED_STATE: 439 res = scsb_led_set(hsp->hs_hpchandle, &sunit, sunit.led_type); 440 if (res != 0) 441 return (HPC_ERR_FAILED); 442 *hlsp = (hpc_led_state_t)sunit.unit_state; 443 break; 444 445 case HPC_CTRL_GET_LED_STATE: 446 res = scsb_led_get(hsp->hs_hpchandle, &sunit, sunit.led_type); 447 if (res) 448 return (HPC_ERR_FAILED); 449 /* hlip->state = sunit.unit_state; */ 450 break; 451 452 default: 453 return (HPC_ERR_INVALID); 454 } 455 456 return (HPC_SUCCESS); 457 458 } 459 460 461 static int 462 hsc_get_slot_state(hsc_slot_t *hsp, hpc_slot_state_t *hssp) 463 { 464 int rstate = 0; 465 int rc; 466 #ifdef DEBUG 467 int orstate; /* original rstate */ 468 #endif 469 470 DEBUG1("hsc_get_slot_state: slot %d", hsp->hs_slot_number); 471 rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number, 472 &rstate); 473 if (rc != DDI_SUCCESS) 474 return (HPC_ERR_FAILED); 475 #ifdef DEBUG 476 orstate = hsp->hs_slot_state; 477 #endif 478 hsp->hs_slot_state = rstate; 479 switch (hsp->hs_slot_state) { 480 case HPC_SLOT_EMPTY: 481 DEBUG0("empty"); 482 break; 483 case HPC_SLOT_CONNECTED: 484 DEBUG0("connected"); 485 break; 486 case HPC_SLOT_DISCONNECTED: 487 DEBUG0("disconnected"); 488 break; 489 } 490 491 *hssp = hsp->hs_slot_state; 492 493 /* doing get-state above may have caused a freeze operation */ 494 if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) && 495 (rstate == HPC_SLOT_DISCONNECTED)) { 496 /* freeze puts disconnected boards to connected state */ 497 *hssp = HPC_SLOT_CONNECTED; 498 #if 0 499 /* in FHS, deassertion of reset may have configured the board */ 500 if (hsp->hs_board_configured == B_TRUE) { 501 hsp->hs_slot_state = *hssp; 502 } 503 #endif 504 } 505 #ifdef DEBUG 506 /* a SCB hotswap may have forced a state change on the receptacle */ 507 if (orstate != *hssp) { 508 cmn_err(CE_NOTE, "hsc_get_state: slot%d state change due" 509 " to SCB hotswap!", hsp->hs_slot_number); 510 } 511 #endif 512 return (HPC_SUCCESS); 513 } 514 515 516 static int 517 hsc_set_config_state(hsc_slot_t *hsp, int cmd) 518 { 519 hsc_state_t *hsc = hsp->hsc; 520 521 DEBUG1("hsc_set_config_state: slot %d", hsp->hs_slot_number); 522 523 switch (cmd) { 524 case HPC_CTRL_DEV_CONFIGURED: 525 /* 526 * Closing of the Ejector switch in configured/busy state can 527 * cause duplicate CONFIGURED messages to come down. 528 * Make sure our LED states are fine. 529 */ 530 if (hsp->hs_board_configured == B_TRUE) { 531 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 532 HPC_LED_ON); 533 break; 534 } 535 hsp->hs_board_configured = B_TRUE; 536 hsp->hs_board_configuring = B_FALSE; 537 if ((hsc->state & HSC_ATTACHED) == HSC_ATTACHED && 538 hsp->hs_flags & HSC_ALARM_CARD_PRES) 539 (void) scsb_hsc_ac_op(hsp->hs_hpchandle, 540 hsp->hs_slot_number, SCSB_HSC_AC_CONFIGURED); 541 /* LED must be OFF on the occupant. */ 542 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 543 HPC_EVENT_SLOT_BLUE_LED_OFF, 0); 544 if (hsp->hs_flags & HSC_AUTOCFG) 545 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 546 HPC_EVENT_ENABLE_ENUM, 0); 547 else 548 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 549 HPC_EVENT_DISABLE_ENUM, 0); 550 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 551 HPC_LED_ON); 552 if (hsc->hsp_last == hsp) 553 hsc->hsp_last = NULL; 554 break; 555 case HPC_CTRL_DEV_UNCONFIGURED: 556 hsp->hs_board_configured = B_FALSE; 557 hsp->hs_board_unconfiguring = B_FALSE; 558 hsp->hs_flags &= ~HSC_SLOT_BAD_STATE; 559 if (hsp->hs_flags & HSC_ALARM_CARD_PRES) 560 (void) scsb_hsc_ac_op(hsp->hs_hpchandle, 561 hsp->hs_slot_number, SCSB_HSC_AC_UNCONFIGURED); 562 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 563 HPC_LED_BLINK); 564 if (((hsc->state & HSC_ENUM_ENABLED) && 565 scsb_hsc_fhs_slot_reset) || 566 (((hsc->state & HSC_ENUM_ENABLED) != HSC_ENUM_ENABLED) && 567 scsb_hsc_bhs_slot_reset) || 568 ((hsp->hs_flags & HSC_AUTOCFG) != 569 HSC_AUTOCFG)) { 570 if (scsb_reset_slot(hsp->hs_hpchandle, 571 hsp->hs_slot_number, SCSB_RESET_SLOT) == 0) { 572 573 hsp->hs_slot_state = HPC_SLOT_DISCONNECTED; 574 hsp->hs_board_healthy = B_FALSE; 575 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 576 HPC_FAULT_LED, HPC_LED_ON); 577 } 578 } 579 break; 580 case HPC_CTRL_DEV_CONFIG_FAILURE: 581 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 582 HPC_LED_BLINK); 583 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 584 HPC_FAULT_LED, HPC_LED_ON); 585 break; 586 case HPC_CTRL_DEV_UNCONFIG_FAILURE: 587 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 588 HPC_LED_ON); 589 break; 590 case HPC_CTRL_DEV_CONFIG_START: 591 case HPC_CTRL_DEV_UNCONFIG_START: 592 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 593 HPC_LED_OFF); 594 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 595 HPC_LED_BLINK); 596 break; 597 default: 598 return (HPC_ERR_INVALID); 599 } 600 601 if (cmd != HPC_CTRL_DEV_CONFIG_START && 602 cmd != HPC_CTRL_DEV_UNCONFIG_START && 603 hsc->regDone == B_FALSE && 604 scsb_hsc_numReg < hsc->n_registered_occupants) { 605 scsb_hsc_numReg++; 606 607 /* 608 * If the callback is invoked for all registered slots, 609 * enable ENUM. 610 */ 611 if (((hsc->state & HSC_ATTACHED) == HSC_ATTACHED) && 612 (scsb_hsc_numReg == hsc->n_registered_occupants)) { 613 hsc->regDone = B_TRUE; 614 if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) { 615 #ifdef DEBUG 616 cmn_err(CE_CONT, "%s%d: Enabling full hotswap" 617 ":%d non-empty slots\n", 618 ddi_driver_name(hsc->dip), 619 ddi_get_instance(hsc->dip), 620 hsc->n_registered_occupants); 621 #endif 622 if (scsb_enable_enum(hsc) != DDI_SUCCESS) { 623 cmn_err(CE_WARN, "%s#%d: Cannot enable " 624 "Full Hotswap", 625 ddi_driver_name(hsc->dip), 626 ddi_get_instance(hsc->dip)); 627 628 return (HPC_ERR_FAILED); 629 } 630 } 631 } 632 } 633 634 return (HPC_SUCCESS); 635 } 636 637 638 /*ARGSUSED*/ 639 static int 640 hsc_get_board_type(hsc_slot_t *hsp, hpc_board_type_t *hbtp) 641 { 642 *hbtp = hsp->hs_board_type; 643 return (HPC_SUCCESS); 644 } 645 646 647 /* ARGSUSED */ 648 static int 649 hsc_autoconfig(hsc_slot_t *hsp, int cmd) 650 { 651 int res = HPC_SUCCESS, enum_disable = B_TRUE, i; 652 char slotautocfg_prop[18]; 653 hsc_state_t *hsc; 654 655 DEBUG1("hsc_autoconfig: slot %d", hsp->hs_slot_number); 656 (void) sprintf(slotautocfg_prop, "slot%d-autoconfig", 657 hsp->hs_slot_number); 658 659 if (cmd == HPC_CTRL_ENABLE_AUTOCFG) { 660 hsp->hs_flags |= HSC_AUTOCFG; 661 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip, 662 slotautocfg_prop, "enabled"); 663 if ((res = scsb_enable_enum(hsp->hsc)) == DDI_SUCCESS) { 664 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 665 HPC_EVENT_ENABLE_ENUM, 0); 666 } 667 } else { 668 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip, 669 slotautocfg_prop, "disabled"); 670 hsp->hs_flags &= ~HSC_AUTOCFG; 671 hsc = hsp->hsc; 672 if (hsc->state & HSC_ATTACHED) { 673 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 674 HPC_EVENT_DISABLE_ENUM, 0); 675 for (i = 0; i < hsc->slot_table_size; i++) { 676 hsc_slot_t *thsp; 677 int slotnum; 678 679 slotnum = hsc->slot_table_prop[i].pslotnum; 680 thsp = hsc_find_slot(slotnum); 681 if (thsp == NULL) { 682 cmn_err(CE_WARN, "%s#%d: hsc_autocfg:" 683 "No Slot Info for slot %d", 684 ddi_driver_name(hsc->dip), 685 ddi_get_instance(hsc->dip), 686 slotnum); 687 continue; 688 } 689 if (thsp->hs_flags & HSC_AUTOCFG) { 690 enum_disable = B_FALSE; 691 break; 692 } 693 } 694 if (enum_disable == B_TRUE) 695 (void) scsb_disable_enum(hsc, 696 SCSB_HSC_FORCE_REMOVE); 697 } 698 } 699 return (res); 700 } 701 702 703 /* 704 * This function is invoked to enable/disable a slot 705 */ 706 /* ARGSUSED */ 707 #ifndef lint 708 static int 709 hsc_slot_enable(hsc_slot_t *hsp, boolean_t enabled) 710 { 711 scsb_uinfo_t sunit; 712 int res; 713 714 DEBUG1("hsc_slot_enable: slot %d", hsp->hs_slot_number); 715 716 sunit.unit_type = SLOT; 717 sunit.unit_number = hsp->hs_slot_number; 718 if (enabled) 719 sunit.unit_state = ON; 720 else 721 sunit.unit_state = OFF; 722 723 res = scsb_reset_unit(hsp->hs_hpchandle, &sunit); 724 if (res == 0) 725 return (HPC_SUCCESS); 726 else if (res == EINVAL) 727 return (HPC_ERR_INVALID); 728 else 729 return (HPC_ERR_FAILED); 730 } 731 #endif 732 733 734 /*ARGSUSED*/ 735 static int 736 hsc_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, caddr_t arg) 737 { 738 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 739 int rc = HPC_SUCCESS; 740 741 DEBUG2("hsc_control: slot %d, op=%x\n", hsp->hs_slot_number, request); 742 743 switch (request) { 744 case HPC_CTRL_GET_LED_STATE: 745 return (hsc_led_state(hsp, 746 HPC_CTRL_GET_LED_STATE, (hpc_led_info_t *)arg)); 747 748 case HPC_CTRL_SET_LED_STATE: 749 return (hsc_led_state(hsp, 750 HPC_CTRL_SET_LED_STATE, (hpc_led_info_t *)arg)); 751 752 case HPC_CTRL_GET_SLOT_STATE: 753 return (hsc_get_slot_state(hsp, (hpc_slot_state_t *)arg)); 754 755 case HPC_CTRL_DEV_CONFIGURED: 756 return (hsc_set_config_state(hsp, HPC_CTRL_DEV_CONFIGURED)); 757 758 case HPC_CTRL_DEV_UNCONFIGURED: 759 return (hsc_set_config_state(hsp, HPC_CTRL_DEV_UNCONFIGURED)); 760 761 case HPC_CTRL_DEV_CONFIG_FAILURE: 762 return (hsc_set_config_state(hsp, HPC_CTRL_DEV_CONFIG_FAILURE)); 763 764 case HPC_CTRL_DEV_UNCONFIG_FAILURE: 765 return (hsc_set_config_state(hsp, 766 HPC_CTRL_DEV_UNCONFIG_FAILURE)); 767 768 case HPC_CTRL_DEV_CONFIG_START: 769 case HPC_CTRL_DEV_UNCONFIG_START: 770 return (hsc_set_config_state(hsp, request)); 771 772 case HPC_CTRL_GET_BOARD_TYPE: 773 return (hsc_get_board_type(hsp, (hpc_board_type_t *)arg)); 774 775 case HPC_CTRL_DISABLE_AUTOCFG: 776 return (hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG)); 777 778 case HPC_CTRL_ENABLE_AUTOCFG: 779 return (hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG)); 780 781 case HPC_CTRL_DISABLE_SLOT: 782 /* 783 * No hardware support for disabling the slot. 784 * Just imitate a disable_autoconfig operation for now 785 */ 786 if (hsp->hs_board_configured == B_TRUE) 787 return (HPC_ERR_FAILED); 788 if (scsb_hsc_disable_slot(hsp) != DDI_SUCCESS) 789 rc = HPC_ERR_FAILED; 790 return (rc); 791 792 case HPC_CTRL_ENABLE_SLOT: 793 if (scsb_hsc_enable_slot(hsp) != DDI_SUCCESS) 794 rc = HPC_ERR_FAILED; 795 return (rc); 796 797 case HPC_CTRL_ENABLE_ENUM: 798 return (scsb_enable_enum(hsp->hsc)); 799 800 case HPC_CTRL_DISABLE_ENUM: 801 return (scsb_disable_enum(hsp->hsc, 0)); 802 803 default: 804 return (HPC_ERR_INVALID); 805 } 806 } 807 808 static int 809 scsb_hsc_disable_slot(hsc_slot_t *hsp) 810 { 811 int rc; 812 char slot_disable_prop[18]; 813 814 DEBUG1("hsc_disable_slot: slot %d", hsp->hs_slot_number); 815 (void) sprintf(slot_disable_prop, "slot%d-status", hsp->hs_slot_number); 816 817 rc = scsb_reset_slot(hsp->hs_hpchandle, hsp->hs_slot_number, 818 SCSB_RESET_SLOT); 819 if (rc == DDI_SUCCESS) { 820 (void) hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG); 821 hsp->hs_flags &= ~HSC_SLOT_ENABLED; 822 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip, 823 slot_disable_prop, "disabled"); 824 } else 825 rc = DDI_FAILURE; 826 return (rc); 827 } 828 829 static int 830 scsb_hsc_enable_slot(hsc_slot_t *hsp) 831 { 832 int rc; 833 char slot_disable_prop[18]; 834 835 DEBUG1("hsc_disable_slot: slot %d", hsp->hs_slot_number); 836 (void) sprintf(slot_disable_prop, "slot%d-status", hsp->hs_slot_number); 837 838 rc = scsb_reset_slot(hsp->hs_hpchandle, hsp->hs_slot_number, 839 SCSB_UNRESET_SLOT); 840 if (rc == DDI_SUCCESS) { 841 (void) hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG); 842 hsp->hs_flags |= HSC_SLOT_ENABLED; 843 (void) ddi_prop_remove(DDI_DEV_T_NONE, hsp->hsc->dip, 844 slot_disable_prop); 845 } else 846 rc = HPC_ERR_FAILED; 847 return (rc); 848 } 849 850 #define NEW(type) (type *) kmem_zalloc(sizeof (type), KM_SLEEP) 851 852 static hsc_slot_t * 853 hsc_alloc_slot( 854 uint16_t device_number, 855 int slot_number, 856 boolean_t board_in_slot) 857 { 858 hpc_slot_info_t *hsip; 859 hsc_slot_t *hsp = NEW(hsc_slot_t); 860 861 DEBUG2("hsc_alloc_slot: slot %d %s", slot_number, 862 board_in_slot ? "occupied" : "empty"); 863 864 if (hsp == NULL) { 865 cmn_err(CE_NOTE, 866 "hsc_alloc_slot: allocation failed for slot %d", 867 slot_number); 868 return (NULL); 869 } 870 871 hsip = &hsp->hs_info; 872 873 hsip->version = HPC_SLOT_INFO_VERSION; 874 hsip->slot_type = HPC_SLOT_TYPE_CPCI; 875 hsip->pci_dev_num = device_number; 876 hsip->pci_slot_capabilities = 0; 877 hsip->slot_flags = HPC_SLOT_CREATE_DEVLINK; 878 /* 879 * Note: the name *must* be 'pci' so that the correct cfgadm plug-in 880 * library is selected 881 */ 882 (void) sprintf(hsip->pci_slot_name, "cpci_slot%d", slot_number); 883 884 /* 885 * We assume that the following LED settings reflect 886 * the hardware state. 887 * After we register the slot, we will be invoked by the nexus 888 * if the slot is occupied, and we will turn on the LED then. 889 */ 890 hsp->hs_active_led_state = HPC_LED_OFF; 891 hsp->hs_fault_led_state = HPC_LED_OFF; 892 893 hsp->hs_board_configured = B_FALSE; 894 hsp->hs_board_healthy = B_FALSE; 895 hsp->hs_board_type = HPC_BOARD_UNKNOWN; 896 897 hsp->hs_flags = HSC_ENABLED | HSC_SLOT_ENABLED; 898 hsp->hs_slot_number = slot_number; 899 900 /* 901 * we should just set this to connected, 902 * as MC slots are always connected. 903 */ 904 if (board_in_slot) 905 hsp->hs_slot_state = HPC_SLOT_CONNECTED; 906 else 907 hsp->hs_slot_state = HPC_SLOT_EMPTY; 908 909 return (hsp); 910 } 911 912 913 static void 914 hsc_free_slot(hsc_slot_t *hsp) 915 { 916 DEBUG0("hsc_free_slot"); 917 918 kmem_free(hsp, sizeof (*hsp)); 919 } 920 921 922 /* 923 * This function is invoked to register a slot 924 */ 925 static int 926 hsc_slot_register( 927 hsc_state_t *hsc, 928 char *bus_path, /* PCI nexus pathname */ 929 uint16_t device_number, /* PCI device number */ 930 uint_t slot_number, /* physical slot number */ 931 boolean_t board_in_slot) /* receptacle status */ 932 { 933 int rc = HPC_SUCCESS; 934 hsc_slot_t *hsp; 935 936 DEBUG2("hsc_slot_register: slot number %d, device number %d", 937 slot_number, device_number); 938 939 hsp = hsc_alloc_slot(device_number, slot_number, 940 board_in_slot); 941 942 if (hsp == NULL) { 943 #ifdef DEBUG 944 cmn_err(CE_NOTE, "hsc_slot_register: hsc_alloc_slot failed"); 945 #endif 946 return (HPC_ERR_FAILED); 947 } 948 949 hsp->hs_hpchandle = hsc->scsb_handle; /* handle for call backs */ 950 hsp->hsc = hsc; 951 952 rc = scsb_hsc_init_slot_state(hsc, hsp); 953 if (rc != DDI_SUCCESS) 954 return (HPC_ERR_FAILED); 955 956 /* slot autoconfiguration by default. */ 957 if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) 958 (void) hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG); 959 else 960 (void) hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG); 961 962 /* 963 * Append to our list 964 */ 965 mutex_enter(&hsc_mutex); 966 hsp->hs_next = hsc_slot_list; 967 hsc_slot_list = hsp; 968 mutex_exit(&hsc_mutex); 969 970 rc = hpc_slot_register(hsc->dip, 971 bus_path, 972 &hsp->hs_info, 973 &hsp->hs_slot_handle, /* return value */ 974 hsc_slotops, 975 (caddr_t)hsp, 976 0); 977 978 if (rc != HPC_SUCCESS) { 979 cmn_err(CE_WARN, "%s#%d: failed to register slot %s:%d", 980 ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip), 981 bus_path, device_number); 982 hsc_free_slot(hsp); 983 return (rc); 984 } 985 986 DEBUG0("hsc_slot_register: hpc_slot_register successful"); 987 988 return (rc); 989 } 990 991 992 static int 993 hsc_slot_unregister(int slot_number) 994 { 995 hsc_slot_t *hsp, *prev; 996 997 DEBUG1("hsc_slot_unregister: slot number %d", slot_number); 998 999 mutex_enter(&hsc_mutex); 1000 hsp = prev = NULL; 1001 for (hsp = hsc_slot_list; hsp != NULL; hsp = hsp->hs_next) { 1002 if (hsp->hs_slot_number == slot_number) { 1003 if (prev == NULL) /* first entry */ 1004 hsc_slot_list = hsc_slot_list->hs_next; 1005 else 1006 prev->hs_next = hsp->hs_next; 1007 hsp->hs_next = NULL; 1008 break; 1009 } 1010 prev = hsp; 1011 } 1012 mutex_exit(&hsc_mutex); 1013 1014 if (hsp != NULL) { 1015 (void) hpc_slot_unregister(&hsp->hs_slot_handle); 1016 if ((hsp->hsc->state & HSC_ATTACHED) != HSC_ATTACHED && 1017 hsp->hs_slot_state != HPC_SLOT_EMPTY) { 1018 hsp->hsc->n_registered_occupants--; 1019 } 1020 hsc_free_slot(hsp); 1021 return (0); 1022 } 1023 return (1); 1024 } 1025 1026 static int 1027 scsb_hsc_init_slot_state(hsc_state_t *hsc, hsc_slot_t *hsp) 1028 { 1029 int rc, rstate; 1030 int slot_number = hsp->hs_slot_number; 1031 scsb_state_t *scsb = (scsb_state_t *)hsc->scsb_handle; 1032 1033 rc = scsb_get_slot_state(hsc->scsb_handle, slot_number, &rstate); 1034 if (rc != DDI_SUCCESS) 1035 return (DDI_FAILURE); 1036 1037 /* 1038 * Set the healthy status for this slot 1039 */ 1040 hsp->hs_board_healthy = scsb_read_slot_health(scsb, slot_number); 1041 hsp->hs_slot_state = rstate; 1042 switch (rstate) { 1043 case HPC_SLOT_EMPTY: 1044 /* 1045 * this will clear any state differences between 1046 * SCB Freeze operations. 1047 */ 1048 hsp->hs_slot_state = HPC_SLOT_EMPTY; 1049 /* slot empty. */ 1050 (void) scsb_reset_slot(hsc->scsb_handle, slot_number, 1051 SCSB_RESET_SLOT); 1052 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 1053 HPC_LED_OFF); 1054 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 1055 HPC_LED_OFF); 1056 break; 1057 case HPC_SLOT_DISCONNECTED: 1058 /* 1059 * this will clear any state differences between 1060 * SCB Freeze operations. 1061 */ 1062 hsp->hs_slot_state = HPC_SLOT_DISCONNECTED; 1063 /* check recovery from SCB freeze */ 1064 if (hsp->hs_board_configured != B_TRUE) { 1065 /* 1066 * Force a disconnect just in case there are 1067 * differences between healthy and reset states. 1068 */ 1069 (void) scsb_reset_slot(hsc->scsb_handle, 1070 slot_number, SCSB_RESET_SLOT); 1071 /* 1072 * Slot in reset. OBP has not probed this 1073 * device. Hence it is ok to remove this board. 1074 */ 1075 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 1076 HPC_ACTIVE_LED, HPC_LED_BLINK); 1077 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 1078 HPC_FAULT_LED, HPC_LED_ON); 1079 break; 1080 } 1081 /*FALLTHROUGH*/ 1082 case HPC_SLOT_CONNECTED: 1083 /* 1084 * this will clear any state differences between 1085 * SCB Freeze operations. 1086 */ 1087 hsp->hs_slot_state = HPC_SLOT_CONNECTED; 1088 /* 1089 * OBP should have probed this device, unless 1090 * it was plugged in during the boot operation 1091 * before the driver was loaded. In any case, 1092 * no assumption is made and hence we take 1093 * the conservative approach by keeping fault 1094 * led off so board removal is not allowed. 1095 */ 1096 if (hsp->hs_board_configured == B_TRUE) 1097 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 1098 HPC_ACTIVE_LED, HPC_LED_ON); 1099 else 1100 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 1101 HPC_ACTIVE_LED, HPC_LED_BLINK); 1102 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 1103 HPC_LED_OFF); 1104 /* 1105 * Netra ct alarm card hotswap support 1106 */ 1107 if (slot_number == scsb->ac_slotnum && 1108 scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES) { 1109 hsp->hs_flags |= HSC_ALARM_CARD_PRES; 1110 DEBUG0("Xscsb_hsc_init_slot_state: " 1111 "set HSC_ALARM_CARD_PRES"); 1112 } 1113 break; 1114 default: 1115 break; 1116 } 1117 return (rc); 1118 } 1119 1120 static hsc_slot_t * 1121 hsc_get_slot_info(hsc_state_t *hsc, int pci_devno) 1122 { 1123 int i; 1124 1125 for (i = 0; i < hsc->slot_table_size; i++) { 1126 1127 if (hsc->slot_table_prop[i].pci_devno == pci_devno) 1128 return ((hsc_slot_t *)hsc_find_slot( 1129 hsc->slot_table_prop[i].pslotnum)); 1130 } 1131 return (NULL); 1132 } 1133 1134 static hsc_slot_t * 1135 hsc_find_slot(int slot_number) 1136 { 1137 hsc_slot_t *hsp; 1138 1139 mutex_enter(&hsc_mutex); 1140 for (hsp = hsc_slot_list; hsp != NULL; hsp = hsp->hs_next) { 1141 if (hsp->hs_slot_number == slot_number) 1142 break; 1143 } 1144 mutex_exit(&hsc_mutex); 1145 return (hsp); 1146 } 1147 1148 1149 /* 1150 * This function is invoked by the SCSB when an interrupt 1151 * happens to indicate that a board has been inserted-in/removed-from 1152 * the specified slot. 1153 */ 1154 int 1155 hsc_slot_occupancy(int slot_number, boolean_t occupied, int flags, int healthy) 1156 { 1157 static const char func[] = "hsc_slot_occupancy"; 1158 hsc_slot_t *hsp; 1159 int rc = DDI_SUCCESS; 1160 1161 DEBUG4("hsc_slot_occupancy: slot %d %s, ac=%d, healthy=%d", 1162 slot_number, occupied ? "occupied" : "not occupied", 1163 (flags == ALARM_CARD_ON_SLOT) ? 1:0, healthy); 1164 1165 hsp = hsc_find_slot(slot_number); 1166 1167 if (hsp == NULL) { 1168 cmn_err(CE_NOTE, 1169 "%s: cannot map slot number %d to a hsc_slot_t", 1170 func, slot_number); 1171 return (DDI_FAILURE); 1172 } 1173 1174 hsp->hs_board_healthy = healthy; 1175 if (occupied) { 1176 /* 1177 * A board was just inserted. We are disconnected at this point. 1178 */ 1179 if (hsp->hs_slot_state == HPC_SLOT_EMPTY) 1180 hsp->hs_board_type = HPC_BOARD_CPCI_HS; 1181 hsp->hs_slot_state = HPC_SLOT_DISCONNECTED; 1182 if (flags == ALARM_CARD_ON_SLOT) { 1183 hsp->hs_flags |= HSC_ALARM_CARD_PRES; 1184 DEBUG0("Xhsc_slot_occupancy: set HSC_ALARM_CARD_PRES"); 1185 } 1186 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 1187 HPC_LED_ON); 1188 /* 1189 * if previous occupant stayed configured, do not allow another 1190 * occupant to be connected. 1191 * So as soon as the board is plugged in, we turn both LEDs On. 1192 * This behaviour is an indication that the slot state 1193 * is not clean. 1194 */ 1195 if (hsp->hs_flags & HSC_SLOT_BAD_STATE) { 1196 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 1197 HPC_LED_ON); 1198 return (DDI_SUCCESS); 1199 } 1200 1201 /* Do not allow connect if slot is disabled */ 1202 if ((hsp->hs_flags & HSC_SLOT_ENABLED) != HSC_SLOT_ENABLED) 1203 return (DDI_SUCCESS); 1204 /* if no healthy, we stay disconnected. */ 1205 if (healthy == B_FALSE) { 1206 return (DDI_SUCCESS); 1207 } 1208 rc = hsc_slot_autoconnect(hsp); 1209 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 1210 HPC_LED_BLINK); 1211 } else { 1212 /* 1213 * A board was just removed 1214 */ 1215 hsp->hs_slot_state = HPC_SLOT_EMPTY; 1216 hsp->hs_board_type = HPC_BOARD_UNKNOWN; 1217 hsp->hs_flags &= ~HSC_ENUM_FAILED; 1218 if (hsp->hs_flags & HSC_ALARM_CARD_PRES) { 1219 hsp->hs_flags &= ~HSC_ALARM_CARD_PRES; 1220 DEBUG0("Xhsc_slot_occupancy:clear HSC_ALARM_CARD_PRES"); 1221 } 1222 if (hsp->hs_board_configured == B_TRUE) { 1223 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 1224 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 1225 cmn_err(CE_WARN, "%s#%d: ALERT! Surprise Removal " 1226 " on Slot %d, Occupant Online!!", 1227 ddi_driver_name(hsp->hsc->dip), 1228 ddi_get_instance(hsp->hsc->dip), 1229 slot_number); 1230 cmn_err(CE_WARN, "%s#%d: ALERT! System now in " 1231 " Inconsistent State! Slot disabled. Halt!", 1232 ddi_driver_name(hsp->hsc->dip), 1233 ddi_get_instance(hsp->hsc->dip)); 1234 /* Slot in reset and disabled */ 1235 (void) scsb_hsc_disable_slot(hsp); 1236 hsp->hs_flags |= HSC_SLOT_BAD_STATE; 1237 /* the following works for P1.0 only. */ 1238 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 1239 HPC_LED_ON); 1240 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 1241 HPC_LED_ON); 1242 } else { 1243 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 1244 HPC_LED_OFF); 1245 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 1246 HPC_LED_OFF); 1247 } 1248 } 1249 return (rc); 1250 } 1251 1252 1253 /* 1254 * This function is invoked by the SCSB when the health status of 1255 * a board changes. 1256 */ 1257 /*ARGSUSED*/ 1258 int 1259 scsb_hsc_board_healthy(int slot_number, boolean_t healthy) 1260 { 1261 hsc_slot_t *hsp; 1262 hsc_state_t *hsc; 1263 1264 DEBUG2("hsc_board_healthy: slot %d = %d\n", slot_number, healthy); 1265 1266 hsp = hsc_find_slot(slot_number); 1267 if (hsp == NULL) { 1268 cmn_err(CE_NOTE, "hsc_board_healthy: No Slot Info."); 1269 return (DDI_FAILURE); 1270 } 1271 1272 hsc = hsp->hsc; 1273 if (hsp->hs_slot_state == HPC_SLOT_EMPTY) { 1274 #ifdef DEBUG 1275 cmn_err(CE_NOTE, "%s#%d: Healthy# %s on " 1276 "empty slot %d", ddi_driver_name(hsc->dip), 1277 ddi_get_instance(hsc->dip), 1278 healthy == B_TRUE ? "On" : "Off", slot_number); 1279 #endif 1280 return (DDI_FAILURE); 1281 } 1282 if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) { 1283 DEBUG2("healthy %s on disconnected slot %d\n", 1284 healthy == B_TRUE ? "On":"Off", slot_number); 1285 /* 1286 * Connect the slot if board healthy and in autoconfig mode. 1287 */ 1288 hsp->hs_board_healthy = healthy; 1289 if (healthy == B_TRUE) 1290 return (hsc_slot_autoconnect(hsp)); 1291 } 1292 1293 /* 1294 * the board is connected. The result could be seviour depending 1295 * on the occupant state. 1296 */ 1297 if (healthy == B_TRUE) { 1298 if (hsp->hs_board_healthy != B_TRUE) { 1299 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 1300 HPC_LED_OFF); 1301 /* Regained HEALTHY# at Run Time...!!! */ 1302 cmn_err(CE_NOTE, "%s#%d: slot %d Occupant " 1303 "%s, Regained HEALTHY#!", 1304 ddi_driver_name(hsc->dip), 1305 ddi_get_instance(hsc->dip), slot_number, 1306 hsp->hs_board_configured == B_TRUE ? 1307 "configured" : "Unconfigured"); 1308 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 1309 HPC_EVENT_SLOT_HEALTHY_OK, 0); 1310 } 1311 } else { 1312 if (hsp->hs_board_configured == B_TRUE) { 1313 /* Lost HEALTHY# at Run Time...Serious Condition. */ 1314 cmn_err(CE_WARN, "%s#%d: ALERT! Lost HEALTHY#" 1315 " on Slot %d, Occupant %s", 1316 ddi_driver_name(hsc->dip), 1317 ddi_get_instance(hsc->dip), slot_number, 1318 hsp->hs_board_configured == B_TRUE ? 1319 "Online!!!" : "Offline"); 1320 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 1321 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 1322 } 1323 if ((hsp->hs_board_configured != B_TRUE) || 1324 scsb_hsc_healthy_reset) { 1325 if (scsb_reset_slot(hsp->hs_hpchandle, 1326 slot_number, SCSB_RESET_SLOT) == 0) { 1327 /* signal Ok to remove board. */ 1328 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 1329 HPC_FAULT_LED, HPC_LED_ON); 1330 cmn_err(CE_WARN, "%s#%d: Slot %d " 1331 "successfully taken offline", 1332 ddi_driver_name(hsc->dip), 1333 ddi_get_instance(hsc->dip), 1334 slot_number); 1335 } 1336 } 1337 } 1338 hsp->hs_board_healthy = healthy; 1339 return (DDI_SUCCESS); 1340 } 1341 1342 static int 1343 hsc_slot_autoconnect(hsc_slot_t *hsp) 1344 { 1345 hsc_state_t *hsc = hsp->hsc; 1346 int rc = DDI_SUCCESS; 1347 /* 1348 * Keep slot in reset unless autoconfiguration is enabled 1349 * Ie. for Basic Hotswap mode, we stay disconnected at 1350 * insertion. For full hotswap mode, we automatically 1351 * go into connected state at insertion, so that occupant 1352 * autoconfiguration is possible. 1353 */ 1354 if (((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) && 1355 (hsp->hs_flags & HSC_AUTOCFG)) { 1356 /* this statement must be here before unreset. */ 1357 hsc->hsp_last = hsp; 1358 if ((rc = scsb_reset_slot(hsp->hs_hpchandle, 1359 hsp->hs_slot_number, SCSB_UNRESET_SLOT)) == 0) { 1360 1361 hsp->hs_slot_state = HPC_SLOT_CONNECTED; 1362 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 1363 HPC_FAULT_LED, HPC_LED_OFF); 1364 } else { 1365 hsc->hsp_last = NULL; 1366 rc = DDI_FAILURE; 1367 } 1368 } 1369 return (rc); 1370 } 1371 1372 /* 1373 * The SCSB code should invoke this function from its _init() function. 1374 */ 1375 int 1376 hsc_init() 1377 { 1378 int rc; 1379 1380 rc = ddi_soft_state_init(&hsc_state, sizeof (hsc_state_t), 1); 1381 if (rc != 0) 1382 return (rc); 1383 1384 hsc_slotops = hpc_alloc_slot_ops(KM_SLEEP); 1385 1386 hsc_slotops->hpc_version = HPC_SLOT_OPS_VERSION; 1387 hsc_slotops->hpc_op_connect = hsc_connect; 1388 hsc_slotops->hpc_op_disconnect = hsc_disconnect; 1389 hsc_slotops->hpc_op_insert = hsc_insert; 1390 hsc_slotops->hpc_op_remove = hsc_remove; 1391 hsc_slotops->hpc_op_control = hsc_control; 1392 1393 return (DDI_SUCCESS); 1394 } 1395 1396 1397 /* 1398 * The SCSB code should invoke this function from its _fini() function. 1399 */ 1400 int 1401 hsc_fini() 1402 { 1403 if (hsc_slotops != NULL) { 1404 hpc_free_slot_ops(hsc_slotops); 1405 hsc_slotops = NULL; 1406 } 1407 ddi_soft_state_fini(&hsc_state); 1408 return (DDI_SUCCESS); 1409 } 1410 1411 static int 1412 scsb_enable_enum(hsc_state_t *hsc) 1413 { 1414 DEBUG0("hsc: Enable ENUM#\n"); 1415 1416 if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) 1417 return (DDI_SUCCESS); 1418 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1419 return (DDI_FAILURE); 1420 1421 if (ddi_add_intr(hsc->dip, 1, NULL, NULL, 1422 hsc_enum_intr, (caddr_t)hsc) != DDI_SUCCESS) { 1423 cmn_err(CE_WARN, "%s#%d: failed ENUM# interrupt registration", 1424 ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip)); 1425 return (DDI_FAILURE); 1426 } 1427 cmn_err(CE_CONT, "?%s%d: Successfully Upgraded to " 1428 "Full Hotswap Mode\n", ddi_driver_name(hsc->dip), 1429 ddi_get_instance(hsc->dip)); 1430 hsc->state |= HSC_ENUM_ENABLED; 1431 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip, 1432 HOTSWAP_MODE_PROP, "full"); 1433 return (DDI_SUCCESS); 1434 1435 } 1436 1437 /*ARGSUSED*/ 1438 static int 1439 scsb_disable_enum(hsc_state_t *hsc, int op) 1440 { 1441 1442 DEBUG0("hsc: Disable ENUM#\n"); 1443 if (op == SCSB_HSC_FORCE_REMOVE) { 1444 /* 1445 * Clear all pending interrupts before unregistering 1446 * the interrupt. Otherwise the system will hang. 1447 * 1448 * Due to the hang problem, we'll not turn off or disable 1449 * interrupts because if there's a non-friendly full hotswap 1450 * device out there, the ENUM# will be kept asserted and 1451 * hence hsc_clear_all_enum() can never deassert ENUM#. 1452 * So the system will hang. 1453 */ 1454 if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) { 1455 /* hsc_clear_all_enum(hsc); */ 1456 ddi_remove_intr(hsc->dip, 1, NULL); 1457 hsc->state &= ~HSC_ENUM_ENABLED; 1458 cmn_err(CE_CONT, "?%s%d: Successfully Downgraded to " 1459 "Basic Hotswap Mode\n", 1460 ddi_driver_name(hsc->dip), 1461 ddi_get_instance(hsc->dip)); 1462 } 1463 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip, 1464 HOTSWAP_MODE_PROP, "basic"); 1465 return (DDI_SUCCESS); 1466 } else 1467 /* No programming interface for disabling ENUM# on MC/Tonga */ 1468 return (HPC_ERR_NOTSUPPORTED); 1469 } 1470 1471 #ifndef lint 1472 static int 1473 hsc_clear_all_enum(hsc_state_t *hsc) 1474 { 1475 int i, rc; 1476 hsc_slot_t *hsp; 1477 1478 for (i = 0; i < hsc->slot_table_size; i++) { 1479 1480 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum); 1481 if (hsp == NULL) 1482 continue; 1483 rc = hpc_slot_event_notify(hsp->hs_slot_handle, 1484 HPC_EVENT_CLEAR_ENUM, 1485 HPC_EVENT_SYNCHRONOUS); 1486 if (rc == HPC_EVENT_UNCLAIMED) 1487 break; /* no pending interrupts across the bus */ 1488 DEBUG1("Pending Intr on slot %d\n", 1489 hsc->slot_table_prop[i].pslotnum); 1490 } 1491 return (0); 1492 } 1493 #endif 1494 1495 int 1496 scsb_hsc_attach(dev_info_t *dip, void *scsb_handle, int instance) 1497 { 1498 int i, n, prop_len; 1499 int prom_prop = 0; /* default: OS property gives slot-table */ 1500 int rc; 1501 char *hotswap_model; 1502 hsc_state_t *hsc; 1503 scsb_state_t *scsb = (scsb_state_t *)scsb_handle; 1504 caddr_t hpc_slot_table_data, s; 1505 int hpc_slot_table_size; 1506 hsc_prom_slot_table_t *hpstp; 1507 int rstate; 1508 1509 DEBUG0("hsc_attach: enter\n"); 1510 /* 1511 * To get the slot information, 1512 * The OBP defines the 'slot-table' property. But the OS 1513 * can override it with 'hsc-slot-map' property 1514 * through the .conf file. 1515 * Since the formats are different, 2 different property names 1516 * are chosen. 1517 * The OBP property format is 1518 * <phandle>,<pci-devno>,<phys-slotno>,<ga-bits> 1519 * The OS property format is (ga-bits is not used however) 1520 * <busnexus-path>,<pci-devno>,<phys-slotno>,<ga-bits> 1521 */ 1522 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1523 "hsc-slot-map", (caddr_t)&hpc_slot_table_data, 1524 &hpc_slot_table_size); 1525 if (rc != DDI_PROP_SUCCESS) { 1526 prom_prop = 1; 1527 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1528 "slot-table", (caddr_t)&hpc_slot_table_data, 1529 &hpc_slot_table_size); 1530 if (rc != DDI_PROP_SUCCESS) { 1531 cmn_err(CE_WARN, "%s#%d: 'slot-table' property " 1532 "missing!", ddi_driver_name(dip), 1533 ddi_get_instance(dip)); 1534 return (DDI_FAILURE); 1535 } 1536 } 1537 rc = ddi_soft_state_zalloc(hsc_state, instance); 1538 if (rc != DDI_SUCCESS) 1539 return (DDI_FAILURE); 1540 1541 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1542 hsc->scsb_handle = scsb_handle; 1543 hsc->dip = dip; 1544 hsc->instance = instance; 1545 hsc->n_registered_occupants = 0; 1546 hsc->regDone = B_FALSE; 1547 /* hsc->slot_info = hsc_slot_list; */ 1548 1549 /* 1550 * Check whether the system should be in basic or full 1551 * hotswap mode. The PROM property always says full, so 1552 * look at the .conf file property whether this is "full" 1553 */ 1554 if (scsb_hsc_enable_fhs) { 1555 hsc->hotswap_mode = HSC_HOTSWAP_MODE_FULL; 1556 } else { 1557 hsc->hotswap_mode = HSC_HOTSWAP_MODE_BASIC; 1558 } 1559 1560 rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1561 "default-hotswap-mode", (caddr_t)&hotswap_model, &prop_len); 1562 1563 if (rc == DDI_PROP_SUCCESS) { 1564 if (strcmp(hotswap_model, "full") == 0) { 1565 hsc->hotswap_mode = HSC_HOTSWAP_MODE_FULL; 1566 } else if (strcmp(hotswap_model, "basic") == 0) { 1567 hsc->hotswap_mode = HSC_HOTSWAP_MODE_BASIC; 1568 } 1569 1570 kmem_free(hotswap_model, prop_len); 1571 } 1572 1573 /* 1574 * Determine the size of the slot table from the property and 1575 * allocate the slot table arrary..Decoding is different for 1576 * OS and PROM property. 1577 */ 1578 if (!prom_prop) { /* OS .conf property */ 1579 for (i = 0, n = 0; i < hpc_slot_table_size; i++) { 1580 if (hpc_slot_table_data[i] == 0) { 1581 n++; 1582 } 1583 } 1584 1585 /* There should be four elements per entry */ 1586 if (n % 4) { 1587 cmn_err(CE_WARN, "%s#%d: bad format for " 1588 "slot-table(%d)", ddi_driver_name(dip), 1589 ddi_get_instance(dip), n); 1590 kmem_free(hpc_slot_table_data, hpc_slot_table_size); 1591 ddi_soft_state_free(hsc_state, instance); 1592 return (DDI_FAILURE); 1593 } 1594 1595 hsc->slot_table_size = n / 4; 1596 } else { 1597 hsc->slot_table_size = hpc_slot_table_size / 1598 sizeof (hsc_prom_slot_table_t); 1599 n = hpc_slot_table_size % sizeof (hsc_prom_slot_table_t); 1600 if (n) { 1601 cmn_err(CE_WARN, "%s#%d: bad format for " 1602 "slot-table(%d)", ddi_driver_name(dip), 1603 ddi_get_instance(dip), hpc_slot_table_size); 1604 kmem_free(hpc_slot_table_data, hpc_slot_table_size); 1605 ddi_soft_state_free(hsc_state, instance); 1606 return (DDI_FAILURE); 1607 } 1608 } 1609 1610 /* 1611 * Netract800 FTC (formerly known as CFTM) workaround. 1612 * Leave Slot 2 out of the HS table if FTC is present in Slot 2 1613 */ 1614 if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES) { 1615 hsc->slot_table_size -= 1; 1616 } 1617 DEBUG1("hsc_attach: %d hotplug slots on bus\n", hsc->slot_table_size); 1618 /* 1619 * Create enough space for each slot table entry 1620 * based on how many entries in the property 1621 */ 1622 hsc->slot_table_prop = (hsc_slot_table_t *) 1623 kmem_zalloc(hsc->slot_table_size * 1624 sizeof (hsc_slot_table_t), KM_SLEEP); 1625 1626 if (!prom_prop) { 1627 s = hpc_slot_table_data; 1628 for (i = 0; i < hsc->slot_table_size; i++) { 1629 1630 char *nexus, *pcidev, *phys_slotname, *ga; 1631 1632 /* Pick off pointer to nexus path or PROM handle */ 1633 nexus = s; 1634 while (*s != NULL) 1635 s++; 1636 s++; 1637 1638 /* Pick off pointer to the pci device number */ 1639 pcidev = s; 1640 while (*s != NULL) 1641 s++; 1642 s++; 1643 1644 /* Pick off physical slot no */ 1645 phys_slotname = s; 1646 while (*s != NULL) 1647 s++; 1648 s++; 1649 1650 /* Pick off GA bits which we dont use for now. */ 1651 ga = s; 1652 while (*s != NULL) 1653 s++; 1654 s++; 1655 1656 if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES && 1657 atoi(phys_slotname) == SC_MC_CTC_SLOT) { 1658 --i; 1659 continue; 1660 } 1661 hsc->slot_table_prop[i].pslotnum = atoi(phys_slotname); 1662 hsc->slot_table_prop[i].ga = atoi(ga); 1663 hsc->slot_table_prop[i].pci_devno = atoi(pcidev); 1664 (void) strcpy(hsc->slot_table_prop[i].nexus, nexus); 1665 } 1666 } else { 1667 hpstp = (hsc_prom_slot_table_t *)hpc_slot_table_data; 1668 for (i = 0; i < hsc->slot_table_size; i++, hpstp++) { 1669 if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES && 1670 hpstp->pslotnum == SC_MC_CTC_SLOT) { 1671 --i; 1672 continue; 1673 } 1674 hsc->slot_table_prop[i].pslotnum = hpstp->pslotnum; 1675 hsc->slot_table_prop[i].ga = hpstp->ga; 1676 hsc->slot_table_prop[i].pci_devno = hpstp->pci_devno; 1677 1678 if (prom_phandle_to_path((uint_t)hpstp->phandle, 1679 hsc->slot_table_prop[i].nexus, 1680 sizeof (hsc->slot_table_prop[i].nexus)) 1681 == -1) { 1682 cmn_err(CE_WARN, "%s#%d: Cannot get phandle " 1683 "to nexus path", ddi_driver_name(dip), 1684 ddi_get_instance(dip)); 1685 kmem_free(hsc->slot_table_prop, 1686 (hsc->slot_table_size * 1687 sizeof (hsc_slot_table_t))); 1688 kmem_free(hpc_slot_table_data, 1689 hpc_slot_table_size); 1690 ddi_soft_state_free(hsc_state, instance); 1691 return (DDI_FAILURE); 1692 } 1693 } 1694 } 1695 1696 /* keep healthy register cache uptodate before reading slot state */ 1697 if (scsb_read_bhealthy(scsb_handle) != 0) { 1698 cmn_err(CE_WARN, "%s#%d: hsc_attach: Cannot read " 1699 "Healthy Registers", ddi_driver_name(dip), 1700 ddi_get_instance(dip)); 1701 kmem_free(hsc->slot_table_prop, 1702 (hsc->slot_table_size * 1703 sizeof (hsc_slot_table_t))); 1704 kmem_free(hpc_slot_table_data, 1705 hpc_slot_table_size); 1706 ddi_soft_state_free(hsc_state, instance); 1707 return (DDI_FAILURE); 1708 } 1709 1710 /* 1711 * Before we start registering the slots, calculate how many 1712 * slots are occupied. 1713 */ 1714 1715 for (i = 0; i < hsc->slot_table_size; i++) { 1716 if (scsb_get_slot_state(scsb_handle, 1717 hsc->slot_table_prop[i].pslotnum, &rstate) != 1718 DDI_SUCCESS) 1719 return (rc); 1720 if (rstate != HPC_SLOT_EMPTY) 1721 hsc->n_registered_occupants++; 1722 } 1723 1724 mutex_init(&hsc->hsc_mutex, NULL, MUTEX_DRIVER, NULL); 1725 for (i = 0; i < hsc->slot_table_size; i++) { 1726 1727 DEBUG2("Registering on nexus [%s] cPCI device [%d]\n", 1728 hsc->slot_table_prop[i].nexus, 1729 hsc->slot_table_prop[i].pci_devno); 1730 1731 if (hsc_slot_register(hsc, hsc->slot_table_prop[i].nexus, 1732 hsc->slot_table_prop[i].pci_devno, 1733 hsc->slot_table_prop[i].pslotnum, B_FALSE) != 1734 HPC_SUCCESS) { 1735 1736 cmn_err(CE_WARN, "%s#%d: Slot Registration Failure", 1737 ddi_driver_name(dip), ddi_get_instance(dip)); 1738 while (i) { 1739 i--; 1740 n = hsc->slot_table_prop[i].pslotnum; 1741 if (hsc_slot_unregister(n) != 0) { 1742 cmn_err(CE_WARN, 1743 "%s#%d: failed to unregister" 1744 " slot %d", 1745 ddi_driver_name(dip), 1746 ddi_get_instance(dip), n); 1747 1748 } 1749 } 1750 mutex_destroy(&hsc->hsc_mutex); 1751 kmem_free(hsc->slot_table_prop, (hsc->slot_table_size * 1752 sizeof (hsc_slot_table_t))); 1753 kmem_free(hpc_slot_table_data, hpc_slot_table_size); 1754 ddi_soft_state_free(hsc_state, instance); 1755 return (DDI_FAILURE); 1756 } 1757 } 1758 1759 hsc->hsp_last = NULL; 1760 hsc->hsc_intr_counter = 0; 1761 kmem_free(hpc_slot_table_data, hpc_slot_table_size); 1762 (void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip, 1763 HOTSWAP_MODE_PROP, "basic"); 1764 hsc->state |= (HSC_ATTACHED|HSC_SCB_CONNECTED); 1765 1766 /* 1767 * We enable full hotswap right here if all the slots are empty. 1768 */ 1769 if ((hsc->regDone == B_FALSE && hsc->n_registered_occupants == 0) || 1770 scsb_hsc_numReg == hsc->n_registered_occupants) { 1771 hsc->regDone = B_TRUE; 1772 if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) { 1773 if (scsb_enable_enum(hsc) != DDI_SUCCESS) { 1774 cmn_err(CE_WARN, "%s#%d: Cannot enable " 1775 "Full Hotswap", ddi_driver_name(dip), 1776 ddi_get_instance(dip)); 1777 } 1778 } 1779 } 1780 return (DDI_SUCCESS); 1781 } 1782 1783 /*ARGSUSED*/ 1784 int 1785 scsb_hsc_detach(dev_info_t *dip, void *scsb_handle, int instance) 1786 { 1787 int i = 0; 1788 hsc_state_t *hsc; 1789 char slotautocfg_prop[18]; 1790 1791 DEBUG0("hsc_detach: enter\n"); 1792 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1793 if (hsc == NULL) { 1794 DEBUG2("%s#%d: hsc_detach: Soft state NULL", 1795 ddi_driver_name(dip), ddi_get_instance(dip)); 1796 return (DDI_FAILURE); 1797 } 1798 1799 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1800 return (DDI_FAILURE); 1801 /* 1802 * let's unregister the hotpluggable slots with hotplug service. 1803 */ 1804 for (i = 0; i < hsc->slot_table_size; i++) { 1805 1806 hsc_slot_t *hsp; 1807 1808 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum); 1809 if (hsp == NULL) { 1810 cmn_err(CE_WARN, "%s#%d: hsc_detach: No Slot Info", 1811 ddi_driver_name(dip), ddi_get_instance(dip)); 1812 } else { 1813 hpc_led_info_t aledinfo; /* active led info. */ 1814 hpc_led_info_t fledinfo; /* fault led info. */ 1815 1816 aledinfo.led = HPC_ACTIVE_LED; 1817 aledinfo.state = HPC_LED_BLINK; 1818 fledinfo.led = HPC_FAULT_LED; 1819 fledinfo.state = HPC_LED_OFF; 1820 (void) hsc_led_state(hsp, HPC_CTRL_SET_LED_STATE, 1821 &aledinfo); 1822 (void) hsc_led_state(hsp, HPC_CTRL_SET_LED_STATE, 1823 &fledinfo); 1824 } 1825 (void) sprintf(slotautocfg_prop, "slot%d-autoconfig", 1826 hsp->hs_slot_number); 1827 (void) ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, 1828 slotautocfg_prop); 1829 if (hsc_slot_unregister(hsc->slot_table_prop[i].pslotnum) 1830 != 0) { 1831 cmn_err(CE_NOTE, "%s#%d: failed to unregister" 1832 " slot %d\n", ddi_driver_name(dip), 1833 ddi_get_instance(dip), 1834 hsc->slot_table_prop[i].pslotnum); 1835 return (DDI_FAILURE); 1836 } 1837 } 1838 kmem_free(hsc->slot_table_prop, (hsc->slot_table_size * 1839 sizeof (hsc_slot_table_t))); 1840 if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) { 1841 ddi_remove_intr(hsc->dip, 1, hsc->enum_iblock); 1842 hsc->state &= ~HSC_ENUM_ENABLED; 1843 } 1844 mutex_destroy(&hsc->hsc_mutex); 1845 (void) ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP); 1846 hsc->state &= ~(HSC_ATTACHED|HSC_SCB_CONNECTED); 1847 ddi_soft_state_free(hsc_state, instance); 1848 return (DDI_SUCCESS); 1849 } 1850 1851 /* 1852 * The following function is called when the SCSB is hot extracted from 1853 * the system. 1854 */ 1855 int 1856 scsb_hsc_freeze(dev_info_t *dip) 1857 { 1858 hsc_state_t *hsc; 1859 int instance = ddi_get_instance(dip); 1860 int i; 1861 hsc_slot_t *hsp; 1862 1863 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1864 if (hsc == NULL) { 1865 DEBUG2("%s#%d: Soft state NULL", 1866 ddi_driver_name(dip), ddi_get_instance(dip)); 1867 return (DDI_SUCCESS); 1868 } 1869 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1870 return (DDI_SUCCESS); 1871 hsc->state &= ~HSC_SCB_CONNECTED; 1872 1873 for (i = 0; i < hsc->slot_table_size; i++) { 1874 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum); 1875 1876 if (hsp == NULL) { 1877 cmn_err(CE_NOTE, "hsc_freeze: " 1878 " Cannot map slot number %d to a hsc_slot_t", 1879 hsc->slot_table_prop[i].pslotnum); 1880 continue; 1881 } 1882 /* 1883 * Since reset lines are pulled low, lets mark these 1884 * slots and not allow a connect operation. 1885 * Note that we still keep the slot as slot disconnected, 1886 * although it is connected from the hardware standpoint. 1887 * As soon as the SCB is plugged back in, we check these 1888 * states and put the hardware state back to its original 1889 * state. 1890 */ 1891 if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) { 1892 cmn_err(CE_WARN, "%s#%d: Slot %d Now out of Reset!", 1893 ddi_driver_name(hsc->dip), 1894 ddi_get_instance(hsc->dip), 1895 hsp->hs_slot_number); 1896 } 1897 hsp->hs_flags |= HSC_SCB_HOTSWAPPED; 1898 } 1899 1900 return (DDI_SUCCESS); 1901 } 1902 1903 /* 1904 * The following function is called when the SCSB is hot inserted from 1905 * the system. We must update the LED status and set the RST# registers 1906 * again. 1907 */ 1908 int 1909 scsb_hsc_restore(dev_info_t *dip) 1910 { 1911 int i; 1912 hsc_state_t *hsc; 1913 hsc_slot_t *hsp; 1914 int instance = ddi_get_instance(dip); 1915 1916 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1917 if (hsc == NULL) { 1918 DEBUG2("%s#%d: Soft state NULL", 1919 ddi_driver_name(dip), ddi_get_instance(dip)); 1920 return (DDI_SUCCESS); 1921 } 1922 1923 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1924 return (DDI_SUCCESS); 1925 hsc->state |= HSC_SCB_CONNECTED; 1926 for (i = 0; i < hsc->slot_table_size; i++) { 1927 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum); 1928 1929 if (hsp == NULL) { 1930 cmn_err(CE_NOTE, "%s#%d: hsc_restore: " 1931 " Cannot map slot number %d to a hsc_slot_t", 1932 ddi_driver_name(hsc->dip), 1933 ddi_get_instance(hsc->dip), 1934 hsc->slot_table_prop[i].pslotnum); 1935 continue; 1936 } 1937 if ((hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) && 1938 (hsp->hs_board_configured == B_FALSE)) { 1939 if (scsb_reset_slot(hsp->hs_hpchandle, 1940 hsp->hs_slot_number, 1941 SCSB_RESET_SLOT) != 0) { 1942 cmn_err(CE_WARN, "%s#%d: hsc_restore: " 1943 " Cannot reset disconnected slot %d", 1944 ddi_driver_name(hsc->dip), 1945 ddi_get_instance(hsc->dip), 1946 hsp->hs_slot_number); 1947 } 1948 } 1949 1950 if (scsb_hsc_init_slot_state(hsc, hsp) != DDI_SUCCESS) { 1951 1952 cmn_err(CE_WARN, "%s#%d: hsc_freeze: Cannot init" 1953 " slot%d state", 1954 ddi_driver_name(hsc->dip), 1955 ddi_get_instance(hsc->dip), 1956 hsp->hs_slot_number); 1957 } 1958 hsp->hs_flags &= ~HSC_SCB_HOTSWAPPED; 1959 } 1960 return (DDI_SUCCESS); 1961 } 1962 1963 #ifndef lint 1964 int 1965 scsb_hsc_freeze_check(dev_info_t *dip) 1966 { 1967 hsc_state_t *hsc; 1968 int instance = ddi_get_instance(dip); 1969 1970 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1971 if (hsc == NULL) { 1972 DEBUG2("%s#%d: Soft state NULL", 1973 ddi_driver_name(dip), ddi_get_instance(dip)); 1974 return (DDI_SUCCESS); 1975 } 1976 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1977 return (DDI_SUCCESS); 1978 return (DDI_SUCCESS); 1979 } 1980 #endif 1981 1982 /* 1983 * update info about Alarm Card insert/remove mechanism. 1984 */ 1985 void 1986 hsc_ac_op(int instance, int pslotnum, int op, void *arg) 1987 { 1988 hsc_slot_t *hsp; 1989 hsc_state_t *hsc; 1990 1991 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1992 if (hsc == NULL) { 1993 cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Soft State Info", 1994 ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip)); 1995 return; 1996 } 1997 1998 hsp = hsc_find_slot(pslotnum); 1999 if (hsp == NULL) { 2000 cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Slot Info", 2001 ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip)); 2002 return; 2003 } 2004 2005 switch (op) { 2006 case SCSB_HSC_AC_UNCONFIGURE : 2007 /* 2008 * If ENUM# is enabled, then action is pending on 2009 * this slot, just send a event. 2010 */ 2011 if (hsc->state & HSC_ENUM_ENABLED) 2012 (void) hpc_slot_event_notify( 2013 hsp->hs_slot_handle, 2014 HPC_EVENT_PROCESS_ENUM, 0); 2015 break; 2016 case SCSB_HSC_AC_GET_SLOT_INFO : 2017 *(hsc_slot_t **)arg = hsp; 2018 break; 2019 default : 2020 break; 2021 } 2022 } 2023 2024 static uint_t 2025 hsc_enum_intr(caddr_t iarg) 2026 { 2027 int rc; 2028 hsc_state_t *hsc = (hsc_state_t *)iarg; 2029 hsc_slot_t *hsp; 2030 2031 DEBUG0("!E!"); 2032 if ((hsc->state & HSC_ATTACHED) == 0) 2033 return (DDI_INTR_UNCLAIMED); 2034 2035 hsp = hsc_find_slot(hsc->slot_table_prop[0].pslotnum); 2036 if (hsp == NULL) /* No slots registered */ 2037 return (DDI_INTR_UNCLAIMED); 2038 2039 /* 2040 * The following must be done to clear interrupt (synchronous event). 2041 * To process the interrupt, we send an asynchronous event. 2042 */ 2043 rc = hpc_slot_event_notify(hsp->hs_slot_handle, 2044 HPC_EVENT_CLEAR_ENUM, 2045 HPC_EVENT_SYNCHRONOUS); 2046 if (rc == HPC_EVENT_UNCLAIMED) { 2047 /* 2048 * possible support for handling insertion of non friendly 2049 * full hotswap boards, otherwise the system hangs due 2050 * to uncleared interrupt bursts. 2051 */ 2052 DEBUG2("!E>counter %d, last op@slot %lx\n", 2053 hsc->hsc_intr_counter, hsc->hsp_last); 2054 hsc->hsc_intr_counter ++; 2055 if (hsc->hsc_intr_counter == scsb_hsc_max_intr_count) { 2056 if (!hsc->hsp_last) { 2057 cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: " 2058 " No Last Board Insertion Info.", 2059 ddi_driver_name(hsc->dip), 2060 ddi_get_instance(hsc->dip)); 2061 hsc->hsc_intr_counter = 0; 2062 return (DDI_INTR_UNCLAIMED); 2063 } 2064 hsp = hsc->hsp_last; 2065 cmn_err(CE_WARN, "%s#%d: Bad (non friendly ?) Board " 2066 "in Slot %d ? Taking it Offline.", 2067 ddi_driver_name(hsc->dip), 2068 ddi_get_instance(hsc->dip), 2069 hsp->hs_slot_number); 2070 /* 2071 * this should put just inserted board back in 2072 * reset, thus deasserting the ENUM# and the 2073 * system hang. 2074 */ 2075 if (scsb_reset_slot(hsp->hs_hpchandle, 2076 hsp->hs_slot_number, 2077 SCSB_RESET_SLOT) == 0) { 2078 /* Enumeration failed on this board */ 2079 hsp->hs_flags |= HSC_ENUM_FAILED; 2080 if (hsp->hs_board_configured == B_TRUE) 2081 cmn_err(CE_WARN, "%s#%d: ALERT! System" 2082 " now in Inconsistent State." 2083 " Halt!", 2084 ddi_driver_name(hsc->dip), 2085 ddi_get_instance(hsc->dip)); 2086 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 2087 HPC_FAULT_LED, HPC_LED_ON); 2088 } 2089 hsc->hsc_intr_counter = 0; 2090 } 2091 return (DDI_INTR_UNCLAIMED); 2092 } 2093 hsc->hsc_intr_counter = 0; 2094 /* 2095 * if interrupt success, rc denotes the PCI device number which 2096 * generated the ENUM# interrupt. 2097 */ 2098 hsp = hsc_get_slot_info(hsc, rc); 2099 if (hsp == NULL) { 2100 cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: no slot info for " 2101 "dev %x", ddi_driver_name(hsc->dip), 2102 ddi_get_instance(hsc->dip), rc); 2103 return (DDI_INTR_CLAIMED); /* interrupt already cleared */ 2104 } 2105 /* if this is Alarm Card and if it is busy, dont process event */ 2106 if (hsp->hs_flags & HSC_ALARM_CARD_PRES) { 2107 if (scsb_hsc_ac_op(hsp->hs_hpchandle, hsp->hs_slot_number, 2108 SCSB_HSC_AC_BUSY) == B_TRUE) { 2109 /* 2110 * Busy means we need to inform (envmond)alarmcard.so 2111 * that it should save the AC configuration, stop the 2112 * heartbeat, and shutdown the RSC link. 2113 */ 2114 (void) scsb_hsc_ac_op(hsp->hs_hpchandle, 2115 hsp->hs_slot_number, 2116 SCSB_HSC_AC_REMOVAL_ALERT); 2117 return (DDI_INTR_CLAIMED); 2118 } 2119 } 2120 /* 2121 * If SCB was swapped out, dont process ENUM#. We put this slot 2122 * back in reset after SCB is inserted. 2123 */ 2124 if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) && 2125 (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED)) 2126 return (DDI_INTR_CLAIMED); 2127 2128 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 2129 HPC_EVENT_PROCESS_ENUM, 0); 2130 return (DDI_INTR_CLAIMED); 2131 } 2132 /* 2133 * A routine to convert a number (represented as a string) to 2134 * the integer value it represents. 2135 */ 2136 2137 static int 2138 isdigit(int ch) 2139 { 2140 return (ch >= '0' && ch <= '9'); 2141 } 2142 2143 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') 2144 #define bad(val) (val == NULL || !isdigit(*val)) 2145 2146 static int 2147 atoi(const char *p) 2148 { 2149 int n; 2150 int c, neg = 0; 2151 2152 if (!isdigit(c = *p)) { 2153 while (isspace(c)) 2154 c = *++p; 2155 switch (c) { 2156 case '-': 2157 neg++; 2158 /* FALLTHROUGH */ 2159 case '+': 2160 c = *++p; 2161 } 2162 if (!isdigit(c)) 2163 return (0); 2164 } 2165 for (n = '0' - c; isdigit(c = *++p); ) { 2166 n *= 10; /* two steps to avoid unnecessary overflow */ 2167 n += '0' - c; /* accum neg to avoid surprises at MAX */ 2168 } 2169 return (neg ? n : -n); 2170 } 2171