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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 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 * MonteCarlo HotSwap Controller functionality 31 */ 32 33 #include <sys/types.h> 34 #include <sys/stropts.h> 35 #include <sys/stream.h> 36 #include <sys/strsun.h> 37 #include <sys/kmem.h> 38 #include <sys/cmn_err.h> 39 #include <sys/errno.h> 40 #include <sys/cpuvar.h> 41 #include <sys/open.h> 42 #include <sys/stat.h> 43 #include <sys/conf.h> 44 #include <sys/ddi.h> 45 #include <sys/sunddi.h> 46 #include <sys/modctl.h> 47 #include <sys/promif.h> 48 #include <sys/hotplug/hpcsvc.h> 49 50 #include <sys/hscimpl.h> 51 #include <sys/hsc.h> 52 53 #include <sys/mct_topology.h> 54 #include <sys/scsbioctl.h> 55 #include <sys/scsb.h> 56 57 #define HOTSWAP_MODE_PROP "hotswap-mode" 58 #define ALARM_CARD_ON_SLOT 1 59 #define SCSB_HSC_FORCE_REMOVE 1 /* force remove enum intr handler */ 60 61 /* TUNABLE PARAMETERS. Some are Debug Only. Please take care when using. */ 62 63 /* 64 * Set this flag to 1, to enable full hotswap mode at boot time. 65 * Since HPS is threaded, it is not recommended that we set this flag 66 * to 1 because enabling full hotswap interrupt can invoke the ENUM 67 * event handler accessing the slot data structure which may have not 68 * been initialized in the hotplug framework since the HPS may not yet 69 * have called the slot registration function with the bus nexus. 70 */ 71 static int scsb_hsc_enable_fhs = 0; 72 73 /* 74 * Every time a slot is registered with the hotswap framework, the 75 * framework calls back. This variable keeps a count on how many 76 * callbacks are done. 77 */ 78 static int scsb_hsc_numReg = 0; 79 /* 80 * When this flag is set, the board is taken offline (put in reset) after 81 * a unconfigure operation, in Basic Hotswap mode. 82 */ 83 static int scsb_hsc_bhs_slot_reset = 1; 84 /* 85 * When this flag is set, we take the board to reset after unconfigure 86 * operation when operating in full hotswap mode. 87 */ 88 static int scsb_hsc_fhs_slot_reset = 1; 89 /* 90 * Implementation of this counter will work only on Montecarlo since 91 * the ENUM# Interrupt line is not shared with other interrupts. 92 * When the hardware routing changes, then there may be need to remove 93 * or change this functionality. 94 * This functionality is provided so that a bad or non friendly full hotswap 95 * board does not hang the system in full hotswap mode. Atleast the 96 * intent is that! Eventually Solaris kernel will provide similar support 97 * for recovering from a stuck interrupt line. Till then, lets do this. 98 */ 99 static int scsb_hsc_max_intr_count = 8; 100 /* 101 * Since the hardware does not support enabling/disabling ENUM#, the 102 * following flag can be used for imitating that behaviour. 103 * Currently we can set this flag and use the remove op to remove the 104 * interrupt handler from the system. Care must be taken when using this 105 * function since trying to remove the interrupt handler when the interrupts 106 * are pending may hang the system permanently. 107 * Since the hardware does not support this functionality, we adopt this 108 * approach for debugs. 109 */ 110 static int scsb_hsc_enum_switch = 0; 111 112 /* 113 * When the board loses Healthy# at runtime (with the board being configured), 114 * cPCI specs states that a Reset has to be asserted immediately. 115 * We dont do this currently, until satellite processor support is given 116 * and the implications of such a act is fully understood. 117 * To adopt the cPCI specs recommendation, set this flag to 1. 118 */ 119 static int scsb_hsc_healthy_reset = 0; 120 121 /* 122 * According to PCI 2.2 specification, once a board comes out of PCI_RST#, 123 * it may take upto 2^25 clock cycles to respond to config cycles. For 124 * montecarlo using a 33MHz cPCI bus, it's around 1.024 s. The variable 125 * will specify the time in ms to wait before attempting config access. 126 */ 127 static int scsb_connect_delay = 1025; 128 129 /* 130 * slot map property for MC should be 131 * 132 * hsc-slot-map="/pci@1f,0/pci@1/pci@1","15","2", 133 * "/pci@1f,0/pci@1/pci@1","14","3", 134 * "/pci@1f,0/pci@1/pci@1","13","4", 135 * "/pci@1f,0/pci@1/pci@1","12","5" 136 * "/pci@1f,0/pci@1/pci@1","11","6" 137 * "/pci@1f,0/pci@1/pci@1","10","7" 138 * "/pci@1f,0/pci@1/pci@1","8","8"; 139 * 140 * slot map property for Tonga should be 141 * hsc-slot-map="/pci@1f,0/pci@1/pci@1","8","1" 142 * "/pci@1f,0/pci@1/pci@1", "15", "2" 143 * "/pci@1f,0/pci@1/pci@1", "14", "4" 144 * "/pci@1f,0/pci@1/pci@1", "13", "5" 145 * 146 * Please note that the CPU slot number is 3 for Tonga. 147 */ 148 149 /* 150 * Services we require from the SCSB 151 */ 152 extern int scsb_get_slot_state(void *, int, int *); 153 extern int scsb_read_bhealthy(scsb_state_t *scsb); 154 extern int scsb_read_slot_health(scsb_state_t *scsb, int pslotnum); 155 extern int scsb_connect_slot(void *, int, int); 156 extern int scsb_disconnect_slot(void *, int, int); 157 158 static void *hsc_state; 159 160 static uint_t hsc_enum_intr(char *); 161 static hsc_slot_t *hsc_get_slot_info(hsc_state_t *, int); 162 static int scsb_enable_enum(hsc_state_t *); 163 static int scsb_disable_enum(hsc_state_t *, int); 164 static int atoi(const char *); 165 static int isdigit(int); 166 static hsc_slot_t *hsc_find_slot(int); 167 static void hsc_led_op(hsc_slot_t *, int, hpc_led_t, hpc_led_state_t); 168 static int hsc_led_state(hsc_slot_t *, int, hpc_led_info_t *); 169 static int scsb_hsc_disable_slot(hsc_slot_t *); 170 static int scsb_hsc_enable_slot(hsc_slot_t *); 171 #ifndef lint 172 static int hsc_clear_all_enum(hsc_state_t *); 173 #endif 174 static int hsc_slot_register(hsc_state_t *, char *, uint16_t, uint_t, 175 boolean_t); 176 static int hsc_slot_unregister(int); 177 static int scsb_hsc_init_slot_state(hsc_state_t *, hsc_slot_t *); 178 static int hsc_slot_autoconnect(hsc_slot_t *); 179 180 static hpc_slot_ops_t *hsc_slotops; 181 static hsc_slot_t *hsc_slot_list; /* linked list of slots */ 182 183 /* 184 * This mutex protects the following variables: 185 * hsc_slot_list 186 */ 187 static kmutex_t hsc_mutex; 188 189 190 /* ARGSUSED */ 191 static int 192 hsc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 193 { 194 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 195 int rc, rstate; 196 hsc_state_t *hsc; 197 198 DEBUG2("hsc_connect: slot %d, healthy %d", hsp->hs_slot_number, 199 hsp->hs_board_healthy); 200 201 if (!(hsp->hs_flags & (HSC_ENABLED|HSC_SLOT_ENABLED))) 202 return (HPC_ERR_FAILED); 203 /* if SCB hotswapped, do not allow connect operations */ 204 if (hsp->hs_flags & HSC_SCB_HOTSWAPPED) 205 return (HPC_ERR_FAILED); 206 /* 207 * if previous occupant stayed configured, do not allow another 208 * occupant to be connected. 209 * This behaviour is an indication that the slot state 210 * is not clean. 211 */ 212 if (hsp->hs_flags & HSC_SLOT_BAD_STATE) { 213 /* 214 * In the current implementation, we turn both fault 215 * and active LEDs to ON state in this situation. 216 */ 217 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 218 HPC_LED_ON); 219 return (HPC_ERR_FAILED); 220 } 221 /* 222 * Get the actual status from the i2c bus 223 */ 224 rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number, 225 &rstate); 226 if (rc != DDI_SUCCESS) 227 return (HPC_ERR_FAILED); 228 229 hsp->hs_slot_state = rstate; 230 if (hsp->hs_slot_state == HPC_SLOT_EMPTY) { 231 #ifdef DEBUG 232 cmn_err(CE_CONT, 233 "?hsc_connect: slot %d is empty\n", 234 hsp->hs_slot_number); 235 #endif 236 return (HPC_ERR_FAILED); 237 } 238 239 if (hsp->hs_slot_state == HPC_SLOT_CONNECTED) 240 return (HPC_SUCCESS); 241 242 rc = HPC_SUCCESS; 243 /* 244 * call scsb to connect the slot. This also makes sure board is healthy 245 */ 246 if (scsb_connect_slot(hsp->hs_hpchandle, hsp->hs_slot_number, 247 hsp->hs_board_healthy) != DDI_SUCCESS) { 248 DEBUG1("hsc_connect: slot %d connection failed", 249 hsp->hs_slot_number); 250 rc = HPC_ERR_FAILED; 251 } else { 252 if (hsp->hs_slot_state != HPC_SLOT_CONNECTED) { 253 if (hsp->hs_board_healthy == B_FALSE) { 254 cmn_err(CE_NOTE, "HEALTHY# not asserted on " 255 " slot %d", hsp->hs_slot_number); 256 return (HPC_ERR_FAILED); 257 } 258 hsc = hsp->hsc; 259 hsc->hsp_last = hsp; 260 if (scsb_reset_slot(hsp->hs_hpchandle, 261 hsp->hs_slot_number, SCSB_UNRESET_SLOT) != 0) { 262 263 return (HPC_ERR_FAILED); 264 } 265 /* 266 * Unresetting a board may have caused an interrupt 267 * burst in case of non friendly boards. So it is 268 * important to make sure that the ISR has not 269 * put this board back to disconnect state. 270 */ 271 delay(1); 272 if (hsp->hs_flags & HSC_ENUM_FAILED) { 273 hsp->hs_flags &= ~HSC_ENUM_FAILED; 274 return (HPC_ERR_FAILED); 275 } 276 DEBUG1("hsc_connect: slot %d connected", 277 hsp->hs_slot_number); 278 rc = HPC_SUCCESS; 279 hsp->hs_slot_state = HPC_SLOT_CONNECTED; 280 (void) hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 281 HPC_FAULT_LED, HPC_LED_OFF); 282 } 283 } 284 285 /* 286 * PCI 2.2 specs recommend that the probe software wait 287 * for upto 2^25 PCI clock cycles after deassertion of 288 * PCI_RST# before the board is able to respond to config 289 * cycles. So, before we return, we wait for ~1 sec. 290 */ 291 delay(drv_usectohz(scsb_connect_delay * 1000)); 292 return (rc); 293 } 294 295 296 /* ARGSUSED */ 297 static int 298 hsc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 299 { 300 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 301 hsc_state_t *hsc; 302 #ifdef DEBUG 303 static const char func[] = "hsc_disconnect"; 304 #endif 305 306 DEBUG1("hsc_disconnect: slot %d", hsp->hs_slot_number); 307 308 if (hsp->hs_board_configured) { 309 #ifdef DEBUG 310 cmn_err(CE_NOTE, 311 "%s: cannot disconnect configured board in slot %d", 312 func, hsp->hs_slot_number); 313 #endif 314 return (HPC_ERR_FAILED); 315 } 316 317 if (hsp->hs_slot_state == HPC_SLOT_EMPTY) { 318 #ifdef DEBUG 319 cmn_err(CE_NOTE, "%s: slot %d is empty", 320 func, hsp->hs_slot_number); 321 #endif 322 return (HPC_SUCCESS); 323 } 324 325 if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) { 326 /* 327 * if already disconnected, just return success 328 * Duplicate disconnect messages should not be failed! 329 */ 330 return (HPC_SUCCESS); 331 } 332 /* if SCB hotswapped, do not allow disconnect operations */ 333 if (hsp->hs_flags & HSC_SCB_HOTSWAPPED) 334 return (HPC_ERR_FAILED); 335 336 /* call scsb to disconnect the slot */ 337 if (scsb_disconnect_slot(hsp->hs_hpchandle, B_TRUE, hsp->hs_slot_number) 338 != DDI_SUCCESS) 339 return (HPC_ERR_FAILED); 340 hsc = hsp->hsc; 341 if (hsc->hsp_last == hsp) 342 hsc->hsp_last = NULL; 343 344 return (HPC_SUCCESS); 345 } 346 347 348 /* 349 * In the cPCI world, this operation is not applicable. 350 * However, we use this function to enable full hotswap mode in debug mode. 351 */ 352 /* ARGSUSED */ 353 static int 354 hsc_insert(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 355 { 356 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 357 358 if (scsb_hsc_enum_switch && 359 (scsb_enable_enum(hsp->hsc) == DDI_SUCCESS)) { 360 return (HPC_SUCCESS); 361 } 362 return (HPC_ERR_NOTSUPPORTED); 363 } 364 365 366 /* 367 * In the cPCI world, this operation is not applicable. 368 * However, we use this function to disable full hotswap mode in debug mode. 369 */ 370 /* ARGSUSED */ 371 static int 372 hsc_remove(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags) 373 { 374 hsc_slot_t *hsp = (hsc_slot_t *)ops_arg; 375 376 if (scsb_hsc_enum_switch && 377 (scsb_disable_enum(hsp->hsc, SCSB_HSC_FORCE_REMOVE) 378 == DDI_SUCCESS)) { 379 hsp->hs_flags &= ~HSC_ENUM_FAILED; 380 return (HPC_SUCCESS); 381 } 382 return (HPC_ERR_NOTSUPPORTED); 383 } 384 385 static void 386 hsc_led_op(hsc_slot_t *hsp, int cmd, hpc_led_t led, hpc_led_state_t led_state) 387 { 388 hpc_led_info_t ledinfo; 389 390 ledinfo.led = led; 391 ledinfo.state = led_state; 392 (void) hsc_led_state(hsp, cmd, &ledinfo); 393 } 394 395 static int 396 hsc_led_state(hsc_slot_t *hsp, int cmd, hpc_led_info_t *hlip) 397 { 398 hpc_led_state_t *hlsp; 399 scsb_uinfo_t sunit; 400 int res; 401 402 DEBUG3("hsc_led_state: slot %d, led %x, state %x", 403 hsp->hs_slot_number, hlip->led, hlip->state); 404 405 sunit.unit_type = SLOT; 406 sunit.unit_number = hsp->hs_slot_number; 407 /* 408 * We ignore operations on LEDs that we don't support 409 */ 410 switch (hlip->led) { 411 case HPC_FAULT_LED: 412 sunit.led_type = NOK; 413 hlsp = &hsp->hs_fault_led_state; 414 break; 415 case HPC_ACTIVE_LED: 416 sunit.led_type = OK; 417 hlsp = &hsp->hs_active_led_state; 418 break; 419 default: 420 return (HPC_ERR_NOTSUPPORTED); 421 } 422 423 switch (hlip->state) { 424 case HPC_LED_BLINK: 425 sunit.unit_state = BLINK; 426 if (hlip->led != HPC_ACTIVE_LED) 427 return (HPC_ERR_NOTSUPPORTED); 428 break; 429 case HPC_LED_ON: 430 sunit.unit_state = ON; 431 break; 432 case HPC_LED_OFF: 433 sunit.unit_state = OFF; 434 break; 435 default: 436 break; 437 } 438 439 switch (cmd) { 440 case HPC_CTRL_SET_LED_STATE: 441 res = scsb_led_set(hsp->hs_hpchandle, &sunit, sunit.led_type); 442 if (res != 0) 443 return (HPC_ERR_FAILED); 444 *hlsp = (hpc_led_state_t)sunit.unit_state; 445 break; 446 447 case HPC_CTRL_GET_LED_STATE: 448 res = scsb_led_get(hsp->hs_hpchandle, &sunit, sunit.led_type); 449 if (res) 450 return (HPC_ERR_FAILED); 451 /* hlip->state = sunit.unit_state; */ 452 break; 453 454 default: 455 return (HPC_ERR_INVALID); 456 } 457 458 return (HPC_SUCCESS); 459 460 } 461 462 463 static int 464 hsc_get_slot_state(hsc_slot_t *hsp, hpc_slot_state_t *hssp) 465 { 466 int rstate = 0; 467 int rc; 468 #ifdef DEBUG 469 int orstate; /* original rstate */ 470 #endif 471 472 DEBUG1("hsc_get_slot_state: slot %d", hsp->hs_slot_number); 473 rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number, 474 &rstate); 475 if (rc != DDI_SUCCESS) 476 return (HPC_ERR_FAILED); 477 #ifdef DEBUG 478 orstate = hsp->hs_slot_state; 479 #endif 480 hsp->hs_slot_state = rstate; 481 switch (hsp->hs_slot_state) { 482 case HPC_SLOT_EMPTY: 483 DEBUG0("empty"); 484 break; 485 case HPC_SLOT_CONNECTED: 486 DEBUG0("connected"); 487 break; 488 case HPC_SLOT_DISCONNECTED: 489 DEBUG0("disconnected"); 490 break; 491 } 492 493 *hssp = hsp->hs_slot_state; 494 495 /* doing get-state above may have caused a freeze operation */ 496 if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) && 497 (rstate == HPC_SLOT_DISCONNECTED)) { 498 /* freeze puts disconnected boards to connected state */ 499 *hssp = HPC_SLOT_CONNECTED; 500 #if 0 501 /* in FHS, deassertion of reset may have configured the board */ 502 if (hsp->hs_board_configured == B_TRUE) { 503 hsp->hs_slot_state = *hssp; 504 } 505 #endif 506 } 507 #ifdef DEBUG 508 /* a SCB hotswap may have forced a state change on the receptacle */ 509 if (orstate != *hssp) { 510 cmn_err(CE_NOTE, "hsc_get_state: slot%d state change due" 511 " to SCB hotswap!", hsp->hs_slot_number); 512 } 513 #endif 514 return (HPC_SUCCESS); 515 } 516 517 518 static int 519 hsc_set_config_state(hsc_slot_t *hsp, int cmd) 520 { 521 hsc_state_t *hsc = hsp->hsc; 522 523 DEBUG1("hsc_set_config_state: slot %d", hsp->hs_slot_number); 524 525 switch (cmd) { 526 case HPC_CTRL_DEV_CONFIGURED: 527 /* 528 * Closing of the Ejector switch in configured/busy state can 529 * cause duplicate CONFIGURED messages to come down. 530 * Make sure our LED states are fine. 531 */ 532 if (hsp->hs_board_configured == B_TRUE) { 533 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 534 HPC_LED_ON); 535 break; 536 } 537 hsp->hs_board_configured = B_TRUE; 538 hsp->hs_board_configuring = B_FALSE; 539 if ((hsc->state & HSC_ATTACHED) == HSC_ATTACHED && 540 hsp->hs_flags & HSC_ALARM_CARD_PRES) 541 scsb_hsc_ac_op(hsp->hs_hpchandle, 542 hsp->hs_slot_number, SCSB_HSC_AC_CONFIGURED); 543 /* LED must be OFF on the occupant. */ 544 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 545 HPC_EVENT_SLOT_BLUE_LED_OFF, 0); 546 if (hsp->hs_flags & HSC_AUTOCFG) 547 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 548 HPC_EVENT_ENABLE_ENUM, 0); 549 else 550 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 551 HPC_EVENT_DISABLE_ENUM, 0); 552 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 553 HPC_LED_ON); 554 if (hsc->hsp_last == hsp) 555 hsc->hsp_last = NULL; 556 break; 557 case HPC_CTRL_DEV_UNCONFIGURED: 558 hsp->hs_board_configured = B_FALSE; 559 hsp->hs_board_unconfiguring = B_FALSE; 560 hsp->hs_flags &= ~HSC_SLOT_BAD_STATE; 561 if (hsp->hs_flags & HSC_ALARM_CARD_PRES) 562 scsb_hsc_ac_op(hsp->hs_hpchandle, 563 hsp->hs_slot_number, SCSB_HSC_AC_UNCONFIGURED); 564 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 565 HPC_LED_BLINK); 566 if (((hsc->state & HSC_ENUM_ENABLED) && 567 scsb_hsc_fhs_slot_reset) || 568 (((hsc->state & HSC_ENUM_ENABLED) != HSC_ENUM_ENABLED) && 569 scsb_hsc_bhs_slot_reset) || 570 ((hsp->hs_flags & HSC_AUTOCFG) != 571 HSC_AUTOCFG)) { 572 if (scsb_reset_slot(hsp->hs_hpchandle, 573 hsp->hs_slot_number, SCSB_RESET_SLOT) == 0) { 574 575 hsp->hs_slot_state = HPC_SLOT_DISCONNECTED; 576 hsp->hs_board_healthy = B_FALSE; 577 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 578 HPC_FAULT_LED, HPC_LED_ON); 579 } 580 } 581 break; 582 case HPC_CTRL_DEV_CONFIG_FAILURE: 583 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 584 HPC_LED_BLINK); 585 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 586 HPC_FAULT_LED, HPC_LED_ON); 587 break; 588 case HPC_CTRL_DEV_UNCONFIG_FAILURE: 589 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 590 HPC_LED_ON); 591 break; 592 case HPC_CTRL_DEV_CONFIG_START: 593 case HPC_CTRL_DEV_UNCONFIG_START: 594 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED, 595 HPC_LED_OFF); 596 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED, 597 HPC_LED_BLINK); 598 break; 599 default: 600 return (HPC_ERR_INVALID); 601 } 602 603 if (cmd != HPC_CTRL_DEV_CONFIG_START && 604 cmd != HPC_CTRL_DEV_UNCONFIG_START && 605 hsc->regDone == B_FALSE && 606 scsb_hsc_numReg < hsc->n_registered_occupants) { 607 scsb_hsc_numReg++; 608 609 /* 610 * If the callback is invoked for all registered slots, 611 * enable ENUM. 612 */ 613 if (((hsc->state & HSC_ATTACHED) == HSC_ATTACHED) && 614 (scsb_hsc_numReg == hsc->n_registered_occupants)) { 615 hsc->regDone = B_TRUE; 616 if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) { 617 #ifdef DEBUG 618 cmn_err(CE_CONT, "%s%d: Enabling full hotswap" 619 ":%d non-empty slots\n", 620 ddi_driver_name(hsc->dip), 621 ddi_get_instance(hsc->dip), 622 hsc->n_registered_occupants); 623 #endif 624 if (scsb_enable_enum(hsc) != DDI_SUCCESS) { 625 cmn_err(CE_WARN, "%s#%d: Cannot enable " 626 "Full Hotswap", 627 ddi_driver_name(hsc->dip), 628 ddi_get_instance(hsc->dip)); 629 630 return (HPC_ERR_FAILED); 631 } 632 } 633 } 634 } 635 636 return (HPC_SUCCESS); 637 } 638 639 640 /*ARGSUSED*/ 641 static int 642 hsc_get_board_type(hsc_slot_t *hsp, hpc_board_type_t *hbtp) 643 { 644 *hbtp = hsp->hs_board_type; 645 return (HPC_SUCCESS); 646 } 647 648 649 /* ARGSUSED */ 650 static int 651 hsc_autoconfig(hsc_slot_t *hsp, int cmd) 652 { 653 int res = HPC_SUCCESS, enum_disable = B_TRUE, i; 654 char slotautocfg_prop[18]; 655 hsc_state_t *hsc; 656 657 DEBUG1("hsc_autoconfig: slot %d", hsp->hs_slot_number); 658 sprintf(slotautocfg_prop, "slot%d-autoconfig", hsp->hs_slot_number); 659 660 if (cmd == HPC_CTRL_ENABLE_AUTOCFG) { 661 hsp->hs_flags |= HSC_AUTOCFG; 662 ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip, 663 slotautocfg_prop, "enabled"); 664 if ((res = scsb_enable_enum(hsp->hsc)) == DDI_SUCCESS) { 665 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 666 HPC_EVENT_ENABLE_ENUM, 0); 667 } 668 } else { 669 ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip, 670 slotautocfg_prop, "disabled"); 671 hsp->hs_flags &= ~HSC_AUTOCFG; 672 hsc = hsp->hsc; 673 if (hsc->state & HSC_ATTACHED) { 674 (void) hpc_slot_event_notify(hsp->hs_slot_handle, 675 HPC_EVENT_DISABLE_ENUM, 0); 676 for (i = 0; i < hsc->slot_table_size; i++) { 677 hsc_slot_t *thsp; 678 int slotnum; 679 680 slotnum = hsc->slot_table_prop[i].pslotnum; 681 thsp = hsc_find_slot(slotnum); 682 if (thsp == NULL) { 683 cmn_err(CE_WARN, "%s#%d: hsc_autocfg:" 684 "No Slot Info for slot %d", 685 ddi_driver_name(hsc->dip), 686 ddi_get_instance(hsc->dip), 687 slotnum); 688 continue; 689 } 690 if (thsp->hs_flags & HSC_AUTOCFG) { 691 enum_disable = B_FALSE; 692 break; 693 } 694 } 695 if (enum_disable == B_TRUE) 696 scsb_disable_enum(hsc, 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 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 hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG); 821 hsp->hs_flags &= ~HSC_SLOT_ENABLED; 822 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 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 hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG); 842 hsp->hs_flags |= HSC_SLOT_ENABLED; 843 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 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 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 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 scsb_reset_slot(hsc->scsb_handle, slot_number, 1070 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 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 ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP, 1432 "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 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 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 ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP, 1763 "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 sprintf(slotautocfg_prop, "slot%d-autoconfig", 1826 hsp->hs_slot_number); 1827 ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, slotautocfg_prop); 1828 if (hsc_slot_unregister(hsc->slot_table_prop[i].pslotnum) 1829 != 0) { 1830 cmn_err(CE_NOTE, "%s#%d: failed to unregister" 1831 " slot %d\n", ddi_driver_name(dip), 1832 ddi_get_instance(dip), 1833 hsc->slot_table_prop[i].pslotnum); 1834 return (DDI_FAILURE); 1835 } 1836 } 1837 kmem_free(hsc->slot_table_prop, (hsc->slot_table_size * 1838 sizeof (hsc_slot_table_t))); 1839 if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) { 1840 ddi_remove_intr(hsc->dip, 1, hsc->enum_iblock); 1841 hsc->state &= ~HSC_ENUM_ENABLED; 1842 } 1843 mutex_destroy(&hsc->hsc_mutex); 1844 ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP); 1845 hsc->state &= ~(HSC_ATTACHED|HSC_SCB_CONNECTED); 1846 ddi_soft_state_free(hsc_state, instance); 1847 return (DDI_SUCCESS); 1848 } 1849 1850 /* 1851 * The following function is called when the SCSB is hot extracted from 1852 * the system. 1853 */ 1854 int 1855 scsb_hsc_freeze(dev_info_t *dip) 1856 { 1857 hsc_state_t *hsc; 1858 int instance = ddi_get_instance(dip); 1859 int i; 1860 hsc_slot_t *hsp; 1861 1862 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1863 if (hsc == NULL) { 1864 DEBUG2("%s#%d: Soft state NULL", 1865 ddi_driver_name(dip), ddi_get_instance(dip)); 1866 return (DDI_SUCCESS); 1867 } 1868 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1869 return (DDI_SUCCESS); 1870 hsc->state &= ~HSC_SCB_CONNECTED; 1871 1872 for (i = 0; i < hsc->slot_table_size; i++) { 1873 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum); 1874 1875 if (hsp == NULL) { 1876 cmn_err(CE_NOTE, "hsc_freeze: " 1877 " Cannot map slot number %d to a hsc_slot_t", 1878 hsc->slot_table_prop[i].pslotnum); 1879 continue; 1880 } 1881 /* 1882 * Since reset lines are pulled low, lets mark these 1883 * slots and not allow a connect operation. 1884 * Note that we still keep the slot as slot disconnected, 1885 * although it is connected from the hardware standpoint. 1886 * As soon as the SCB is plugged back in, we check these 1887 * states and put the hardware state back to its original 1888 * state. 1889 */ 1890 if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) { 1891 cmn_err(CE_WARN, "%s#%d: Slot %d Now out of Reset!", 1892 ddi_driver_name(hsc->dip), 1893 ddi_get_instance(hsc->dip), 1894 hsp->hs_slot_number); 1895 } 1896 hsp->hs_flags |= HSC_SCB_HOTSWAPPED; 1897 } 1898 1899 return (DDI_SUCCESS); 1900 } 1901 1902 /* 1903 * The following function is called when the SCSB is hot inserted from 1904 * the system. We must update the LED status and set the RST# registers 1905 * again. 1906 */ 1907 int 1908 scsb_hsc_restore(dev_info_t *dip) 1909 { 1910 int i; 1911 hsc_state_t *hsc; 1912 hsc_slot_t *hsp; 1913 int instance = ddi_get_instance(dip); 1914 1915 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1916 if (hsc == NULL) { 1917 DEBUG2("%s#%d: Soft state NULL", 1918 ddi_driver_name(dip), ddi_get_instance(dip)); 1919 return (DDI_SUCCESS); 1920 } 1921 1922 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1923 return (DDI_SUCCESS); 1924 hsc->state |= HSC_SCB_CONNECTED; 1925 for (i = 0; i < hsc->slot_table_size; i++) { 1926 hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum); 1927 1928 if (hsp == NULL) { 1929 cmn_err(CE_NOTE, "%s#%d: hsc_restore: " 1930 " Cannot map slot number %d to a hsc_slot_t", 1931 ddi_driver_name(hsc->dip), 1932 ddi_get_instance(hsc->dip), 1933 hsc->slot_table_prop[i].pslotnum); 1934 continue; 1935 } 1936 if ((hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) && 1937 (hsp->hs_board_configured == B_FALSE)) { 1938 if (scsb_reset_slot(hsp->hs_hpchandle, 1939 hsp->hs_slot_number, 1940 SCSB_RESET_SLOT) != 0) { 1941 cmn_err(CE_WARN, "%s#%d: hsc_restore: " 1942 " Cannot reset disconnected slot %d", 1943 ddi_driver_name(hsc->dip), 1944 ddi_get_instance(hsc->dip), 1945 hsp->hs_slot_number); 1946 } 1947 } 1948 1949 if (scsb_hsc_init_slot_state(hsc, hsp) != DDI_SUCCESS) { 1950 1951 cmn_err(CE_WARN, "%s#%d: hsc_freeze: Cannot init" 1952 " slot%d state", 1953 ddi_driver_name(hsc->dip), 1954 ddi_get_instance(hsc->dip), 1955 hsp->hs_slot_number); 1956 } 1957 hsp->hs_flags &= ~HSC_SCB_HOTSWAPPED; 1958 } 1959 return (DDI_SUCCESS); 1960 } 1961 1962 #ifndef lint 1963 int 1964 scsb_hsc_freeze_check(dev_info_t *dip) 1965 { 1966 hsc_state_t *hsc; 1967 int instance = ddi_get_instance(dip); 1968 1969 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1970 if (hsc == NULL) { 1971 DEBUG2("%s#%d: Soft state NULL", 1972 ddi_driver_name(dip), ddi_get_instance(dip)); 1973 return (DDI_SUCCESS); 1974 } 1975 if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED) 1976 return (DDI_SUCCESS); 1977 return (DDI_SUCCESS); 1978 } 1979 #endif 1980 1981 /* 1982 * update info about Alarm Card insert/remove mechanism. 1983 */ 1984 void 1985 hsc_ac_op(int instance, int pslotnum, int op, void *arg) 1986 { 1987 hsc_slot_t *hsp; 1988 hsc_state_t *hsc; 1989 1990 hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance); 1991 if (hsc == NULL) { 1992 cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Soft State Info", 1993 ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip)); 1994 return; 1995 } 1996 1997 hsp = hsc_find_slot(pslotnum); 1998 if (hsp == NULL) { 1999 cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Slot Info", 2000 ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip)); 2001 return; 2002 } 2003 2004 switch (op) { 2005 case SCSB_HSC_AC_UNCONFIGURE : 2006 /* 2007 * If ENUM# is enabled, then action is pending on 2008 * this slot, just send a event. 2009 */ 2010 if (hsc->state & HSC_ENUM_ENABLED) 2011 hpc_slot_event_notify(hsp->hs_slot_handle, 2012 HPC_EVENT_PROCESS_ENUM, 0); 2013 break; 2014 case SCSB_HSC_AC_GET_SLOT_INFO : 2015 *(hsc_slot_t **)arg = hsp; 2016 break; 2017 default : 2018 break; 2019 } 2020 } 2021 2022 static uint_t 2023 hsc_enum_intr(caddr_t iarg) 2024 { 2025 int rc; 2026 hsc_state_t *hsc = (hsc_state_t *)iarg; 2027 hsc_slot_t *hsp; 2028 2029 DEBUG0("!E!"); 2030 if ((hsc->state & HSC_ATTACHED) == 0) 2031 return (DDI_INTR_UNCLAIMED); 2032 2033 hsp = hsc_find_slot(hsc->slot_table_prop[0].pslotnum); 2034 if (hsp == NULL) /* No slots registered */ 2035 return (DDI_INTR_UNCLAIMED); 2036 2037 /* 2038 * The following must be done to clear interrupt (synchronous event). 2039 * To process the interrupt, we send an asynchronous event. 2040 */ 2041 rc = hpc_slot_event_notify(hsp->hs_slot_handle, 2042 HPC_EVENT_CLEAR_ENUM, 2043 HPC_EVENT_SYNCHRONOUS); 2044 if (rc == HPC_EVENT_UNCLAIMED) { 2045 /* 2046 * possible support for handling insertion of non friendly 2047 * full hotswap boards, otherwise the system hangs due 2048 * to uncleared interrupt bursts. 2049 */ 2050 DEBUG2("!E>counter %d, last op@slot %lx\n", 2051 hsc->hsc_intr_counter, hsc->hsp_last); 2052 hsc->hsc_intr_counter ++; 2053 if (hsc->hsc_intr_counter == scsb_hsc_max_intr_count) { 2054 if (!hsc->hsp_last) { 2055 cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: " 2056 " No Last Board Insertion Info.", 2057 ddi_driver_name(hsc->dip), 2058 ddi_get_instance(hsc->dip)); 2059 hsc->hsc_intr_counter = 0; 2060 return (DDI_INTR_UNCLAIMED); 2061 } 2062 hsp = hsc->hsp_last; 2063 cmn_err(CE_WARN, "%s#%d: Bad (non friendly ?) Board " 2064 "in Slot %d ? Taking it Offline.", 2065 ddi_driver_name(hsc->dip), 2066 ddi_get_instance(hsc->dip), 2067 hsp->hs_slot_number); 2068 /* 2069 * this should put just inserted board back in 2070 * reset, thus deasserting the ENUM# and the 2071 * system hang. 2072 */ 2073 if (scsb_reset_slot(hsp->hs_hpchandle, 2074 hsp->hs_slot_number, 2075 SCSB_RESET_SLOT) == 0) { 2076 /* Enumeration failed on this board */ 2077 hsp->hs_flags |= HSC_ENUM_FAILED; 2078 if (hsp->hs_board_configured == B_TRUE) 2079 cmn_err(CE_WARN, "%s#%d: ALERT! System" 2080 " now in Inconsistent State." 2081 " Halt!", 2082 ddi_driver_name(hsc->dip), 2083 ddi_get_instance(hsc->dip)); 2084 hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, 2085 HPC_FAULT_LED, HPC_LED_ON); 2086 } 2087 hsc->hsc_intr_counter = 0; 2088 } 2089 return (DDI_INTR_UNCLAIMED); 2090 } 2091 hsc->hsc_intr_counter = 0; 2092 /* 2093 * if interrupt success, rc denotes the PCI device number which 2094 * generated the ENUM# interrupt. 2095 */ 2096 hsp = hsc_get_slot_info(hsc, rc); 2097 if (hsp == NULL) { 2098 cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: no slot info for " 2099 "dev %x", ddi_driver_name(hsc->dip), 2100 ddi_get_instance(hsc->dip), rc); 2101 return (DDI_INTR_CLAIMED); /* interrupt already cleared */ 2102 } 2103 /* if this is Alarm Card and if it is busy, dont process event */ 2104 if (hsp->hs_flags & HSC_ALARM_CARD_PRES) { 2105 if (scsb_hsc_ac_op(hsp->hs_hpchandle, hsp->hs_slot_number, 2106 SCSB_HSC_AC_BUSY) == B_TRUE) { 2107 /* 2108 * Busy means we need to inform (envmond)alarmcard.so 2109 * that it should save the AC configuration, stop the 2110 * heartbeat, and shutdown the RSC link. 2111 */ 2112 (void) scsb_hsc_ac_op(hsp->hs_hpchandle, 2113 hsp->hs_slot_number, 2114 SCSB_HSC_AC_REMOVAL_ALERT); 2115 return (DDI_INTR_CLAIMED); 2116 } 2117 } 2118 /* 2119 * If SCB was swapped out, dont process ENUM#. We put this slot 2120 * back in reset after SCB is inserted. 2121 */ 2122 if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) && 2123 (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED)) 2124 return (DDI_INTR_CLAIMED); 2125 2126 hpc_slot_event_notify(hsp->hs_slot_handle, HPC_EVENT_PROCESS_ENUM, 0); 2127 return (DDI_INTR_CLAIMED); 2128 } 2129 /* 2130 * A routine to convert a number (represented as a string) to 2131 * the integer value it represents. 2132 */ 2133 2134 static int 2135 isdigit(int ch) 2136 { 2137 return (ch >= '0' && ch <= '9'); 2138 } 2139 2140 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') 2141 #define bad(val) (val == NULL || !isdigit(*val)) 2142 2143 static int 2144 atoi(const char *p) 2145 { 2146 int n; 2147 int c, neg = 0; 2148 2149 if (!isdigit(c = *p)) { 2150 while (isspace(c)) 2151 c = *++p; 2152 switch (c) { 2153 case '-': 2154 neg++; 2155 /* FALLTHROUGH */ 2156 case '+': 2157 c = *++p; 2158 } 2159 if (!isdigit(c)) 2160 return (0); 2161 } 2162 for (n = '0' - c; isdigit(c = *++p); ) { 2163 n *= 10; /* two steps to avoid unnecessary overflow */ 2164 n += '0' - c; /* accum neg to avoid surprises at MAX */ 2165 } 2166 return (neg ? n : -n); 2167 } 2168