shpchp_ctrl.c 18 KB

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