xref: /openbsd-src/sys/dev/vscsi.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: vscsi.c,v 1.2 2009/02/16 21:19:06 miod Exp $ */
2 
3 /*
4  * Copyright (c) 2008 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 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/buf.h>
22 #include <sys/kernel.h>
23 #include <sys/malloc.h>
24 #include <sys/device.h>
25 #include <sys/proc.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 
37 #include <dev/vscsivar.h>
38 
39 #ifdef VSCSI_DEBUG
40 #define VSCSI_D_INIT	(1<<0)
41 
42 int vscsidebug = 0;
43 
44 #define DPRINTF(_m, _p...)	do { \
45 					if (ISSET(vscsidebug, (_m))) \
46 						printf(p); \
47 				} while (0)
48 #else
49 #define DPRINTF(_m, _p...)	/* _m, _p */
50 #endif
51 
52 int		vscsi_match(struct device *, void *, void *);
53 void		vscsi_attach(struct device *, struct device *, void *);
54 void		vscsi_shutdown(void *);
55 
56 struct vscsi_ccb {
57 	TAILQ_ENTRY(vscsi_ccb)	ccb_entry;
58 	int			ccb_tag;
59 	struct scsi_xfer	*ccb_xs;
60 	size_t			ccb_datalen;
61 };
62 
63 TAILQ_HEAD(vscsi_ccb_list, vscsi_ccb);
64 
65 struct vscsi_softc {
66 	struct device		sc_dev;
67 	struct scsi_link	sc_link;
68 	struct scsibus_softc	*sc_scsibus;
69 
70 	struct pool		sc_ccb_pool;
71 	struct vscsi_ccb_list	sc_ccb_i2t;
72 	struct vscsi_ccb_list	sc_ccb_t2i;
73 	int			sc_ccb_tag;
74 	struct mutex		sc_ccb_mtx;
75 	struct rwlock		sc_ccb_polling;
76 
77 	struct selinfo		sc_sel;
78 	struct mutex		sc_sel_mtx;
79 
80 	struct rwlock		sc_open;
81 	volatile int		sc_opened;
82 };
83 
84 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
85 #define DEV2SC(_d) ((struct vscsi_softc *)device_lookup(&vscsi_cd, minor(_d)))
86 
87 struct cfattach vscsi_ca = {
88 	sizeof(struct vscsi_softc),
89 	vscsi_match,
90 	vscsi_attach
91 };
92 
93 struct cfdriver vscsi_cd = {
94 	NULL,
95 	"vscsi",
96 	DV_DULL
97 };
98 
99 int		vscsi_cmd(struct scsi_xfer *);
100 int		vscsi_probe(struct scsi_link *);
101 
102 struct scsi_adapter vscsi_switch = {
103 	vscsi_cmd,
104 	scsi_minphys,
105 	vscsi_probe,
106 	NULL
107 };
108 
109 struct scsi_device vscsi_dev = {
110 	NULL, NULL, NULL, NULL
111 };
112 
113 void		vscsi_xs_stuffup(struct scsi_xfer *);
114 
115 
116 int		vscsi_i2t(struct vscsi_softc *, struct vscsi_ioc_i2t *);
117 int		vscsi_data(struct vscsi_softc *, struct vscsi_ioc_data *, int);
118 int		vscsi_t2i(struct vscsi_softc *, struct vscsi_ioc_t2i *);
119 
120 struct vscsi_ccb *	vscsi_ccb_get(struct vscsi_softc *, int);
121 #define vscsi_ccb_put(_s, _c) pool_put(&(_s)->sc_ccb_pool, (_c))
122 
123 void		filt_vscsidetach(struct knote *);
124 int		filt_vscsiread(struct knote *, long);
125 
126 struct filterops vscsi_filtops = {
127 	1,
128 	NULL,
129 	filt_vscsidetach,
130 	filt_vscsiread
131 };
132 
133 
134 int
135 vscsi_match(struct device *parent, void *match, void *aux)
136 {
137 	return (1);
138 }
139 
140 void
141 vscsi_attach(struct device *parent, struct device *self, void *aux)
142 {
143 	struct vscsi_softc		*sc = (struct vscsi_softc *)self;
144 	struct scsibus_attach_args	saa;
145 
146 	printf("\n");
147 
148 	rw_init(&sc->sc_open, DEVNAME(sc));
149 	rw_init(&sc->sc_ccb_polling, DEVNAME(sc));
150 
151 	sc->sc_link.device = &vscsi_dev;
152 	sc->sc_link.adapter = &vscsi_switch;
153 	sc->sc_link.adapter_softc = sc;
154 	sc->sc_link.adapter_target = 256;
155 	sc->sc_link.adapter_buswidth = 256;
156 	sc->sc_link.openings = 1;
157 
158 	bzero(&saa, sizeof(saa));
159 	saa.saa_sc_link = &sc->sc_link;
160 
161 	sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dev,
162 	    &saa, scsiprint);
163 }
164 
165 int
166 vscsi_cmd(struct scsi_xfer *xs)
167 {
168 	struct scsi_link		*link = xs->sc_link;
169 	struct vscsi_softc		*sc = link->adapter_softc;
170 	struct vscsi_ccb		*ccb;
171 	int				polled = ISSET(xs->flags, SCSI_POLL);
172 
173 	if (sc->sc_opened == 0) {
174 		vscsi_xs_stuffup(xs);
175 		return (COMPLETE);
176 	}
177 
178 	if (ISSET(xs->flags, SCSI_POLL) && ISSET(xs->flags, SCSI_NOSLEEP)) {
179 		printf("%s: POLL && NOSLEEP for 0x%02x\n", DEVNAME(sc),
180 		    xs->cmd->opcode);
181 		vscsi_xs_stuffup(xs);
182 		return (COMPLETE);
183 	}
184 
185 	ccb = vscsi_ccb_get(sc, ISSET(xs->flags, SCSI_NOSLEEP) ? 0 : 1);
186 	if (ccb == NULL) {
187 		vscsi_xs_stuffup(xs);
188 		return (COMPLETE);
189 	}
190 
191 	ccb->ccb_xs = xs;
192 	mtx_enter(&sc->sc_ccb_mtx);
193 	TAILQ_INSERT_TAIL(&sc->sc_ccb_i2t, ccb, ccb_entry);
194 	mtx_leave(&sc->sc_ccb_mtx);
195 
196 	selwakeup(&sc->sc_sel);
197 	KNOTE(&sc->sc_sel.si_note, 0);
198 
199 	if (polled) {
200 		rw_enter_read(&sc->sc_ccb_polling);
201 		while (ccb->ccb_xs != NULL)
202 			tsleep(ccb, PRIBIO, "vscsipoll", 0);
203 		vscsi_ccb_put(sc, ccb);
204 		rw_exit_read(&sc->sc_ccb_polling);
205 		return (COMPLETE);
206 	}
207 
208 	return (SUCCESSFULLY_QUEUED);
209 }
210 
211 void
212 vscsi_xs_stuffup(struct scsi_xfer *xs)
213 {
214 	int				s;
215 
216 	xs->error = XS_DRIVER_STUFFUP;
217 	xs->flags |= ITSDONE;
218 	s = splbio();
219 	scsi_done(xs);
220 	splx(s);
221 }
222 
223 int
224 vscsi_probe(struct scsi_link *link)
225 {
226 	struct vscsi_softc		*sc = link->adapter_softc;
227 
228 	if (sc->sc_opened == 0)
229 		return (ENXIO);
230 
231 	return (0);
232 }
233 
234 int
235 vscsiopen(dev_t dev, int flags, int mode, struct proc *p)
236 {
237 	struct vscsi_softc		*sc = DEV2SC(dev);
238 	int				rv;
239 
240 	if (sc == NULL)
241 		return (ENXIO);
242 
243 	rv = rw_enter(&sc->sc_open, RW_WRITE | RW_NOSLEEP);
244 	if (rv != 0)
245 		return (rv);
246 
247 	pool_init(&sc->sc_ccb_pool, sizeof(struct vscsi_ccb), 0, 0, 0,
248 	    "vscsiccb", NULL);
249 	pool_setipl(&sc->sc_ccb_pool, IPL_BIO);
250 	TAILQ_INIT(&sc->sc_ccb_i2t);
251 	TAILQ_INIT(&sc->sc_ccb_t2i);
252 	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
253 	mtx_init(&sc->sc_sel_mtx, IPL_BIO);
254 
255 	sc->sc_opened = 1;
256 
257 	return (0);
258 }
259 
260 int
261 vscsiioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
262 {
263 	struct vscsi_softc		*sc = DEV2SC(dev);
264 	int				read = 0;
265 	int				err = 0;
266 
267 	switch (cmd) {
268 	case VSCSI_I2T:
269 		err = vscsi_i2t(sc, (struct vscsi_ioc_i2t *)addr);
270 		break;
271 
272 	case VSCSI_DATA_READ:
273 		read = 1;
274 	case VSCSI_DATA_WRITE:
275 		err = vscsi_data(sc, (struct vscsi_ioc_data *)addr, read);
276 		break;
277 
278 	case VSCSI_T2I:
279 		err = vscsi_t2i(sc, (struct vscsi_ioc_t2i *)addr);
280 		break;
281 
282 	default:
283 		err = ENOTTY;
284 		break;
285 	}
286 
287 	return (err);
288 }
289 
290 int
291 vscsi_i2t(struct vscsi_softc *sc, struct vscsi_ioc_i2t *i2t)
292 {
293 	struct vscsi_ccb		*ccb;
294 	struct scsi_xfer		*xs;
295 	struct scsi_link		*link;
296 
297 	mtx_enter(&sc->sc_ccb_mtx);
298 	ccb = TAILQ_FIRST(&sc->sc_ccb_i2t);
299 	if (ccb != NULL)
300 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
301 	mtx_leave(&sc->sc_ccb_mtx);
302 
303 	if (ccb == NULL)
304 		return (EAGAIN);
305 
306 	xs = ccb->ccb_xs;
307 	link = xs->sc_link;
308 
309 	i2t->tag = ccb->ccb_tag;
310 	i2t->target = link->target;
311 	i2t->lun = link->lun;
312 	bcopy(xs->cmd, &i2t->cmd, xs->cmdlen);
313 	i2t->cmdlen = xs->cmdlen;
314 	i2t->datalen = xs->datalen;
315 
316 	switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
317 	case SCSI_DATA_IN:
318 		i2t->direction = VSCSI_DIR_READ;
319 		break;
320 	case SCSI_DATA_OUT:
321 		i2t->direction = VSCSI_DIR_WRITE;
322 		break;
323 	default:
324 		i2t->direction = VSCSI_DIR_NONE;
325 		break;
326 	}
327 
328 	TAILQ_INSERT_TAIL(&sc->sc_ccb_t2i, ccb, ccb_entry);
329 
330 	return (0);
331 }
332 
333 int
334 vscsi_data(struct vscsi_softc *sc, struct vscsi_ioc_data *data, int read)
335 {
336 	struct vscsi_ccb		*ccb;
337 	struct scsi_xfer		*xs;
338 	int				xsread;
339 	u_int8_t			*buf;
340 	int				rv = EINVAL;
341 
342 	TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
343 		if (ccb->ccb_tag == data->tag)
344 			break;
345 	}
346 	if (ccb == NULL)
347 		return (EFAULT);
348 
349 	xs = ccb->ccb_xs;
350 
351 	if (data->datalen + ccb->ccb_datalen > xs->datalen)
352 		return (ENOMEM);
353 
354 	switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
355 	case SCSI_DATA_IN:
356 		xsread = 1;
357 		break;
358 	case SCSI_DATA_OUT:
359 		xsread = 0;
360 		break;
361 	default:
362 		return (EINVAL);
363 	}
364 
365 	if (read != xsread)
366 		return (EINVAL);
367 
368 	buf = xs->data;
369 	buf += ccb->ccb_datalen;
370 
371 	if (read)
372 		rv = copyin(data->data, buf, data->datalen);
373 	else
374 		rv = copyout(buf, data->data, data->datalen);
375 
376 	if (rv == 0)
377 		ccb->ccb_datalen += data->datalen;
378 
379 	return (rv);
380 }
381 
382 int
383 vscsi_t2i(struct vscsi_softc *sc, struct vscsi_ioc_t2i *t2i)
384 {
385 	struct vscsi_ccb		*ccb;
386 	struct scsi_xfer		*xs;
387 	struct scsi_link		*link;
388 	int				rv = 0;
389 	int				polled;
390 	int				s;
391 
392 	TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
393 		if (ccb->ccb_tag == t2i->tag)
394 			break;
395 	}
396 	if (ccb == NULL)
397 		return (EFAULT);
398 
399 	TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry);
400 
401 	xs = ccb->ccb_xs;
402 	link = xs->sc_link;
403 
404 	xs->resid = xs->datalen - ccb->ccb_datalen;
405 	xs->status = SCSI_OK;
406 
407 	switch (t2i->status) {
408 	case VSCSI_STAT_DONE:
409 		xs->error = XS_NOERROR;
410 		break;
411 	case VSCSI_STAT_SENSE:
412 		xs->error = XS_SENSE;
413 		bcopy(&t2i->sense, &xs->sense, t2i->senselen);
414 		xs->req_sense_length = t2i->senselen;
415 		break;
416 	case VSCSI_STAT_ERR:
417 	default:
418 		xs->error = XS_DRIVER_STUFFUP;
419 		break;
420 	}
421 
422 	polled = ISSET(xs->flags, SCSI_POLL);
423 
424 	xs->flags |= ITSDONE;
425 	s = splbio();
426 	scsi_done(xs);
427 	splx(s);
428 
429 	if (polled) {
430 		ccb->ccb_xs = NULL;
431 		wakeup(ccb);
432 	} else
433 		vscsi_ccb_put(sc, ccb);
434 
435 	return (rv);
436 }
437 
438 int
439 vscsipoll(dev_t dev, int events, struct proc *p)
440 {
441 	struct vscsi_softc		*sc = DEV2SC(dev);
442 	int				revents = 0;
443 
444 	if (events & (POLLIN | POLLRDNORM)) {
445 		mtx_enter(&sc->sc_ccb_mtx);
446 		if (!TAILQ_EMPTY(&sc->sc_ccb_i2t))
447 			revents |= events & (POLLIN | POLLRDNORM);
448 		mtx_leave(&sc->sc_ccb_mtx);
449 	}
450 
451 	if (revents == 0) {
452 		if (events & (POLLIN | POLLRDNORM))
453 			selrecord(p, &sc->sc_sel);
454 	}
455 
456 	return (revents);
457 }
458 
459 int
460 vscsikqfilter(dev_t dev, struct knote *kn)
461 {
462 	struct vscsi_softc *sc = DEV2SC(dev);
463 	struct klist *klist = &sc->sc_sel.si_note;
464 
465 	switch (kn->kn_filter) {
466 	case EVFILT_READ:
467 		kn->kn_fop = &vscsi_filtops;
468 		break;
469 	default:
470 		return (1);
471 	}
472 
473 	kn->kn_hook = (caddr_t)sc;
474 
475 	mtx_enter(&sc->sc_sel_mtx);
476 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
477 	mtx_leave(&sc->sc_sel_mtx);
478 
479 	return (0);
480 }
481 
482 void
483 filt_vscsidetach(struct knote *kn)
484 {
485 	struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook;
486 	struct klist *klist = &sc->sc_sel.si_note;
487 
488 	mtx_enter(&sc->sc_sel_mtx);
489 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
490 	mtx_leave(&sc->sc_sel_mtx);
491 }
492 
493 int
494 filt_vscsiread(struct knote *kn, long hint)
495 {
496 	struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook;
497 	int event = 0;
498 
499 	mtx_enter(&sc->sc_ccb_mtx);
500 	if (!TAILQ_EMPTY(&sc->sc_ccb_i2t))
501 		event = 1;
502 	mtx_leave(&sc->sc_ccb_mtx);
503 
504 	return (event);
505 }
506 
507 int
508 vscsiclose(dev_t dev, int flags, int mode, struct proc *p)
509 {
510 	struct vscsi_softc		*sc = DEV2SC(dev);
511 	struct vscsi_ccb		*ccb;
512 	int				polled;
513 	int				i;
514 
515 	sc->sc_opened = 0;
516 
517 	while ((ccb = TAILQ_FIRST(&sc->sc_ccb_t2i)) != NULL) {
518 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
519 		polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL);
520 
521 		vscsi_xs_stuffup(ccb->ccb_xs);
522 
523 		if (polled) {
524 			ccb->ccb_xs = NULL;
525 			wakeup(ccb);
526 		} else
527 			vscsi_ccb_put(sc, ccb);
528 	}
529 
530 	while ((ccb = TAILQ_FIRST(&sc->sc_ccb_i2t)) != NULL) {
531 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
532 		polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL);
533 
534 		vscsi_xs_stuffup(ccb->ccb_xs);
535 
536 		if (polled) {
537 			ccb->ccb_xs = NULL;
538 			wakeup(ccb);
539 		} else
540 			vscsi_ccb_put(sc, ccb);
541 	}
542 
543 	rw_enter_write(&sc->sc_ccb_polling);
544 	pool_destroy(&sc->sc_ccb_pool);
545 	rw_exit_write(&sc->sc_ccb_polling);
546 
547 	for (i = 0; i < sc->sc_link.adapter_buswidth; i++)
548 		scsi_detach_target(sc->sc_scsibus, i, DETACH_FORCE);
549 
550 	rw_exit(&sc->sc_open);
551 
552 	return (0);
553 }
554 
555 struct vscsi_ccb *
556 vscsi_ccb_get(struct vscsi_softc *sc, int waitok)
557 {
558 	struct vscsi_ccb		*ccb;
559 
560 	ccb = pool_get(&sc->sc_ccb_pool, waitok ? PR_WAITOK : PR_NOWAIT);
561 	if (ccb == NULL)
562 		return (NULL);
563 
564 	ccb->ccb_tag = sc->sc_ccb_tag++;
565 	ccb->ccb_datalen = 0;
566 
567 	return (ccb);
568 }
569