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