1 /* 2 * Standard Hot Plug Controller Driver 3 * 4 * Copyright (C) 1995,2001 Compaq Computer Corporation 5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) 6 * Copyright (C) 2001 IBM Corp. 7 * Copyright (C) 2003-2004 Intel Corporation 8 * 9 * All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or (at 14 * your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 19 * NON INFRINGEMENT. See the GNU General Public License for more 20 * details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * 26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> 27 * 28 */ 29 30 #include <linux/module.h> 31 #include <linux/kernel.h> 32 #include <linux/types.h> 33 #include <linux/slab.h> 34 #include <linux/pci.h> 35 #include "../pci.h" 36 #include "shpchp.h" 37 38 static void interrupt_event_handler(struct work_struct *work); 39 static int shpchp_enable_slot(struct slot *p_slot); 40 static int shpchp_disable_slot(struct slot *p_slot); 41 42 static int queue_interrupt_event(struct slot *p_slot, u32 event_type) 43 { 44 struct event_info *info; 45 46 info = kmalloc(sizeof(*info), GFP_ATOMIC); 47 if (!info) 48 return -ENOMEM; 49 50 info->event_type = event_type; 51 info->p_slot = p_slot; 52 INIT_WORK(&info->work, interrupt_event_handler); 53 54 queue_work(shpchp_wq, &info->work); 55 56 return 0; 57 } 58 59 u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl) 60 { 61 struct slot *p_slot; 62 u32 event_type; 63 64 /* Attention Button Change */ 65 ctrl_dbg(ctrl, "Attention button interrupt received\n"); 66 67 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 68 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 69 70 /* 71 * Button pressed - See if need to TAKE ACTION!!! 72 */ 73 ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot)); 74 event_type = INT_BUTTON_PRESS; 75 76 queue_interrupt_event(p_slot, event_type); 77 78 return 0; 79 80 } 81 82 u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl) 83 { 84 struct slot *p_slot; 85 u8 getstatus; 86 u32 event_type; 87 88 /* Switch Change */ 89 ctrl_dbg(ctrl, "Switch interrupt received\n"); 90 91 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 92 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 93 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 94 ctrl_dbg(ctrl, "Card present %x Power status %x\n", 95 p_slot->presence_save, p_slot->pwr_save); 96 97 if (getstatus) { 98 /* 99 * Switch opened 100 */ 101 ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot)); 102 event_type = INT_SWITCH_OPEN; 103 if (p_slot->pwr_save && p_slot->presence_save) { 104 event_type = INT_POWER_FAULT; 105 ctrl_err(ctrl, "Surprise Removal of card\n"); 106 } 107 } else { 108 /* 109 * Switch closed 110 */ 111 ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot)); 112 event_type = INT_SWITCH_CLOSE; 113 } 114 115 queue_interrupt_event(p_slot, event_type); 116 117 return 1; 118 } 119 120 u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl) 121 { 122 struct slot *p_slot; 123 u32 event_type; 124 125 /* Presence Change */ 126 ctrl_dbg(ctrl, "Presence/Notify input change\n"); 127 128 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 129 130 /* 131 * Save the presence state 132 */ 133 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 134 if (p_slot->presence_save) { 135 /* 136 * Card Present 137 */ 138 ctrl_info(ctrl, "Card present on Slot(%s)\n", 139 slot_name(p_slot)); 140 event_type = INT_PRESENCE_ON; 141 } else { 142 /* 143 * Not Present 144 */ 145 ctrl_info(ctrl, "Card not present on Slot(%s)\n", 146 slot_name(p_slot)); 147 event_type = INT_PRESENCE_OFF; 148 } 149 150 queue_interrupt_event(p_slot, event_type); 151 152 return 1; 153 } 154 155 u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl) 156 { 157 struct slot *p_slot; 158 u32 event_type; 159 160 /* Power fault */ 161 ctrl_dbg(ctrl, "Power fault interrupt received\n"); 162 163 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 164 165 if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { 166 /* 167 * Power fault Cleared 168 */ 169 ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n", 170 slot_name(p_slot)); 171 p_slot->status = 0x00; 172 event_type = INT_POWER_FAULT_CLEAR; 173 } else { 174 /* 175 * Power fault 176 */ 177 ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot)); 178 event_type = INT_POWER_FAULT; 179 /* set power fault status for this board */ 180 p_slot->status = 0xFF; 181 ctrl_info(ctrl, "Power fault bit %x set\n", hp_slot); 182 } 183 184 queue_interrupt_event(p_slot, event_type); 185 186 return 1; 187 } 188 189 /* The following routines constitute the bulk of the 190 hotplug controller logic 191 */ 192 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, 193 enum pci_bus_speed speed) 194 { 195 int rc = 0; 196 197 ctrl_dbg(ctrl, "Change speed to %d\n", speed); 198 if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { 199 ctrl_err(ctrl, "%s: Issue of set bus speed mode command " 200 "failed\n", __func__); 201 return WRONG_BUS_FREQUENCY; 202 } 203 return rc; 204 } 205 206 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, 207 u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, 208 enum pci_bus_speed msp) 209 { 210 int rc = 0; 211 212 /* 213 * If other slots on the same bus are occupied, we cannot 214 * change the bus speed. 215 */ 216 if (flag) { 217 if (asp < bsp) { 218 ctrl_err(ctrl, "Speed of bus %x and adapter %x " 219 "mismatch\n", bsp, asp); 220 rc = WRONG_BUS_FREQUENCY; 221 } 222 return rc; 223 } 224 225 if (asp < msp) { 226 if (bsp != asp) 227 rc = change_bus_speed(ctrl, pslot, asp); 228 } else { 229 if (bsp != msp) 230 rc = change_bus_speed(ctrl, pslot, msp); 231 } 232 return rc; 233 } 234 235 /** 236 * board_added - Called after a board has been added to the system. 237 * @p_slot: target &slot 238 * 239 * Turns power on for the board. 240 * Configures board. 241 */ 242 static int board_added(struct slot *p_slot) 243 { 244 u8 hp_slot; 245 u8 slots_not_empty = 0; 246 int rc = 0; 247 enum pci_bus_speed asp, bsp, msp; 248 struct controller *ctrl = p_slot->ctrl; 249 struct pci_bus *parent = ctrl->pci_dev->subordinate; 250 251 hp_slot = p_slot->device - ctrl->slot_device_offset; 252 253 ctrl_dbg(ctrl, 254 "%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", 255 __func__, p_slot->device, ctrl->slot_device_offset, hp_slot); 256 257 /* Power on slot without connecting to bus */ 258 rc = p_slot->hpc_ops->power_on_slot(p_slot); 259 if (rc) { 260 ctrl_err(ctrl, "Failed to power on slot\n"); 261 return -1; 262 } 263 264 if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { 265 if (slots_not_empty) 266 return WRONG_BUS_FREQUENCY; 267 268 if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { 269 ctrl_err(ctrl, "%s: Issue of set bus speed mode command" 270 " failed\n", __func__); 271 return WRONG_BUS_FREQUENCY; 272 } 273 274 /* turn on board, blink green LED, turn off Amber LED */ 275 if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { 276 ctrl_err(ctrl, "Issue of Slot Enable command failed\n"); 277 return rc; 278 } 279 } 280 281 rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); 282 if (rc) { 283 ctrl_err(ctrl, "Can't get adapter speed or " 284 "bus mode mismatch\n"); 285 return WRONG_BUS_FREQUENCY; 286 } 287 288 bsp = ctrl->pci_dev->bus->cur_bus_speed; 289 msp = ctrl->pci_dev->bus->max_bus_speed; 290 291 /* Check if there are other slots or devices on the same bus */ 292 if (!list_empty(&ctrl->pci_dev->subordinate->devices)) 293 slots_not_empty = 1; 294 295 ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d," 296 " max_bus_speed %d\n", __func__, slots_not_empty, asp, 297 bsp, msp); 298 299 rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp); 300 if (rc) 301 return rc; 302 303 /* turn on board, blink green LED, turn off Amber LED */ 304 if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { 305 ctrl_err(ctrl, "Issue of Slot Enable command failed\n"); 306 return rc; 307 } 308 309 /* Wait for ~1 second */ 310 msleep(1000); 311 312 ctrl_dbg(ctrl, "%s: slot status = %x\n", __func__, p_slot->status); 313 /* Check for a power fault */ 314 if (p_slot->status == 0xFF) { 315 /* power fault occurred, but it was benign */ 316 ctrl_dbg(ctrl, "%s: Power fault\n", __func__); 317 rc = POWER_FAILURE; 318 p_slot->status = 0; 319 goto err_exit; 320 } 321 322 if (shpchp_configure_device(p_slot)) { 323 ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n", 324 pci_domain_nr(parent), p_slot->bus, p_slot->device); 325 goto err_exit; 326 } 327 328 p_slot->status = 0; 329 p_slot->is_a_board = 0x01; 330 p_slot->pwr_save = 1; 331 332 p_slot->hpc_ops->green_led_on(p_slot); 333 334 return 0; 335 336 err_exit: 337 /* turn off slot, turn on Amber LED, turn off Green LED */ 338 rc = p_slot->hpc_ops->slot_disable(p_slot); 339 if (rc) { 340 ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n", 341 __func__); 342 return rc; 343 } 344 345 return(rc); 346 } 347 348 349 /** 350 * remove_board - Turns off slot and LEDs 351 * @p_slot: target &slot 352 */ 353 static int remove_board(struct slot *p_slot) 354 { 355 struct controller *ctrl = p_slot->ctrl; 356 u8 hp_slot; 357 int rc; 358 359 if (shpchp_unconfigure_device(p_slot)) 360 return(1); 361 362 hp_slot = p_slot->device - ctrl->slot_device_offset; 363 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 364 365 ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot); 366 367 /* Change status to shutdown */ 368 if (p_slot->is_a_board) 369 p_slot->status = 0x01; 370 371 /* turn off slot, turn on Amber LED, turn off Green LED */ 372 rc = p_slot->hpc_ops->slot_disable(p_slot); 373 if (rc) { 374 ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n", 375 __func__); 376 return rc; 377 } 378 379 rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); 380 if (rc) { 381 ctrl_err(ctrl, "Issue of Set Attention command failed\n"); 382 return rc; 383 } 384 385 p_slot->pwr_save = 0; 386 p_slot->is_a_board = 0; 387 388 return 0; 389 } 390 391 392 struct pushbutton_work_info { 393 struct slot *p_slot; 394 struct work_struct work; 395 }; 396 397 /** 398 * shpchp_pushbutton_thread - handle pushbutton events 399 * @work: &struct work_struct to be handled 400 * 401 * Scheduled procedure to handle blocking stuff for the pushbuttons. 402 * Handles all pending events and exits. 403 */ 404 static void shpchp_pushbutton_thread(struct work_struct *work) 405 { 406 struct pushbutton_work_info *info = 407 container_of(work, struct pushbutton_work_info, work); 408 struct slot *p_slot = info->p_slot; 409 410 mutex_lock(&p_slot->lock); 411 switch (p_slot->state) { 412 case POWEROFF_STATE: 413 mutex_unlock(&p_slot->lock); 414 shpchp_disable_slot(p_slot); 415 mutex_lock(&p_slot->lock); 416 p_slot->state = STATIC_STATE; 417 break; 418 case POWERON_STATE: 419 mutex_unlock(&p_slot->lock); 420 if (shpchp_enable_slot(p_slot)) 421 p_slot->hpc_ops->green_led_off(p_slot); 422 mutex_lock(&p_slot->lock); 423 p_slot->state = STATIC_STATE; 424 break; 425 default: 426 break; 427 } 428 mutex_unlock(&p_slot->lock); 429 430 kfree(info); 431 } 432 433 void shpchp_queue_pushbutton_work(struct work_struct *work) 434 { 435 struct slot *p_slot = container_of(work, struct slot, work.work); 436 struct pushbutton_work_info *info; 437 438 info = kmalloc(sizeof(*info), GFP_KERNEL); 439 if (!info) { 440 ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", 441 __func__); 442 return; 443 } 444 info->p_slot = p_slot; 445 INIT_WORK(&info->work, shpchp_pushbutton_thread); 446 447 mutex_lock(&p_slot->lock); 448 switch (p_slot->state) { 449 case BLINKINGOFF_STATE: 450 p_slot->state = POWEROFF_STATE; 451 break; 452 case BLINKINGON_STATE: 453 p_slot->state = POWERON_STATE; 454 break; 455 default: 456 kfree(info); 457 goto out; 458 } 459 queue_work(shpchp_ordered_wq, &info->work); 460 out: 461 mutex_unlock(&p_slot->lock); 462 } 463 464 static int update_slot_info (struct slot *slot) 465 { 466 struct hotplug_slot_info *info; 467 int result; 468 469 info = kmalloc(sizeof(*info), GFP_KERNEL); 470 if (!info) 471 return -ENOMEM; 472 473 slot->hpc_ops->get_power_status(slot, &(info->power_status)); 474 slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); 475 slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); 476 slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); 477 478 result = pci_hp_change_slot_info(slot->hotplug_slot, info); 479 kfree (info); 480 return result; 481 } 482 483 /* 484 * Note: This function must be called with slot->lock held 485 */ 486 static void handle_button_press_event(struct slot *p_slot) 487 { 488 u8 getstatus; 489 struct controller *ctrl = p_slot->ctrl; 490 491 switch (p_slot->state) { 492 case STATIC_STATE: 493 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 494 if (getstatus) { 495 p_slot->state = BLINKINGOFF_STATE; 496 ctrl_info(ctrl, "PCI slot #%s - powering off due to " 497 "button press.\n", slot_name(p_slot)); 498 } else { 499 p_slot->state = BLINKINGON_STATE; 500 ctrl_info(ctrl, "PCI slot #%s - powering on due to " 501 "button press.\n", slot_name(p_slot)); 502 } 503 /* blink green LED and turn off amber */ 504 p_slot->hpc_ops->green_led_blink(p_slot); 505 p_slot->hpc_ops->set_attention_status(p_slot, 0); 506 507 queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ); 508 break; 509 case BLINKINGOFF_STATE: 510 case BLINKINGON_STATE: 511 /* 512 * Cancel if we are still blinking; this means that we 513 * press the attention again before the 5 sec. limit 514 * expires to cancel hot-add or hot-remove 515 */ 516 ctrl_info(ctrl, "Button cancel on Slot(%s)\n", 517 slot_name(p_slot)); 518 cancel_delayed_work(&p_slot->work); 519 if (p_slot->state == BLINKINGOFF_STATE) 520 p_slot->hpc_ops->green_led_on(p_slot); 521 else 522 p_slot->hpc_ops->green_led_off(p_slot); 523 p_slot->hpc_ops->set_attention_status(p_slot, 0); 524 ctrl_info(ctrl, "PCI slot #%s - action canceled due to " 525 "button press\n", slot_name(p_slot)); 526 p_slot->state = STATIC_STATE; 527 break; 528 case POWEROFF_STATE: 529 case POWERON_STATE: 530 /* 531 * Ignore if the slot is on power-on or power-off state; 532 * this means that the previous attention button action 533 * to hot-add or hot-remove is undergoing 534 */ 535 ctrl_info(ctrl, "Button ignore on Slot(%s)\n", 536 slot_name(p_slot)); 537 update_slot_info(p_slot); 538 break; 539 default: 540 ctrl_warn(ctrl, "Not a valid state\n"); 541 break; 542 } 543 } 544 545 static void interrupt_event_handler(struct work_struct *work) 546 { 547 struct event_info *info = container_of(work, struct event_info, work); 548 struct slot *p_slot = info->p_slot; 549 550 mutex_lock(&p_slot->lock); 551 switch (info->event_type) { 552 case INT_BUTTON_PRESS: 553 handle_button_press_event(p_slot); 554 break; 555 case INT_POWER_FAULT: 556 ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__); 557 p_slot->hpc_ops->set_attention_status(p_slot, 1); 558 p_slot->hpc_ops->green_led_off(p_slot); 559 break; 560 default: 561 update_slot_info(p_slot); 562 break; 563 } 564 mutex_unlock(&p_slot->lock); 565 566 kfree(info); 567 } 568 569 570 static int shpchp_enable_slot (struct slot *p_slot) 571 { 572 u8 getstatus = 0; 573 int rc, retval = -ENODEV; 574 struct controller *ctrl = p_slot->ctrl; 575 576 /* Check to see if (latch closed, card present, power off) */ 577 mutex_lock(&p_slot->ctrl->crit_sect); 578 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 579 if (rc || !getstatus) { 580 ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); 581 goto out; 582 } 583 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 584 if (rc || getstatus) { 585 ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot)); 586 goto out; 587 } 588 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 589 if (rc || getstatus) { 590 ctrl_info(ctrl, "Already enabled on slot(%s)\n", 591 slot_name(p_slot)); 592 goto out; 593 } 594 595 p_slot->is_a_board = 1; 596 597 /* We have to save the presence info for these slots */ 598 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 599 p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); 600 ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save); 601 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 602 603 if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) || 604 (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)) 605 && p_slot->ctrl->num_slots == 1) { 606 /* handle amd pogo errata; this must be done before enable */ 607 amd_pogo_errata_save_misc_reg(p_slot); 608 retval = board_added(p_slot); 609 /* handle amd pogo errata; this must be done after enable */ 610 amd_pogo_errata_restore_misc_reg(p_slot); 611 } else 612 retval = board_added(p_slot); 613 614 if (retval) { 615 p_slot->hpc_ops->get_adapter_status(p_slot, 616 &(p_slot->presence_save)); 617 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 618 } 619 620 update_slot_info(p_slot); 621 out: 622 mutex_unlock(&p_slot->ctrl->crit_sect); 623 return retval; 624 } 625 626 627 static int shpchp_disable_slot (struct slot *p_slot) 628 { 629 u8 getstatus = 0; 630 int rc, retval = -ENODEV; 631 struct controller *ctrl = p_slot->ctrl; 632 633 if (!p_slot->ctrl) 634 return -ENODEV; 635 636 /* Check to see if (latch closed, card present, power on) */ 637 mutex_lock(&p_slot->ctrl->crit_sect); 638 639 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 640 if (rc || !getstatus) { 641 ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); 642 goto out; 643 } 644 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 645 if (rc || getstatus) { 646 ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot)); 647 goto out; 648 } 649 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 650 if (rc || !getstatus) { 651 ctrl_info(ctrl, "Already disabled on slot(%s)\n", 652 slot_name(p_slot)); 653 goto out; 654 } 655 656 retval = remove_board(p_slot); 657 update_slot_info(p_slot); 658 out: 659 mutex_unlock(&p_slot->ctrl->crit_sect); 660 return retval; 661 } 662 663 int shpchp_sysfs_enable_slot(struct slot *p_slot) 664 { 665 int retval = -ENODEV; 666 struct controller *ctrl = p_slot->ctrl; 667 668 mutex_lock(&p_slot->lock); 669 switch (p_slot->state) { 670 case BLINKINGON_STATE: 671 cancel_delayed_work(&p_slot->work); 672 case STATIC_STATE: 673 p_slot->state = POWERON_STATE; 674 mutex_unlock(&p_slot->lock); 675 retval = shpchp_enable_slot(p_slot); 676 mutex_lock(&p_slot->lock); 677 p_slot->state = STATIC_STATE; 678 break; 679 case POWERON_STATE: 680 ctrl_info(ctrl, "Slot %s is already in powering on state\n", 681 slot_name(p_slot)); 682 break; 683 case BLINKINGOFF_STATE: 684 case POWEROFF_STATE: 685 ctrl_info(ctrl, "Already enabled on slot %s\n", 686 slot_name(p_slot)); 687 break; 688 default: 689 ctrl_err(ctrl, "Not a valid state on slot %s\n", 690 slot_name(p_slot)); 691 break; 692 } 693 mutex_unlock(&p_slot->lock); 694 695 return retval; 696 } 697 698 int shpchp_sysfs_disable_slot(struct slot *p_slot) 699 { 700 int retval = -ENODEV; 701 struct controller *ctrl = p_slot->ctrl; 702 703 mutex_lock(&p_slot->lock); 704 switch (p_slot->state) { 705 case BLINKINGOFF_STATE: 706 cancel_delayed_work(&p_slot->work); 707 case STATIC_STATE: 708 p_slot->state = POWEROFF_STATE; 709 mutex_unlock(&p_slot->lock); 710 retval = shpchp_disable_slot(p_slot); 711 mutex_lock(&p_slot->lock); 712 p_slot->state = STATIC_STATE; 713 break; 714 case POWEROFF_STATE: 715 ctrl_info(ctrl, "Slot %s is already in powering off state\n", 716 slot_name(p_slot)); 717 break; 718 case BLINKINGON_STATE: 719 case POWERON_STATE: 720 ctrl_info(ctrl, "Already disabled on slot %s\n", 721 slot_name(p_slot)); 722 break; 723 default: 724 ctrl_err(ctrl, "Not a valid state on slot %s\n", 725 slot_name(p_slot)); 726 break; 727 } 728 mutex_unlock(&p_slot->lock); 729 730 return retval; 731 } 732