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