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