root/drivers/pci/hotplug/shpchp_ctrl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. queue_interrupt_event
  2. shpchp_handle_attention_button
  3. shpchp_handle_switch_change
  4. shpchp_handle_presence_change
  5. shpchp_handle_power_fault
  6. change_bus_speed
  7. fix_bus_speed
  8. board_added
  9. remove_board
  10. shpchp_pushbutton_thread
  11. shpchp_queue_pushbutton_work
  12. update_slot_info
  13. handle_button_press_event
  14. interrupt_event_handler
  15. shpchp_enable_slot
  16. shpchp_disable_slot
  17. shpchp_sysfs_enable_slot
  18. shpchp_sysfs_disable_slot

   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 
  24 static void interrupt_event_handler(struct work_struct *work);
  25 static int shpchp_enable_slot(struct slot *p_slot);
  26 static int shpchp_disable_slot(struct slot *p_slot);
  27 
  28 static 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 
  45 u8 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 
  68 u8 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 
 106 u8 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 
 141 u8 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  */
 178 static 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 
 193 static 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  */
 229 static 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 
 321 err_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  */
 338 static 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 
 377 struct 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  */
 389 static 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 
 418 void 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 
 449 static 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  */
 460 static 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 
 519 static 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 
 544 static 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 
 601 static 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 
 637 int 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 
 673 int 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 }

/* [<][>][^][v][top][bottom][index][help] */