mpath_emc.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /* $OpenBSD: mpath_emc.c,v 1.21 2015/03/14 03:38:52 jsg 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. /* EMC CLARiiON AX/CX 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 EMC_VPD_SP_INFO 0xc0
  34. struct emc_vpd_sp_info {
  35. struct scsi_vpd_hdr hdr; /* EMC_VPD_SP_INFO */
  36. u_int8_t lun_state;
  37. #define EMC_SP_INFO_LUN_STATE_UNBOUND 0x00
  38. #define EMC_SP_INFO_LUN_STATE_BOUND 0x01
  39. #define EMC_SP_INFO_LUN_STATE_OWNED 0x02
  40. u_int8_t default_sp;
  41. u_int8_t _reserved1[1];
  42. u_int8_t port;
  43. u_int8_t current_sp;
  44. u_int8_t _reserved2[1];
  45. u_int8_t unique_id[16];
  46. u_int8_t _reserved3[1];
  47. u_int8_t type;
  48. u_int8_t failover_mode;
  49. u_int8_t _reserved4[21];
  50. u_int8_t serial[16];
  51. } __packed;
  52. struct emc_softc {
  53. struct device sc_dev;
  54. struct mpath_path sc_path;
  55. struct scsi_xshandler sc_xsh;
  56. struct emc_vpd_sp_info *sc_pg;
  57. };
  58. #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
  59. int emc_match(struct device *, void *, void *);
  60. void emc_attach(struct device *, struct device *, void *);
  61. int emc_detach(struct device *, int);
  62. int emc_activate(struct device *, int);
  63. struct cfattach emc_ca = {
  64. sizeof(struct emc_softc),
  65. emc_match,
  66. emc_attach,
  67. emc_detach,
  68. emc_activate
  69. };
  70. struct cfdriver emc_cd = {
  71. NULL,
  72. "emc",
  73. DV_DULL
  74. };
  75. void emc_mpath_start(struct scsi_xfer *);
  76. int emc_mpath_checksense(struct scsi_xfer *);
  77. void emc_mpath_status(struct scsi_link *);
  78. const struct mpath_ops emc_mpath_ops = {
  79. "emc",
  80. emc_mpath_checksense,
  81. emc_mpath_status
  82. };
  83. struct emc_device {
  84. char *vendor;
  85. char *product;
  86. };
  87. void emc_status(struct scsi_xfer *);
  88. void emc_status_done(struct scsi_xfer *);
  89. int emc_sp_info(struct emc_softc *, int *);
  90. struct emc_device emc_devices[] = {
  91. /* " vendor " " device " */
  92. /* "01234567" "0123456789012345" */
  93. { "DGC ", "RAID" },
  94. { "DGC ", "DISK" },
  95. { "DGC ", "VRAID" }
  96. };
  97. int
  98. emc_match(struct device *parent, void *match, void *aux)
  99. {
  100. struct scsi_attach_args *sa = aux;
  101. struct scsi_inquiry_data *inq = sa->sa_inqbuf;
  102. struct emc_device *s;
  103. int i;
  104. if (mpath_path_probe(sa->sa_sc_link) != 0)
  105. return (0);
  106. for (i = 0; i < nitems(emc_devices); i++) {
  107. s = &emc_devices[i];
  108. if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
  109. bcmp(s->product, inq->product, strlen(s->product)) == 0)
  110. return (8);
  111. }
  112. return (0);
  113. }
  114. void
  115. emc_attach(struct device *parent, struct device *self, void *aux)
  116. {
  117. struct emc_softc *sc = (struct emc_softc *)self;
  118. struct scsi_attach_args *sa = aux;
  119. struct scsi_link *link = sa->sa_sc_link;
  120. int sp;
  121. printf("\n");
  122. /* init link */
  123. link->device_softc = sc;
  124. /* init path */
  125. scsi_xsh_set(&sc->sc_path.p_xsh, link, emc_mpath_start);
  126. sc->sc_path.p_link = link;
  127. /* init status handler */
  128. scsi_xsh_set(&sc->sc_xsh, link, emc_status);
  129. sc->sc_pg = dma_alloc(sizeof(*sc->sc_pg), PR_WAITOK);
  130. /* let's go */
  131. if (emc_sp_info(sc, &sp)) {
  132. printf("%s: unable to get sp info\n", DEVNAME(sc));
  133. return;
  134. }
  135. if (mpath_path_attach(&sc->sc_path, sp, &emc_mpath_ops) != 0)
  136. printf("%s: unable to attach path\n", DEVNAME(sc));
  137. }
  138. int
  139. emc_detach(struct device *self, int flags)
  140. {
  141. struct emc_softc *sc = (struct emc_softc *)self;
  142. dma_free(sc->sc_pg, sizeof(*sc->sc_pg));
  143. return (0);
  144. }
  145. int
  146. emc_activate(struct device *self, int act)
  147. {
  148. struct emc_softc *sc = (struct emc_softc *)self;
  149. int rv = 0;
  150. switch (act) {
  151. case DVACT_DEACTIVATE:
  152. if (sc->sc_path.p_group != NULL)
  153. mpath_path_detach(&sc->sc_path);
  154. break;
  155. }
  156. return (rv);
  157. }
  158. void
  159. emc_mpath_start(struct scsi_xfer *xs)
  160. {
  161. struct emc_softc *sc = xs->sc_link->device_softc;
  162. mpath_start(&sc->sc_path, xs);
  163. }
  164. int
  165. emc_mpath_checksense(struct scsi_xfer *xs)
  166. {
  167. struct scsi_sense_data *sense = &xs->sense;
  168. if ((sense->error_code & SSD_ERRCODE) == SSD_ERRCODE_CURRENT &&
  169. (sense->flags & SSD_KEY) == SKEY_NOT_READY &&
  170. ASC_ASCQ(sense) == 0x0403) {
  171. /* Logical Unit Not Ready, Manual Intervention Required */
  172. return (MPATH_SENSE_FAILOVER);
  173. }
  174. return (MPATH_SENSE_DECLINED);
  175. }
  176. void
  177. emc_mpath_status(struct scsi_link *link)
  178. {
  179. struct emc_softc *sc = link->device_softc;
  180. scsi_xsh_add(&sc->sc_xsh);
  181. }
  182. void
  183. emc_status(struct scsi_xfer *xs)
  184. {
  185. struct scsi_link *link = xs->sc_link;
  186. struct emc_softc *sc = link->device_softc;
  187. scsi_init_inquiry(xs, SI_EVPD, EMC_VPD_SP_INFO,
  188. sc->sc_pg, sizeof(*sc->sc_pg));
  189. xs->done = emc_status_done;
  190. scsi_xs_exec(xs);
  191. }
  192. void
  193. emc_status_done(struct scsi_xfer *xs)
  194. {
  195. struct scsi_link *link = xs->sc_link;
  196. struct emc_softc *sc = link->device_softc;
  197. struct emc_vpd_sp_info *pg = sc->sc_pg;
  198. int status = MPATH_S_UNKNOWN;
  199. if (xs->error == XS_NOERROR) {
  200. status = (pg->lun_state == EMC_SP_INFO_LUN_STATE_OWNED) ?
  201. MPATH_S_ACTIVE : MPATH_S_PASSIVE;
  202. }
  203. scsi_xs_put(xs);
  204. mpath_path_status(&sc->sc_path, status);
  205. }
  206. int
  207. emc_sp_info(struct emc_softc *sc, int *sp)
  208. {
  209. struct emc_vpd_sp_info *pg = sc->sc_pg;
  210. int error;
  211. error = scsi_inquire_vpd(sc->sc_path.p_link, pg, sizeof(*pg),
  212. EMC_VPD_SP_INFO, scsi_autoconf);
  213. if (error != 0)
  214. return (error);
  215. *sp = pg->current_sp;
  216. printf("%s: SP-%c port %d\n", DEVNAME(sc), pg->current_sp + 'A',
  217. pg->port);
  218. return (0);
  219. }