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