scsi_dh_hp_sw.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be
  4. * upgraded.
  5. *
  6. * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
  7. * Copyright (C) 2006 Mike Christie
  8. * Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
  9. */
  10. #include <linux/slab.h>
  11. #include <linux/module.h>
  12. #include <scsi/scsi.h>
  13. #include <scsi/scsi_dbg.h>
  14. #include <scsi/scsi_eh.h>
  15. #include <scsi/scsi_dh.h>
  16. #define HP_SW_NAME "hp_sw"
  17. #define HP_SW_TIMEOUT (60 * HZ)
  18. #define HP_SW_RETRIES 3
  19. #define HP_SW_PATH_UNINITIALIZED -1
  20. #define HP_SW_PATH_ACTIVE 0
  21. #define HP_SW_PATH_PASSIVE 1
  22. struct hp_sw_dh_data {
  23. int path_state;
  24. int retries;
  25. int retry_cnt;
  26. struct scsi_device *sdev;
  27. };
  28. static int hp_sw_start_stop(struct hp_sw_dh_data *);
  29. /*
  30. * tur_done - Handle TEST UNIT READY return status
  31. * @sdev: sdev the command has been sent to
  32. * @errors: blk error code
  33. *
  34. * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
  35. */
  36. static int tur_done(struct scsi_device *sdev, struct hp_sw_dh_data *h,
  37. struct scsi_sense_hdr *sshdr)
  38. {
  39. int ret = SCSI_DH_IO;
  40. switch (sshdr->sense_key) {
  41. case NOT_READY:
  42. if (sshdr->asc == 0x04 && sshdr->ascq == 2) {
  43. /*
  44. * LUN not ready - Initialization command required
  45. *
  46. * This is the passive path
  47. */
  48. h->path_state = HP_SW_PATH_PASSIVE;
  49. ret = SCSI_DH_OK;
  50. break;
  51. }
  52. fallthrough;
  53. default:
  54. sdev_printk(KERN_WARNING, sdev,
  55. "%s: sending tur failed, sense %x/%x/%x\n",
  56. HP_SW_NAME, sshdr->sense_key, sshdr->asc,
  57. sshdr->ascq);
  58. break;
  59. }
  60. return ret;
  61. }
  62. /*
  63. * hp_sw_tur - Send TEST UNIT READY
  64. * @sdev: sdev command should be sent to
  65. *
  66. * Use the TEST UNIT READY command to determine
  67. * the path state.
  68. */
  69. static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
  70. {
  71. unsigned char cmd[6] = { TEST_UNIT_READY };
  72. struct scsi_sense_hdr sshdr;
  73. int ret, res;
  74. blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
  75. REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
  76. struct scsi_failure failure_defs[] = {
  77. {
  78. .sense = UNIT_ATTENTION,
  79. .asc = SCMD_FAILURE_ASC_ANY,
  80. .ascq = SCMD_FAILURE_ASCQ_ANY,
  81. .allowed = SCMD_FAILURE_NO_LIMIT,
  82. .result = SAM_STAT_CHECK_CONDITION,
  83. },
  84. {}
  85. };
  86. struct scsi_failures failures = {
  87. .failure_definitions = failure_defs,
  88. };
  89. const struct scsi_exec_args exec_args = {
  90. .sshdr = &sshdr,
  91. .failures = &failures,
  92. };
  93. res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
  94. HP_SW_RETRIES, &exec_args);
  95. if (res > 0 && scsi_sense_valid(&sshdr)) {
  96. ret = tur_done(sdev, h, &sshdr);
  97. } else if (res == 0) {
  98. h->path_state = HP_SW_PATH_ACTIVE;
  99. ret = SCSI_DH_OK;
  100. } else {
  101. sdev_printk(KERN_WARNING, sdev,
  102. "%s: sending tur failed with %x\n",
  103. HP_SW_NAME, res);
  104. ret = SCSI_DH_IO;
  105. }
  106. return ret;
  107. }
  108. /*
  109. * hp_sw_start_stop - Send START STOP UNIT command
  110. * @sdev: sdev command should be sent to
  111. *
  112. * Sending START STOP UNIT activates the SP.
  113. */
  114. static int hp_sw_start_stop(struct hp_sw_dh_data *h)
  115. {
  116. unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 };
  117. struct scsi_sense_hdr sshdr;
  118. struct scsi_device *sdev = h->sdev;
  119. int res, rc;
  120. blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
  121. REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
  122. struct scsi_failure failure_defs[] = {
  123. {
  124. /*
  125. * LUN not ready - manual intervention required
  126. *
  127. * Switch-over in progress, retry.
  128. */
  129. .sense = NOT_READY,
  130. .asc = 0x04,
  131. .ascq = 0x03,
  132. .allowed = HP_SW_RETRIES,
  133. .result = SAM_STAT_CHECK_CONDITION,
  134. },
  135. {}
  136. };
  137. struct scsi_failures failures = {
  138. .failure_definitions = failure_defs,
  139. };
  140. const struct scsi_exec_args exec_args = {
  141. .sshdr = &sshdr,
  142. .failures = &failures,
  143. };
  144. res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
  145. HP_SW_RETRIES, &exec_args);
  146. if (!res) {
  147. return SCSI_DH_OK;
  148. } else if (res < 0 || !scsi_sense_valid(&sshdr)) {
  149. sdev_printk(KERN_WARNING, sdev,
  150. "%s: sending start_stop_unit failed, "
  151. "no sense available\n", HP_SW_NAME);
  152. return SCSI_DH_IO;
  153. }
  154. switch (sshdr.sense_key) {
  155. case NOT_READY:
  156. if (sshdr.asc == 0x04 && sshdr.ascq == 3) {
  157. rc = SCSI_DH_RETRY;
  158. break;
  159. }
  160. fallthrough;
  161. default:
  162. sdev_printk(KERN_WARNING, sdev,
  163. "%s: sending start_stop_unit failed, "
  164. "sense %x/%x/%x\n", HP_SW_NAME,
  165. sshdr.sense_key, sshdr.asc, sshdr.ascq);
  166. rc = SCSI_DH_IO;
  167. }
  168. return rc;
  169. }
  170. static blk_status_t hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
  171. {
  172. struct hp_sw_dh_data *h = sdev->handler_data;
  173. if (h->path_state != HP_SW_PATH_ACTIVE) {
  174. req->rq_flags |= RQF_QUIET;
  175. return BLK_STS_IOERR;
  176. }
  177. return BLK_STS_OK;
  178. }
  179. /*
  180. * hp_sw_activate - Activate a path
  181. * @sdev: sdev on the path to be activated
  182. *
  183. * The HP Active/Passive firmware is pretty simple;
  184. * the passive path reports NOT READY with sense codes
  185. * 0x04/0x02; a START STOP UNIT command will then
  186. * activate the passive path (and deactivate the
  187. * previously active one).
  188. */
  189. static int hp_sw_activate(struct scsi_device *sdev,
  190. activate_complete fn, void *data)
  191. {
  192. int ret = SCSI_DH_OK;
  193. struct hp_sw_dh_data *h = sdev->handler_data;
  194. ret = hp_sw_tur(sdev, h);
  195. if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE)
  196. ret = hp_sw_start_stop(h);
  197. if (fn)
  198. fn(data, ret);
  199. return 0;
  200. }
  201. static int hp_sw_bus_attach(struct scsi_device *sdev)
  202. {
  203. struct hp_sw_dh_data *h;
  204. int ret;
  205. h = kzalloc(sizeof(*h), GFP_KERNEL);
  206. if (!h)
  207. return SCSI_DH_NOMEM;
  208. h->path_state = HP_SW_PATH_UNINITIALIZED;
  209. h->retries = HP_SW_RETRIES;
  210. h->sdev = sdev;
  211. ret = hp_sw_tur(sdev, h);
  212. if (ret != SCSI_DH_OK)
  213. goto failed;
  214. if (h->path_state == HP_SW_PATH_UNINITIALIZED) {
  215. ret = SCSI_DH_NOSYS;
  216. goto failed;
  217. }
  218. sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
  219. HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
  220. "active":"passive");
  221. sdev->handler_data = h;
  222. return SCSI_DH_OK;
  223. failed:
  224. kfree(h);
  225. return ret;
  226. }
  227. static void hp_sw_bus_detach( struct scsi_device *sdev )
  228. {
  229. kfree(sdev->handler_data);
  230. sdev->handler_data = NULL;
  231. }
  232. static struct scsi_device_handler hp_sw_dh = {
  233. .name = HP_SW_NAME,
  234. .module = THIS_MODULE,
  235. .attach = hp_sw_bus_attach,
  236. .detach = hp_sw_bus_detach,
  237. .activate = hp_sw_activate,
  238. .prep_fn = hp_sw_prep_fn,
  239. };
  240. static int __init hp_sw_init(void)
  241. {
  242. return scsi_register_device_handler(&hp_sw_dh);
  243. }
  244. static void __exit hp_sw_exit(void)
  245. {
  246. scsi_unregister_device_handler(&hp_sw_dh);
  247. }
  248. module_init(hp_sw_init);
  249. module_exit(hp_sw_exit);
  250. MODULE_DESCRIPTION("HP Active/Passive driver");
  251. MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
  252. MODULE_LICENSE("GPL");