mpath_hds.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /* $OpenBSD: mpath_hds.c,v 1.19 2015/06/07 19:13:27 krw Exp $ */
  2. /*
  3. * Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* Hitachi Modular Storage support for mpath(4) */
  18. #include <sys/param.h>
  19. #include <sys/systm.h>
  20. #include <sys/kernel.h>
  21. #include <sys/malloc.h>
  22. #include <sys/device.h>
  23. #include <sys/conf.h>
  24. #include <sys/queue.h>
  25. #include <sys/rwlock.h>
  26. #include <sys/pool.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/poll.h>
  29. #include <sys/selinfo.h>
  30. #include <scsi/scsi_all.h>
  31. #include <scsi/scsiconf.h>
  32. #include <scsi/mpathvar.h>
  33. #define HDS_INQ_LDEV_OFFSET 44
  34. #define HDS_INQ_LDEV_LEN 4
  35. #define HDS_INQ_CTRL_OFFSET 49
  36. #define HDS_INQ_PORT_OFFSET 50
  37. #define HDS_INQ_TYPE_OFFSET 128
  38. #define HDS_INQ_TYPE 0x44463030 /* "DF00" */
  39. #define HDS_VPD 0xe0
  40. struct hds_vpd {
  41. struct scsi_vpd_hdr hdr; /* HDS_VPD */
  42. u_int8_t state;
  43. #define HDS_VPD_VALID 0x80
  44. #define HDS_VPD_PREFERRED 0x40
  45. /* followed by lots of unknown stuff */
  46. };
  47. #define HDS_SYMMETRIC 0
  48. #define HDS_ASYMMETRIC 1
  49. struct hds_softc {
  50. struct device sc_dev;
  51. struct mpath_path sc_path;
  52. struct scsi_xshandler sc_xsh;
  53. struct hds_vpd *sc_vpd;
  54. int sc_mode;
  55. int sc_ctrl;
  56. };
  57. #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
  58. int hds_match(struct device *, void *, void *);
  59. void hds_attach(struct device *, struct device *, void *);
  60. int hds_detach(struct device *, int);
  61. int hds_activate(struct device *, int);
  62. struct cfattach hds_ca = {
  63. sizeof(struct hds_softc),
  64. hds_match,
  65. hds_attach,
  66. hds_detach,
  67. hds_activate
  68. };
  69. struct cfdriver hds_cd = {
  70. NULL,
  71. "hds",
  72. DV_DULL
  73. };
  74. void hds_mpath_start(struct scsi_xfer *);
  75. int hds_mpath_checksense(struct scsi_xfer *);
  76. void hds_mpath_status(struct scsi_link *);
  77. const struct mpath_ops hds_mpath_ops = {
  78. "hds",
  79. hds_mpath_checksense,
  80. hds_mpath_status
  81. };
  82. struct hds_device {
  83. char *vendor;
  84. char *product;
  85. };
  86. int hds_inquiry(struct scsi_link *, int *);
  87. int hds_info(struct hds_softc *);
  88. void hds_status(struct scsi_xfer *);
  89. void hds_status_done(struct scsi_xfer *);
  90. struct hds_device hds_devices[] = {
  91. /* " vendor " " device " */
  92. /* "01234567" "0123456789012345" */
  93. { "HITACHI ", "DF600F " },
  94. { "HITACHI ", "DF600F-CM " }
  95. };
  96. int
  97. hds_match(struct device *parent, void *match, void *aux)
  98. {
  99. struct scsi_attach_args *sa = aux;
  100. struct scsi_inquiry_data *inq = sa->sa_inqbuf;
  101. struct scsi_link *link = sa->sa_sc_link;
  102. struct hds_device *s;
  103. int i, mode;
  104. if (mpath_path_probe(sa->sa_sc_link) != 0)
  105. return (0);
  106. for (i = 0; i < nitems(hds_devices); i++) {
  107. s = &hds_devices[i];
  108. if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
  109. bcmp(s->product, inq->product, strlen(s->product)) == 0 &&
  110. hds_inquiry(link, &mode) == 0)
  111. return (8);
  112. }
  113. return (0);
  114. }
  115. void
  116. hds_attach(struct device *parent, struct device *self, void *aux)
  117. {
  118. struct hds_softc *sc = (struct hds_softc *)self;
  119. struct scsi_attach_args *sa = aux;
  120. struct scsi_link *link = sa->sa_sc_link;
  121. printf("\n");
  122. /* init link */
  123. link->device_softc = sc;
  124. /* init path */
  125. scsi_xsh_set(&sc->sc_path.p_xsh, link, hds_mpath_start);
  126. sc->sc_path.p_link = link;
  127. /* init status handler */
  128. scsi_xsh_set(&sc->sc_xsh, link, hds_status);
  129. sc->sc_vpd = dma_alloc(sizeof(*sc->sc_vpd), PR_WAITOK);
  130. if (hds_inquiry(link, &sc->sc_mode) != 0) {
  131. printf("%s: unable to query controller mode\n", DEVNAME(sc));
  132. return;
  133. }
  134. if (hds_info(sc) != 0) {
  135. printf("%s: unable to query path info\n", DEVNAME(sc));
  136. return;
  137. }
  138. if (mpath_path_attach(&sc->sc_path,
  139. (sc->sc_mode == HDS_SYMMETRIC) ? 0 : sc->sc_ctrl,
  140. &hds_mpath_ops) != 0)
  141. printf("%s: unable to attach path\n", DEVNAME(sc));
  142. }
  143. int
  144. hds_detach(struct device *self, int flags)
  145. {
  146. struct hds_softc *sc = (struct hds_softc *)self;
  147. dma_free(sc->sc_vpd, sizeof(*sc->sc_vpd));
  148. return (0);
  149. }
  150. int
  151. hds_activate(struct device *self, int act)
  152. {
  153. struct hds_softc *sc = (struct hds_softc *)self;
  154. int rv = 0;
  155. switch (act) {
  156. case DVACT_DEACTIVATE:
  157. if (sc->sc_path.p_group != NULL)
  158. mpath_path_detach(&sc->sc_path);
  159. break;
  160. }
  161. return (rv);
  162. }
  163. void
  164. hds_mpath_start(struct scsi_xfer *xs)
  165. {
  166. struct hds_softc *sc = xs->sc_link->device_softc;
  167. mpath_start(&sc->sc_path, xs);
  168. }
  169. int
  170. hds_mpath_checksense(struct scsi_xfer *xs)
  171. {
  172. return (MPATH_SENSE_DECLINED);
  173. }
  174. void
  175. hds_mpath_status(struct scsi_link *link)
  176. {
  177. struct hds_softc *sc = link->device_softc;
  178. if (sc->sc_mode == HDS_SYMMETRIC)
  179. mpath_path_status(&sc->sc_path, MPATH_S_ACTIVE);
  180. else
  181. scsi_xsh_add(&sc->sc_xsh);
  182. }
  183. void
  184. hds_status(struct scsi_xfer *xs)
  185. {
  186. struct scsi_link *link = xs->sc_link;
  187. struct hds_softc *sc = link->device_softc;
  188. scsi_init_inquiry(xs, SI_EVPD, HDS_VPD,
  189. sc->sc_vpd, sizeof(*sc->sc_vpd));
  190. xs->done = hds_status_done;
  191. scsi_xs_exec(xs);
  192. }
  193. void
  194. hds_status_done(struct scsi_xfer *xs)
  195. {
  196. struct scsi_link *link = xs->sc_link;
  197. struct hds_softc *sc = link->device_softc;
  198. struct hds_vpd *vpd = sc->sc_vpd;
  199. int status = MPATH_S_UNKNOWN;
  200. if (xs->error == XS_NOERROR &&
  201. _2btol(vpd->hdr.page_length) >= sizeof(vpd->state) &&
  202. ISSET(vpd->state, HDS_VPD_VALID)) {
  203. status = ISSET(vpd->state, HDS_VPD_PREFERRED) ?
  204. MPATH_S_ACTIVE : MPATH_S_PASSIVE;
  205. }
  206. scsi_xs_put(xs);
  207. mpath_path_status(&sc->sc_path, status);
  208. }
  209. int
  210. hds_inquiry(struct scsi_link *link, int *mode)
  211. {
  212. struct scsi_xfer *xs;
  213. u_int8_t *buf;
  214. size_t len = link->inqdata.additional_length + 5;
  215. int error;
  216. if (len < HDS_INQ_TYPE_OFFSET + sizeof(int))
  217. return (ENXIO);
  218. xs = scsi_xs_get(link, scsi_autoconf);
  219. if (xs == NULL)
  220. return (ENOMEM);
  221. buf = dma_alloc(len, PR_WAITOK);
  222. scsi_init_inquiry(xs, 0, 0, buf, len);
  223. error = scsi_xs_sync(xs);
  224. scsi_xs_put(xs);
  225. if (error)
  226. goto done;
  227. if (buf[128] == '\0')
  228. *mode = HDS_ASYMMETRIC;
  229. else if (_4btol(&buf[HDS_INQ_TYPE_OFFSET]) == HDS_INQ_TYPE)
  230. *mode = HDS_SYMMETRIC;
  231. else
  232. error = ENXIO;
  233. done:
  234. dma_free(buf, len);
  235. return (error);
  236. }
  237. int
  238. hds_info(struct hds_softc *sc)
  239. {
  240. struct scsi_link *link = sc->sc_path.p_link;
  241. struct scsi_xfer *xs;
  242. u_int8_t *buf;
  243. size_t len = link->inqdata.additional_length + 5;
  244. char ldev[9], ctrl, port;
  245. int error;
  246. xs = scsi_xs_get(link, scsi_autoconf);
  247. if (xs == NULL)
  248. return (ENOMEM);
  249. buf = dma_alloc(len, PR_WAITOK);
  250. scsi_init_inquiry(xs, 0, 0, buf, len);
  251. error = scsi_xs_sync(xs);
  252. scsi_xs_put(xs);
  253. if (error)
  254. goto done;
  255. bzero(ldev, sizeof(ldev));
  256. scsi_strvis(ldev, &buf[HDS_INQ_LDEV_OFFSET], HDS_INQ_LDEV_LEN);
  257. ctrl = buf[HDS_INQ_CTRL_OFFSET];
  258. port = buf[HDS_INQ_PORT_OFFSET];
  259. if (ctrl >= '0' && ctrl <= '9' && port >= 'A' && port <= 'B') {
  260. printf("%s: ldev %s, controller %c, port %c, %s\n",
  261. DEVNAME(sc), ldev, ctrl, port,
  262. sc->sc_mode == HDS_SYMMETRIC ? "symmetric" : "asymmetric");
  263. sc->sc_ctrl = ctrl;
  264. } else
  265. error = ENXIO;
  266. done:
  267. dma_free(buf, len);
  268. return (error);
  269. }