scsi_dh_hp_sw.c 6.6 KB

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