Merge branch 'asoc-5.6' into asoc-linus
[linux-2.6-microblaze.git] / drivers / pci / hotplug / shpchp_ctrl.c
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 }