xref: /linux/drivers/pci/hotplug/shpchp_ctrl.c (revision a33f32244d8550da8b4a26e277ce07d5c6d158b5)
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/slab.h>
34 #include <linux/pci.h>
35 #include <linux/workqueue.h>
36 #include "../pci.h"
37 #include "shpchp.h"
38 
39 static void interrupt_event_handler(struct work_struct *work);
40 static int shpchp_enable_slot(struct slot *p_slot);
41 static int shpchp_disable_slot(struct slot *p_slot);
42 
43 static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
44 {
45 	struct event_info *info;
46 
47 	info = kmalloc(sizeof(*info), GFP_ATOMIC);
48 	if (!info)
49 		return -ENOMEM;
50 
51 	info->event_type = event_type;
52 	info->p_slot = p_slot;
53 	INIT_WORK(&info->work, interrupt_event_handler);
54 
55 	schedule_work(&info->work);
56 
57 	return 0;
58 }
59 
60 u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
61 {
62 	struct slot *p_slot;
63 	u32 event_type;
64 
65 	/* Attention Button Change */
66 	ctrl_dbg(ctrl, "Attention button interrupt received\n");
67 
68 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
69 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
70 
71 	/*
72 	 *  Button pressed - See if need to TAKE ACTION!!!
73 	 */
74 	ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot));
75 	event_type = INT_BUTTON_PRESS;
76 
77 	queue_interrupt_event(p_slot, event_type);
78 
79 	return 0;
80 
81 }
82 
83 u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
84 {
85 	struct slot *p_slot;
86 	u8 getstatus;
87 	u32 event_type;
88 
89 	/* Switch Change */
90 	ctrl_dbg(ctrl, "Switch interrupt received\n");
91 
92 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
93 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
94 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
95 	ctrl_dbg(ctrl, "Card present %x Power status %x\n",
96 		 p_slot->presence_save, p_slot->pwr_save);
97 
98 	if (getstatus) {
99 		/*
100 		 * Switch opened
101 		 */
102 		ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot));
103 		event_type = INT_SWITCH_OPEN;
104 		if (p_slot->pwr_save && p_slot->presence_save) {
105 			event_type = INT_POWER_FAULT;
106 			ctrl_err(ctrl, "Surprise Removal of card\n");
107 		}
108 	} else {
109 		/*
110 		 *  Switch closed
111 		 */
112 		ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot));
113 		event_type = INT_SWITCH_CLOSE;
114 	}
115 
116 	queue_interrupt_event(p_slot, event_type);
117 
118 	return 1;
119 }
120 
121 u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
122 {
123 	struct slot *p_slot;
124 	u32 event_type;
125 
126 	/* Presence Change */
127 	ctrl_dbg(ctrl, "Presence/Notify input change\n");
128 
129 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
130 
131 	/*
132 	 * Save the presence state
133 	 */
134 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
135 	if (p_slot->presence_save) {
136 		/*
137 		 * Card Present
138 		 */
139 		ctrl_info(ctrl, "Card present on Slot(%s)\n",
140 			  slot_name(p_slot));
141 		event_type = INT_PRESENCE_ON;
142 	} else {
143 		/*
144 		 * Not Present
145 		 */
146 		ctrl_info(ctrl, "Card not present on Slot(%s)\n",
147 			  slot_name(p_slot));
148 		event_type = INT_PRESENCE_OFF;
149 	}
150 
151 	queue_interrupt_event(p_slot, event_type);
152 
153 	return 1;
154 }
155 
156 u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
157 {
158 	struct slot *p_slot;
159 	u32 event_type;
160 
161 	/* Power fault */
162 	ctrl_dbg(ctrl, "Power fault interrupt received\n");
163 
164 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
165 
166 	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
167 		/*
168 		 * Power fault Cleared
169 		 */
170 		ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n",
171 			  slot_name(p_slot));
172 		p_slot->status = 0x00;
173 		event_type = INT_POWER_FAULT_CLEAR;
174 	} else {
175 		/*
176 		 *   Power fault
177 		 */
178 		ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot));
179 		event_type = INT_POWER_FAULT;
180 		/* set power fault status for this board */
181 		p_slot->status = 0xFF;
182 		ctrl_info(ctrl, "Power fault bit %x set\n", hp_slot);
183 	}
184 
185 	queue_interrupt_event(p_slot, event_type);
186 
187 	return 1;
188 }
189 
190 /* The following routines constitute the bulk of the
191    hotplug controller logic
192  */
193 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
194 		enum pci_bus_speed speed)
195 {
196 	int rc = 0;
197 
198 	ctrl_dbg(ctrl, "Change speed to %d\n", speed);
199 	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
200 		ctrl_err(ctrl, "%s: Issue of set bus speed mode command "
201 			 "failed\n", __func__);
202 		return WRONG_BUS_FREQUENCY;
203 	}
204 	return rc;
205 }
206 
207 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
208 		u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
209 		enum pci_bus_speed msp)
210 {
211 	int rc = 0;
212 
213 	/*
214 	 * If other slots on the same bus are occupied, we cannot
215 	 * change the bus speed.
216 	 */
217 	if (flag) {
218 		if (asp < bsp) {
219 			ctrl_err(ctrl, "Speed of bus %x and adapter %x "
220 				 "mismatch\n", bsp, asp);
221 			rc = WRONG_BUS_FREQUENCY;
222 		}
223 		return rc;
224 	}
225 
226 	if (asp < msp) {
227 		if (bsp != asp)
228 			rc = change_bus_speed(ctrl, pslot, asp);
229 	} else {
230 		if (bsp != msp)
231 			rc = change_bus_speed(ctrl, pslot, msp);
232 	}
233 	return rc;
234 }
235 
236 /**
237  * board_added - Called after a board has been added to the system.
238  * @p_slot: target &slot
239  *
240  * Turns power on for the board.
241  * Configures board.
242  */
243 static int board_added(struct slot *p_slot)
244 {
245 	u8 hp_slot;
246 	u8 slots_not_empty = 0;
247 	int rc = 0;
248 	enum pci_bus_speed asp, bsp, msp;
249 	struct controller *ctrl = p_slot->ctrl;
250 	struct pci_bus *parent = ctrl->pci_dev->subordinate;
251 
252 	hp_slot = p_slot->device - ctrl->slot_device_offset;
253 
254 	ctrl_dbg(ctrl,
255 		 "%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n",
256 		 __func__, p_slot->device, ctrl->slot_device_offset, hp_slot);
257 
258 	/* Power on slot without connecting to bus */
259 	rc = p_slot->hpc_ops->power_on_slot(p_slot);
260 	if (rc) {
261 		ctrl_err(ctrl, "Failed to power on slot\n");
262 		return -1;
263 	}
264 
265 	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
266 		if (slots_not_empty)
267 			return WRONG_BUS_FREQUENCY;
268 
269 		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
270 			ctrl_err(ctrl, "%s: Issue of set bus speed mode command"
271 				 " failed\n", __func__);
272 			return WRONG_BUS_FREQUENCY;
273 		}
274 
275 		/* turn on board, blink green LED, turn off Amber LED */
276 		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
277 			ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
278 			return rc;
279 		}
280 	}
281 
282 	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
283 	if (rc) {
284 		ctrl_err(ctrl, "Can't get adapter speed or "
285 			 "bus mode mismatch\n");
286 		return WRONG_BUS_FREQUENCY;
287 	}
288 
289 	bsp = ctrl->pci_dev->bus->cur_bus_speed;
290 	msp = ctrl->pci_dev->bus->max_bus_speed;
291 
292 	/* Check if there are other slots or devices on the same bus */
293 	if (!list_empty(&ctrl->pci_dev->subordinate->devices))
294 		slots_not_empty = 1;
295 
296 	ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d,"
297 		 " max_bus_speed %d\n", __func__, slots_not_empty, asp,
298 		 bsp, msp);
299 
300 	rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp);
301 	if (rc)
302 		return rc;
303 
304 	/* turn on board, blink green LED, turn off Amber LED */
305 	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
306 		ctrl_err(ctrl, "Issue of Slot Enable command failed\n");
307 		return rc;
308 	}
309 
310 	/* Wait for ~1 second */
311 	msleep(1000);
312 
313 	ctrl_dbg(ctrl, "%s: slot status = %x\n", __func__, p_slot->status);
314 	/* Check for a power fault */
315 	if (p_slot->status == 0xFF) {
316 		/* power fault occurred, but it was benign */
317 		ctrl_dbg(ctrl, "%s: Power fault\n", __func__);
318 		rc = POWER_FAILURE;
319 		p_slot->status = 0;
320 		goto err_exit;
321 	}
322 
323 	if (shpchp_configure_device(p_slot)) {
324 		ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n",
325 			 pci_domain_nr(parent), p_slot->bus, p_slot->device);
326 		goto err_exit;
327 	}
328 
329 	p_slot->status = 0;
330 	p_slot->is_a_board = 0x01;
331 	p_slot->pwr_save = 1;
332 
333 	p_slot->hpc_ops->green_led_on(p_slot);
334 
335 	return 0;
336 
337 err_exit:
338 	/* turn off slot, turn on Amber LED, turn off Green LED */
339 	rc = p_slot->hpc_ops->slot_disable(p_slot);
340 	if (rc) {
341 		ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
342 			 __func__);
343 		return rc;
344 	}
345 
346 	return(rc);
347 }
348 
349 
350 /**
351  * remove_board - Turns off slot and LEDs
352  * @p_slot: target &slot
353  */
354 static int remove_board(struct slot *p_slot)
355 {
356 	struct controller *ctrl = p_slot->ctrl;
357 	u8 hp_slot;
358 	int rc;
359 
360 	if (shpchp_unconfigure_device(p_slot))
361 		return(1);
362 
363 	hp_slot = p_slot->device - ctrl->slot_device_offset;
364 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
365 
366 	ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot);
367 
368 	/* Change status to shutdown */
369 	if (p_slot->is_a_board)
370 		p_slot->status = 0x01;
371 
372 	/* turn off slot, turn on Amber LED, turn off Green LED */
373 	rc = p_slot->hpc_ops->slot_disable(p_slot);
374 	if (rc) {
375 		ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n",
376 			 __func__);
377 		return rc;
378 	}
379 
380 	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
381 	if (rc) {
382 		ctrl_err(ctrl, "Issue of Set Attention command failed\n");
383 		return rc;
384 	}
385 
386 	p_slot->pwr_save = 0;
387 	p_slot->is_a_board = 0;
388 
389 	return 0;
390 }
391 
392 
393 struct pushbutton_work_info {
394 	struct slot *p_slot;
395 	struct work_struct work;
396 };
397 
398 /**
399  * shpchp_pushbutton_thread - handle pushbutton events
400  * @work: &struct work_struct to be handled
401  *
402  * Scheduled procedure to handle blocking stuff for the pushbuttons.
403  * Handles all pending events and exits.
404  */
405 static void shpchp_pushbutton_thread(struct work_struct *work)
406 {
407 	struct pushbutton_work_info *info =
408 		container_of(work, struct pushbutton_work_info, work);
409 	struct slot *p_slot = info->p_slot;
410 
411 	mutex_lock(&p_slot->lock);
412 	switch (p_slot->state) {
413 	case POWEROFF_STATE:
414 		mutex_unlock(&p_slot->lock);
415 		shpchp_disable_slot(p_slot);
416 		mutex_lock(&p_slot->lock);
417 		p_slot->state = STATIC_STATE;
418 		break;
419 	case POWERON_STATE:
420 		mutex_unlock(&p_slot->lock);
421 		if (shpchp_enable_slot(p_slot))
422 			p_slot->hpc_ops->green_led_off(p_slot);
423 		mutex_lock(&p_slot->lock);
424 		p_slot->state = STATIC_STATE;
425 		break;
426 	default:
427 		break;
428 	}
429 	mutex_unlock(&p_slot->lock);
430 
431 	kfree(info);
432 }
433 
434 void shpchp_queue_pushbutton_work(struct work_struct *work)
435 {
436 	struct slot *p_slot = container_of(work, struct slot, work.work);
437 	struct pushbutton_work_info *info;
438 
439 	info = kmalloc(sizeof(*info), GFP_KERNEL);
440 	if (!info) {
441 		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
442 			 __func__);
443 		return;
444 	}
445 	info->p_slot = p_slot;
446 	INIT_WORK(&info->work, shpchp_pushbutton_thread);
447 
448 	mutex_lock(&p_slot->lock);
449 	switch (p_slot->state) {
450 	case BLINKINGOFF_STATE:
451 		p_slot->state = POWEROFF_STATE;
452 		break;
453 	case BLINKINGON_STATE:
454 		p_slot->state = POWERON_STATE;
455 		break;
456 	default:
457 		kfree(info);
458 		goto out;
459 	}
460 	queue_work(shpchp_wq, &info->work);
461  out:
462 	mutex_unlock(&p_slot->lock);
463 }
464 
465 static int update_slot_info (struct slot *slot)
466 {
467 	struct hotplug_slot_info *info;
468 	int result;
469 
470 	info = kmalloc(sizeof(*info), GFP_KERNEL);
471 	if (!info)
472 		return -ENOMEM;
473 
474 	slot->hpc_ops->get_power_status(slot, &(info->power_status));
475 	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
476 	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
477 	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
478 
479 	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
480 	kfree (info);
481 	return result;
482 }
483 
484 /*
485  * Note: This function must be called with slot->lock held
486  */
487 static void handle_button_press_event(struct slot *p_slot)
488 {
489 	u8 getstatus;
490 	struct controller *ctrl = p_slot->ctrl;
491 
492 	switch (p_slot->state) {
493 	case STATIC_STATE:
494 		p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
495 		if (getstatus) {
496 			p_slot->state = BLINKINGOFF_STATE;
497 			ctrl_info(ctrl, "PCI slot #%s - powering off due to "
498 				  "button press.\n", slot_name(p_slot));
499 		} else {
500 			p_slot->state = BLINKINGON_STATE;
501 			ctrl_info(ctrl, "PCI slot #%s - powering on due to "
502 				  "button press.\n", slot_name(p_slot));
503 		}
504 		/* blink green LED and turn off amber */
505 		p_slot->hpc_ops->green_led_blink(p_slot);
506 		p_slot->hpc_ops->set_attention_status(p_slot, 0);
507 
508 		schedule_delayed_work(&p_slot->work, 5*HZ);
509 		break;
510 	case BLINKINGOFF_STATE:
511 	case BLINKINGON_STATE:
512 		/*
513 		 * Cancel if we are still blinking; this means that we
514 		 * press the attention again before the 5 sec. limit
515 		 * expires to cancel hot-add or hot-remove
516 		 */
517 		ctrl_info(ctrl, "Button cancel on Slot(%s)\n",
518 			  slot_name(p_slot));
519 		cancel_delayed_work(&p_slot->work);
520 		if (p_slot->state == BLINKINGOFF_STATE)
521 			p_slot->hpc_ops->green_led_on(p_slot);
522 		else
523 			p_slot->hpc_ops->green_led_off(p_slot);
524 		p_slot->hpc_ops->set_attention_status(p_slot, 0);
525 		ctrl_info(ctrl, "PCI slot #%s - action canceled due to "
526 			  "button press\n", slot_name(p_slot));
527 		p_slot->state = STATIC_STATE;
528 		break;
529 	case POWEROFF_STATE:
530 	case POWERON_STATE:
531 		/*
532 		 * Ignore if the slot is on power-on or power-off state;
533 		 * this means that the previous attention button action
534 		 * to hot-add or hot-remove is undergoing
535 		 */
536 		ctrl_info(ctrl, "Button ignore on Slot(%s)\n",
537 			  slot_name(p_slot));
538 		update_slot_info(p_slot);
539 		break;
540 	default:
541 		ctrl_warn(ctrl, "Not a valid state\n");
542 		break;
543 	}
544 }
545 
546 static void interrupt_event_handler(struct work_struct *work)
547 {
548 	struct event_info *info = container_of(work, struct event_info, work);
549 	struct slot *p_slot = info->p_slot;
550 
551 	mutex_lock(&p_slot->lock);
552 	switch (info->event_type) {
553 	case INT_BUTTON_PRESS:
554 		handle_button_press_event(p_slot);
555 		break;
556 	case INT_POWER_FAULT:
557 		ctrl_dbg(p_slot->ctrl, "%s: Power fault\n", __func__);
558 		p_slot->hpc_ops->set_attention_status(p_slot, 1);
559 		p_slot->hpc_ops->green_led_off(p_slot);
560 		break;
561 	default:
562 		update_slot_info(p_slot);
563 		break;
564 	}
565 	mutex_unlock(&p_slot->lock);
566 
567 	kfree(info);
568 }
569 
570 
571 static int shpchp_enable_slot (struct slot *p_slot)
572 {
573 	u8 getstatus = 0;
574 	int rc, retval = -ENODEV;
575 	struct controller *ctrl = p_slot->ctrl;
576 
577 	/* Check to see if (latch closed, card present, power off) */
578 	mutex_lock(&p_slot->ctrl->crit_sect);
579 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
580 	if (rc || !getstatus) {
581 		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
582 		goto out;
583 	}
584 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
585 	if (rc || getstatus) {
586 		ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
587 		goto out;
588 	}
589 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
590 	if (rc || getstatus) {
591 		ctrl_info(ctrl, "Already enabled on slot(%s)\n",
592 			  slot_name(p_slot));
593 		goto out;
594 	}
595 
596 	p_slot->is_a_board = 1;
597 
598 	/* We have to save the presence info for these slots */
599 	p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
600 	p_slot->hpc_ops->get_power_status(p_slot, &(p_slot->pwr_save));
601 	ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
602 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
603 
604 	if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
605 	    (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
606 	     && p_slot->ctrl->num_slots == 1) {
607 		/* handle amd pogo errata; this must be done before enable  */
608 		amd_pogo_errata_save_misc_reg(p_slot);
609 		retval = board_added(p_slot);
610 		/* handle amd pogo errata; this must be done after enable  */
611 		amd_pogo_errata_restore_misc_reg(p_slot);
612 	} else
613 		retval = board_added(p_slot);
614 
615 	if (retval) {
616 		p_slot->hpc_ops->get_adapter_status(p_slot,
617 				&(p_slot->presence_save));
618 		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
619 	}
620 
621 	update_slot_info(p_slot);
622  out:
623 	mutex_unlock(&p_slot->ctrl->crit_sect);
624 	return retval;
625 }
626 
627 
628 static int shpchp_disable_slot (struct slot *p_slot)
629 {
630 	u8 getstatus = 0;
631 	int rc, retval = -ENODEV;
632 	struct controller *ctrl = p_slot->ctrl;
633 
634 	if (!p_slot->ctrl)
635 		return -ENODEV;
636 
637 	/* Check to see if (latch closed, card present, power on) */
638 	mutex_lock(&p_slot->ctrl->crit_sect);
639 
640 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
641 	if (rc || !getstatus) {
642 		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
643 		goto out;
644 	}
645 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
646 	if (rc || getstatus) {
647 		ctrl_info(ctrl, "Latch open on slot(%s)\n", slot_name(p_slot));
648 		goto out;
649 	}
650 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
651 	if (rc || !getstatus) {
652 		ctrl_info(ctrl, "Already disabled on slot(%s)\n",
653 			  slot_name(p_slot));
654 		goto out;
655 	}
656 
657 	retval = remove_board(p_slot);
658 	update_slot_info(p_slot);
659  out:
660 	mutex_unlock(&p_slot->ctrl->crit_sect);
661 	return retval;
662 }
663 
664 int shpchp_sysfs_enable_slot(struct slot *p_slot)
665 {
666 	int retval = -ENODEV;
667 	struct controller *ctrl = p_slot->ctrl;
668 
669 	mutex_lock(&p_slot->lock);
670 	switch (p_slot->state) {
671 	case BLINKINGON_STATE:
672 		cancel_delayed_work(&p_slot->work);
673 	case STATIC_STATE:
674 		p_slot->state = POWERON_STATE;
675 		mutex_unlock(&p_slot->lock);
676 		retval = shpchp_enable_slot(p_slot);
677 		mutex_lock(&p_slot->lock);
678 		p_slot->state = STATIC_STATE;
679 		break;
680 	case POWERON_STATE:
681 		ctrl_info(ctrl, "Slot %s is already in powering on state\n",
682 			  slot_name(p_slot));
683 		break;
684 	case BLINKINGOFF_STATE:
685 	case POWEROFF_STATE:
686 		ctrl_info(ctrl, "Already enabled on slot %s\n",
687 			  slot_name(p_slot));
688 		break;
689 	default:
690 		ctrl_err(ctrl, "Not a valid state on slot %s\n",
691 			 slot_name(p_slot));
692 		break;
693 	}
694 	mutex_unlock(&p_slot->lock);
695 
696 	return retval;
697 }
698 
699 int shpchp_sysfs_disable_slot(struct slot *p_slot)
700 {
701 	int retval = -ENODEV;
702 	struct controller *ctrl = p_slot->ctrl;
703 
704 	mutex_lock(&p_slot->lock);
705 	switch (p_slot->state) {
706 	case BLINKINGOFF_STATE:
707 		cancel_delayed_work(&p_slot->work);
708 	case STATIC_STATE:
709 		p_slot->state = POWEROFF_STATE;
710 		mutex_unlock(&p_slot->lock);
711 		retval = shpchp_disable_slot(p_slot);
712 		mutex_lock(&p_slot->lock);
713 		p_slot->state = STATIC_STATE;
714 		break;
715 	case POWEROFF_STATE:
716 		ctrl_info(ctrl, "Slot %s is already in powering off state\n",
717 			  slot_name(p_slot));
718 		break;
719 	case BLINKINGON_STATE:
720 	case POWERON_STATE:
721 		ctrl_info(ctrl, "Already disabled on slot %s\n",
722 			  slot_name(p_slot));
723 		break;
724 	default:
725 		ctrl_err(ctrl, "Not a valid state on slot %s\n",
726 			 slot_name(p_slot));
727 		break;
728 	}
729 	mutex_unlock(&p_slot->lock);
730 
731 	return retval;
732 }
733