linux/drivers/pci/hotplug/shpchp_ctrl.c
<<
>>
Prefs
   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
  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        queue_work(shpchp_wq, &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, "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
 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, "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
 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, "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 */
 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        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
 336err_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 */
 353static 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
 392struct 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 */
 404static 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
 433void 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
 464static 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 */
 486static 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
 545static 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
 570static 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
 627static 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
 663int 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
 698int 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