Line data Source code
1 : /* $OpenBSD: mpath_emc.c,v 1.21 2015/03/14 03:38:52 jsg Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : /* EMC CLARiiON AX/CX support for mpath(4) */
20 :
21 : #include <sys/param.h>
22 : #include <sys/systm.h>
23 : #include <sys/kernel.h>
24 : #include <sys/malloc.h>
25 : #include <sys/device.h>
26 : #include <sys/conf.h>
27 : #include <sys/queue.h>
28 : #include <sys/rwlock.h>
29 : #include <sys/pool.h>
30 : #include <sys/ioctl.h>
31 : #include <sys/poll.h>
32 : #include <sys/selinfo.h>
33 :
34 : #include <scsi/scsi_all.h>
35 : #include <scsi/scsiconf.h>
36 : #include <scsi/mpathvar.h>
37 :
38 : #define EMC_VPD_SP_INFO 0xc0
39 :
40 : struct emc_vpd_sp_info {
41 : struct scsi_vpd_hdr hdr; /* EMC_VPD_SP_INFO */
42 :
43 : u_int8_t lun_state;
44 : #define EMC_SP_INFO_LUN_STATE_UNBOUND 0x00
45 : #define EMC_SP_INFO_LUN_STATE_BOUND 0x01
46 : #define EMC_SP_INFO_LUN_STATE_OWNED 0x02
47 : u_int8_t default_sp;
48 : u_int8_t _reserved1[1];
49 : u_int8_t port;
50 : u_int8_t current_sp;
51 : u_int8_t _reserved2[1];
52 : u_int8_t unique_id[16];
53 : u_int8_t _reserved3[1];
54 : u_int8_t type;
55 : u_int8_t failover_mode;
56 : u_int8_t _reserved4[21];
57 : u_int8_t serial[16];
58 : } __packed;
59 :
60 : struct emc_softc {
61 : struct device sc_dev;
62 : struct mpath_path sc_path;
63 : struct scsi_xshandler sc_xsh;
64 : struct emc_vpd_sp_info *sc_pg;
65 : };
66 : #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
67 :
68 : int emc_match(struct device *, void *, void *);
69 : void emc_attach(struct device *, struct device *, void *);
70 : int emc_detach(struct device *, int);
71 : int emc_activate(struct device *, int);
72 :
73 : struct cfattach emc_ca = {
74 : sizeof(struct emc_softc),
75 : emc_match,
76 : emc_attach,
77 : emc_detach,
78 : emc_activate
79 : };
80 :
81 : struct cfdriver emc_cd = {
82 : NULL,
83 : "emc",
84 : DV_DULL
85 : };
86 :
87 : void emc_mpath_start(struct scsi_xfer *);
88 : int emc_mpath_checksense(struct scsi_xfer *);
89 : void emc_mpath_status(struct scsi_link *);
90 :
91 : const struct mpath_ops emc_mpath_ops = {
92 : "emc",
93 : emc_mpath_checksense,
94 : emc_mpath_status
95 : };
96 :
97 : struct emc_device {
98 : char *vendor;
99 : char *product;
100 : };
101 :
102 : void emc_status(struct scsi_xfer *);
103 : void emc_status_done(struct scsi_xfer *);
104 :
105 : int emc_sp_info(struct emc_softc *, int *);
106 :
107 : struct emc_device emc_devices[] = {
108 : /* " vendor " " device " */
109 : /* "01234567" "0123456789012345" */
110 : { "DGC ", "RAID" },
111 : { "DGC ", "DISK" },
112 : { "DGC ", "VRAID" }
113 : };
114 :
115 : int
116 0 : emc_match(struct device *parent, void *match, void *aux)
117 : {
118 0 : struct scsi_attach_args *sa = aux;
119 0 : struct scsi_inquiry_data *inq = sa->sa_inqbuf;
120 : struct emc_device *s;
121 : int i;
122 :
123 0 : if (mpath_path_probe(sa->sa_sc_link) != 0)
124 0 : return (0);
125 :
126 0 : for (i = 0; i < nitems(emc_devices); i++) {
127 0 : s = &emc_devices[i];
128 :
129 0 : if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
130 0 : bcmp(s->product, inq->product, strlen(s->product)) == 0)
131 0 : return (8);
132 : }
133 :
134 0 : return (0);
135 0 : }
136 :
137 : void
138 0 : emc_attach(struct device *parent, struct device *self, void *aux)
139 : {
140 0 : struct emc_softc *sc = (struct emc_softc *)self;
141 0 : struct scsi_attach_args *sa = aux;
142 0 : struct scsi_link *link = sa->sa_sc_link;
143 0 : int sp;
144 :
145 0 : printf("\n");
146 :
147 : /* init link */
148 0 : link->device_softc = sc;
149 :
150 : /* init path */
151 0 : scsi_xsh_set(&sc->sc_path.p_xsh, link, emc_mpath_start);
152 0 : sc->sc_path.p_link = link;
153 :
154 : /* init status handler */
155 0 : scsi_xsh_set(&sc->sc_xsh, link, emc_status);
156 0 : sc->sc_pg = dma_alloc(sizeof(*sc->sc_pg), PR_WAITOK);
157 :
158 : /* let's go */
159 :
160 0 : if (emc_sp_info(sc, &sp)) {
161 0 : printf("%s: unable to get sp info\n", DEVNAME(sc));
162 0 : return;
163 : }
164 :
165 0 : if (mpath_path_attach(&sc->sc_path, sp, &emc_mpath_ops) != 0)
166 0 : printf("%s: unable to attach path\n", DEVNAME(sc));
167 0 : }
168 :
169 : int
170 0 : emc_detach(struct device *self, int flags)
171 : {
172 0 : struct emc_softc *sc = (struct emc_softc *)self;
173 :
174 0 : dma_free(sc->sc_pg, sizeof(*sc->sc_pg));
175 :
176 0 : return (0);
177 : }
178 :
179 : int
180 0 : emc_activate(struct device *self, int act)
181 : {
182 0 : struct emc_softc *sc = (struct emc_softc *)self;
183 : int rv = 0;
184 :
185 0 : switch (act) {
186 : case DVACT_DEACTIVATE:
187 0 : if (sc->sc_path.p_group != NULL)
188 0 : mpath_path_detach(&sc->sc_path);
189 : break;
190 : }
191 0 : return (rv);
192 : }
193 :
194 : void
195 0 : emc_mpath_start(struct scsi_xfer *xs)
196 : {
197 0 : struct emc_softc *sc = xs->sc_link->device_softc;
198 :
199 0 : mpath_start(&sc->sc_path, xs);
200 0 : }
201 :
202 : int
203 0 : emc_mpath_checksense(struct scsi_xfer *xs)
204 : {
205 0 : struct scsi_sense_data *sense = &xs->sense;
206 :
207 0 : if ((sense->error_code & SSD_ERRCODE) == SSD_ERRCODE_CURRENT &&
208 0 : (sense->flags & SSD_KEY) == SKEY_NOT_READY &&
209 0 : ASC_ASCQ(sense) == 0x0403) {
210 : /* Logical Unit Not Ready, Manual Intervention Required */
211 0 : return (MPATH_SENSE_FAILOVER);
212 : }
213 :
214 0 : return (MPATH_SENSE_DECLINED);
215 0 : }
216 :
217 : void
218 0 : emc_mpath_status(struct scsi_link *link)
219 : {
220 0 : struct emc_softc *sc = link->device_softc;
221 :
222 0 : scsi_xsh_add(&sc->sc_xsh);
223 0 : }
224 :
225 : void
226 0 : emc_status(struct scsi_xfer *xs)
227 : {
228 0 : struct scsi_link *link = xs->sc_link;
229 0 : struct emc_softc *sc = link->device_softc;
230 :
231 0 : scsi_init_inquiry(xs, SI_EVPD, EMC_VPD_SP_INFO,
232 0 : sc->sc_pg, sizeof(*sc->sc_pg));
233 :
234 0 : xs->done = emc_status_done;
235 :
236 0 : scsi_xs_exec(xs);
237 0 : }
238 :
239 : void
240 0 : emc_status_done(struct scsi_xfer *xs)
241 : {
242 0 : struct scsi_link *link = xs->sc_link;
243 0 : struct emc_softc *sc = link->device_softc;
244 0 : struct emc_vpd_sp_info *pg = sc->sc_pg;
245 : int status = MPATH_S_UNKNOWN;
246 :
247 0 : if (xs->error == XS_NOERROR) {
248 0 : status = (pg->lun_state == EMC_SP_INFO_LUN_STATE_OWNED) ?
249 : MPATH_S_ACTIVE : MPATH_S_PASSIVE;
250 0 : }
251 :
252 0 : scsi_xs_put(xs);
253 :
254 0 : mpath_path_status(&sc->sc_path, status);
255 0 : }
256 :
257 : int
258 0 : emc_sp_info(struct emc_softc *sc, int *sp)
259 : {
260 0 : struct emc_vpd_sp_info *pg = sc->sc_pg;
261 : int error;
262 :
263 0 : error = scsi_inquire_vpd(sc->sc_path.p_link, pg, sizeof(*pg),
264 0 : EMC_VPD_SP_INFO, scsi_autoconf);
265 0 : if (error != 0)
266 0 : return (error);
267 :
268 0 : *sp = pg->current_sp;
269 :
270 0 : printf("%s: SP-%c port %d\n", DEVNAME(sc), pg->current_sp + 'A',
271 0 : pg->port);
272 :
273 0 : return (0);
274 0 : }
|