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