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(p_slot->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 rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed); 199 if (rc) { 200 ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n", 201 __func__); 202 return WRONG_BUS_FREQUENCY; 203 } 204 return rc; 205 } 206 207 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, 208 u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, 209 enum pci_bus_speed msp) 210 { 211 int rc = 0; 212 213 /* 214 * If other slots on the same bus are occupied, we cannot 215 * change the bus speed. 216 */ 217 if (flag) { 218 if (asp < bsp) { 219 ctrl_err(ctrl, "Speed of bus %x and adapter %x mismatch\n", 220 bsp, asp); 221 rc = WRONG_BUS_FREQUENCY; 222 } 223 return rc; 224 } 225 226 if (asp < msp) { 227 if (bsp != asp) 228 rc = change_bus_speed(ctrl, pslot, asp); 229 } else { 230 if (bsp != msp) 231 rc = change_bus_speed(ctrl, pslot, msp); 232 } 233 return rc; 234 } 235 236 /** 237 * board_added - Called after a board has been added to the system. 238 * @p_slot: target &slot 239 * 240 * Turns power on for the board. 241 * Configures board. 242 */ 243 static int board_added(struct slot *p_slot) 244 { 245 u8 hp_slot; 246 u8 slots_not_empty = 0; 247 int rc = 0; 248 enum pci_bus_speed asp, bsp, msp; 249 struct controller *ctrl = p_slot->ctrl; 250 struct pci_bus *parent = ctrl->pci_dev->subordinate; 251 252 hp_slot = p_slot->device - ctrl->slot_device_offset; 253 254 ctrl_dbg(ctrl, "%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 rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz); 266 if (rc) { 267 ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n", 268 __func__); 269 return WRONG_BUS_FREQUENCY; 270 } 271 272 /* turn on board, blink green LED, turn off Amber LED */ 273 rc = p_slot->hpc_ops->slot_enable(p_slot); 274 if (rc) { 275 ctrl_err(ctrl, "Issue of Slot Enable command failed\n"); 276 return rc; 277 } 278 } 279 280 rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); 281 if (rc) { 282 ctrl_err(ctrl, "Can't get adapter speed or bus mode mismatch\n"); 283 return WRONG_BUS_FREQUENCY; 284 } 285 286 bsp = ctrl->pci_dev->subordinate->cur_bus_speed; 287 msp = ctrl->pci_dev->subordinate->max_bus_speed; 288 289 /* Check if there are other slots or devices on the same bus */ 290 if (!list_empty(&ctrl->pci_dev->subordinate->devices)) 291 slots_not_empty = 1; 292 293 ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, max_bus_speed %d\n", 294 __func__, slots_not_empty, asp, 295 bsp, msp); 296 297 rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp); 298 if (rc) 299 return rc; 300 301 /* turn on board, blink green LED, turn off Amber LED */ 302 rc = p_slot->hpc_ops->slot_enable(p_slot); 303 if (rc) { 304 ctrl_err(ctrl, "Issue of Slot Enable command failed\n"); 305 return rc; 306 } 307 308 /* Wait for ~1 second */ 309 msleep(1000); 310 311 ctrl_dbg(ctrl, "%s: slot status = %x\n", __func__, p_slot->status); 312 /* Check for a power fault */ 313 if (p_slot->status == 0xFF) { 314 /* power fault occurred, but it was benign */ 315 ctrl_dbg(ctrl, "%s: Power fault\n", __func__); 316 rc = POWER_FAILURE; 317 p_slot->status = 0; 318 goto err_exit; 319 } 320 321 if (shpchp_configure_device(p_slot)) { 322 ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n", 323 pci_domain_nr(parent), p_slot->bus, p_slot->device); 324 goto err_exit; 325 } 326 327 p_slot->status = 0; 328 p_slot->is_a_board = 0x01; 329 p_slot->pwr_save = 1; 330 331 p_slot->hpc_ops->green_led_on(p_slot); 332 333 return 0; 334 335 err_exit: 336 /* turn off slot, turn on Amber LED, turn off Green LED */ 337 rc = p_slot->hpc_ops->slot_disable(p_slot); 338 if (rc) { 339 ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n", 340 __func__); 341 return rc; 342 } 343 344 return(rc); 345 } 346 347 348 /** 349 * remove_board - Turns off slot and LEDs 350 * @p_slot: target &slot 351 */ 352 static int remove_board(struct slot *p_slot) 353 { 354 struct controller *ctrl = p_slot->ctrl; 355 u8 hp_slot; 356 int rc; 357 358 if (shpchp_unconfigure_device(p_slot)) 359 return(1); 360 361 hp_slot = p_slot->device - ctrl->slot_device_offset; 362 p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); 363 364 ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot); 365 366 /* Change status to shutdown */ 367 if (p_slot->is_a_board) 368 p_slot->status = 0x01; 369 370 /* turn off slot, turn on Amber LED, turn off Green LED */ 371 rc = p_slot->hpc_ops->slot_disable(p_slot); 372 if (rc) { 373 ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n", 374 __func__); 375 return rc; 376 } 377 378 rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); 379 if (rc) { 380 ctrl_err(ctrl, "Issue of Set Attention command failed\n"); 381 return rc; 382 } 383 384 p_slot->pwr_save = 0; 385 p_slot->is_a_board = 0; 386 387 return 0; 388 } 389 390 391 struct pushbutton_work_info { 392 struct slot *p_slot; 393 struct work_struct work; 394 }; 395 396 /** 397 * shpchp_pushbutton_thread - handle pushbutton events 398 * @work: &struct work_struct to be handled 399 * 400 * Scheduled procedure to handle blocking stuff for the pushbuttons. 401 * Handles all pending events and exits. 402 */ 403 static void shpchp_pushbutton_thread(struct work_struct *work) 404 { 405 struct pushbutton_work_info *info = 406 container_of(work, struct pushbutton_work_info, work); 407 struct slot *p_slot = info->p_slot; 408 409 mutex_lock(&p_slot->lock); 410 switch (p_slot->state) { 411 case POWEROFF_STATE: 412 mutex_unlock(&p_slot->lock); 413 shpchp_disable_slot(p_slot); 414 mutex_lock(&p_slot->lock); 415 p_slot->state = STATIC_STATE; 416 break; 417 case POWERON_STATE: 418 mutex_unlock(&p_slot->lock); 419 if (shpchp_enable_slot(p_slot)) 420 p_slot->hpc_ops->green_led_off(p_slot); 421 mutex_lock(&p_slot->lock); 422 p_slot->state = STATIC_STATE; 423 break; 424 default: 425 break; 426 } 427 mutex_unlock(&p_slot->lock); 428 429 kfree(info); 430 } 431 432 void shpchp_queue_pushbutton_work(struct work_struct *work) 433 { 434 struct slot *p_slot = container_of(work, struct slot, work.work); 435 struct pushbutton_work_info *info; 436 437 info = kmalloc(sizeof(*info), GFP_KERNEL); 438 if (!info) { 439 ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", 440 __func__); 441 return; 442 } 443 info->p_slot = p_slot; 444 INIT_WORK(&info->work, shpchp_pushbutton_thread); 445 446 mutex_lock(&p_slot->lock); 447 switch (p_slot->state) { 448 case BLINKINGOFF_STATE: 449 p_slot->state = POWEROFF_STATE; 450 break; 451 case BLINKINGON_STATE: 452 p_slot->state = POWERON_STATE; 453 break; 454 default: 455 kfree(info); 456 goto out; 457 } 458 queue_work(p_slot->wq, &info->work); 459 out: 460 mutex_unlock(&p_slot->lock); 461 } 462 463 static int update_slot_info (struct slot *slot) 464 { 465 struct hotplug_slot_info *info; 466 int result; 467 468 info = kmalloc(sizeof(*info), GFP_KERNEL); 469 if (!info) 470 return -ENOMEM; 471 472 slot->hpc_ops->get_power_status(slot, &(info->power_status)); 473 slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); 474 slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); 475 slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); 476 477 result = pci_hp_change_slot_info(slot->hotplug_slot, info); 478 kfree (info); 479 return result; 480 } 481 482 /* 483 * Note: This function must be called with slot->lock held 484 */ 485 static void handle_button_press_event(struct slot *p_slot) 486 { 487 u8 getstatus; 488 struct controller *ctrl = p_slot->ctrl; 489 490 switch (p_slot->state) { 491 case STATIC_STATE: 492 p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 493 if (getstatus) { 494 p_slot->state = BLINKINGOFF_STATE; 495 ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n", 496 slot_name(p_slot)); 497 } else { 498 p_slot->state = BLINKINGON_STATE; 499 ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n", 500 slot_name(p_slot)); 501 } 502 /* blink green LED and turn off amber */ 503 p_slot->hpc_ops->green_led_blink(p_slot); 504 p_slot->hpc_ops->set_attention_status(p_slot, 0); 505 506 queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); 507 break; 508 case BLINKINGOFF_STATE: 509 case BLINKINGON_STATE: 510 /* 511 * Cancel if we are still blinking; this means that we 512 * press the attention again before the 5 sec. limit 513 * expires to cancel hot-add or hot-remove 514 */ 515 ctrl_info(ctrl, "Button cancel on Slot(%s)\n", 516 slot_name(p_slot)); 517 cancel_delayed_work(&p_slot->work); 518 if (p_slot->state == BLINKINGOFF_STATE) 519 p_slot->hpc_ops->green_led_on(p_slot); 520 else 521 p_slot->hpc_ops->green_led_off(p_slot); 522 p_slot->hpc_ops->set_attention_status(p_slot, 0); 523 ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n", 524 slot_name(p_slot)); 525 p_slot->state = STATIC_STATE; 526 break; 527 case POWEROFF_STATE: 528 case POWERON_STATE: 529 /* 530 * Ignore if the slot is on power-on or power-off state; 531 * this means that the previous attention button action 532 * to hot-add or hot-remove is undergoing 533 */ 534 ctrl_info(ctrl, "Button ignore on Slot(%s)\n", 535 slot_name(p_slot)); 536 update_slot_info(p_slot); 537 break; 538 default: 539 ctrl_warn(ctrl, "Not a valid state\n"); 540 break; 541 } 542 } 543 544 static void interrupt_event_handler(struct work_struct *work) 545 { 546 struct event_info *info = container_of(work, struct event_info, work); 547 struct slot *p_slot = info->p_slot; 548 549 mutex_lock(&p_slot->lock); 550 switch (info->event_type) { 551 case INT_BUTTON_PRESS: 552 handle_button_press_event(p_slot); 553 break; 554 case INT_POWER_FAULT: 555 ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__); 556 p_slot->hpc_ops->set_attention_status(p_slot, 1); 557 p_slot->hpc_ops->green_led_off(p_slot); 558 break; 559 default: 560 update_slot_info(p_slot); 561 break; 562 } 563 mutex_unlock(&p_slot->lock); 564 565 kfree(info); 566 } 567 568 569 static int shpchp_enable_slot (struct slot *p_slot) 570 { 571 u8 getstatus = 0; 572 int rc, retval = -ENODEV; 573 struct controller *ctrl = p_slot->ctrl; 574 575 /* Check to see if (latch closed, card present, power off) */ 576 mutex_lock(&p_slot->ctrl->crit_sect); 577 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 578 if (rc || !getstatus) { 579 ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); 580 goto out; 581 } 582 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 583 if (rc || getstatus) { 584 ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot)); 585 goto out; 586 } 587 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 588 if (rc || getstatus) { 589 ctrl_info(ctrl, "Already enabled on slot(%s)\n", 590 slot_name(p_slot)); 591 goto out; 592 } 593 594 p_slot->is_a_board = 1; 595 596 /* We have to save the presence info for these slots */ 597 p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); 598 p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save)); 599 ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save); 600 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 601 602 if (((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) || 603 (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)) 604 && p_slot->ctrl->num_slots == 1) { 605 /* handle amd pogo errata; this must be done before enable */ 606 amd_pogo_errata_save_misc_reg(p_slot); 607 retval = board_added(p_slot); 608 /* handle amd pogo errata; this must be done after enable */ 609 amd_pogo_errata_restore_misc_reg(p_slot); 610 } else 611 retval = board_added(p_slot); 612 613 if (retval) { 614 p_slot->hpc_ops->get_adapter_status(p_slot, 615 &(p_slot->presence_save)); 616 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 617 } 618 619 update_slot_info(p_slot); 620 out: 621 mutex_unlock(&p_slot->ctrl->crit_sect); 622 return retval; 623 } 624 625 626 static int shpchp_disable_slot (struct slot *p_slot) 627 { 628 u8 getstatus = 0; 629 int rc, retval = -ENODEV; 630 struct controller *ctrl = p_slot->ctrl; 631 632 if (!p_slot->ctrl) 633 return -ENODEV; 634 635 /* Check to see if (latch closed, card present, power on) */ 636 mutex_lock(&p_slot->ctrl->crit_sect); 637 638 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 639 if (rc || !getstatus) { 640 ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); 641 goto out; 642 } 643 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 644 if (rc || getstatus) { 645 ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot)); 646 goto out; 647 } 648 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 649 if (rc || !getstatus) { 650 ctrl_info(ctrl, "Already disabled on slot(%s)\n", 651 slot_name(p_slot)); 652 goto out; 653 } 654 655 retval = remove_board(p_slot); 656 update_slot_info(p_slot); 657 out: 658 mutex_unlock(&p_slot->ctrl->crit_sect); 659 return retval; 660 } 661 662 int shpchp_sysfs_enable_slot(struct slot *p_slot) 663 { 664 int retval = -ENODEV; 665 struct controller *ctrl = p_slot->ctrl; 666 667 mutex_lock(&p_slot->lock); 668 switch (p_slot->state) { 669 case BLINKINGON_STATE: 670 cancel_delayed_work(&p_slot->work); 671 case STATIC_STATE: 672 p_slot->state = POWERON_STATE; 673 mutex_unlock(&p_slot->lock); 674 retval = shpchp_enable_slot(p_slot); 675 mutex_lock(&p_slot->lock); 676 p_slot->state = STATIC_STATE; 677 break; 678 case POWERON_STATE: 679 ctrl_info(ctrl, "Slot %s is already in powering on state\n", 680 slot_name(p_slot)); 681 break; 682 case BLINKINGOFF_STATE: 683 case POWEROFF_STATE: 684 ctrl_info(ctrl, "Already enabled on slot %s\n", 685 slot_name(p_slot)); 686 break; 687 default: 688 ctrl_err(ctrl, "Not a valid state on slot %s\n", 689 slot_name(p_slot)); 690 break; 691 } 692 mutex_unlock(&p_slot->lock); 693 694 return retval; 695 } 696 697 int shpchp_sysfs_disable_slot(struct slot *p_slot) 698 { 699 int retval = -ENODEV; 700 struct controller *ctrl = p_slot->ctrl; 701 702 mutex_lock(&p_slot->lock); 703 switch (p_slot->state) { 704 case BLINKINGOFF_STATE: 705 cancel_delayed_work(&p_slot->work); 706 case STATIC_STATE: 707 p_slot->state = POWEROFF_STATE; 708 mutex_unlock(&p_slot->lock); 709 retval = shpchp_disable_slot(p_slot); 710 mutex_lock(&p_slot->lock); 711 p_slot->state = STATIC_STATE; 712 break; 713 case POWEROFF_STATE: 714 ctrl_info(ctrl, "Slot %s is already in powering off state\n", 715 slot_name(p_slot)); 716 break; 717 case BLINKINGON_STATE: 718 case POWERON_STATE: 719 ctrl_info(ctrl, "Already disabled on slot %s\n", 720 slot_name(p_slot)); 721 break; 722 default: 723 ctrl_err(ctrl, "Not a valid state on slot %s\n", 724 slot_name(p_slot)); 725 break; 726 } 727 mutex_unlock(&p_slot->lock); 728 729 return retval; 730 } 731