Showing error 785

User: Jiri Slaby
Error type: Memory Leak
Error type description: There the code omits to free some allocated memory
File location: drivers/pci/hotplug/shpchp_ctrl.c
Line in file: 447
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2011-11-07 22:26:27 UTC


Source:

  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}