shpchp_ctrl.c 18 KB

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