xref: /openbsd-src/sys/dev/vscsi.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*	$OpenBSD: vscsi.c,v 1.3 2009/08/13 19:51:49 dlg 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 	struct vscsi_ioc_devevent	*de = (struct vscsi_ioc_devevent *)addr;
265 	int				read = 0;
266 	int				err = 0;
267 
268 	switch (cmd) {
269 	case VSCSI_I2T:
270 		err = vscsi_i2t(sc, (struct vscsi_ioc_i2t *)addr);
271 		break;
272 
273 	case VSCSI_DATA_READ:
274 		read = 1;
275 	case VSCSI_DATA_WRITE:
276 		err = vscsi_data(sc, (struct vscsi_ioc_data *)addr, read);
277 		break;
278 
279 	case VSCSI_T2I:
280 		err = vscsi_t2i(sc, (struct vscsi_ioc_t2i *)addr);
281 		break;
282 
283 	case VSCSI_REQPROBE:
284 		err = scsi_req_probe(sc->sc_scsibus, de->target, de->lun);
285 		break;
286 
287 	case VSCSI_REQDETACH:
288 		err = scsi_req_detach(sc->sc_scsibus, de->target, de->lun,
289 		    DETACH_FORCE);
290 		break;
291 
292 	default:
293 		err = ENOTTY;
294 		break;
295 	}
296 
297 	return (err);
298 }
299 
300 int
301 vscsi_i2t(struct vscsi_softc *sc, struct vscsi_ioc_i2t *i2t)
302 {
303 	struct vscsi_ccb		*ccb;
304 	struct scsi_xfer		*xs;
305 	struct scsi_link		*link;
306 
307 	mtx_enter(&sc->sc_ccb_mtx);
308 	ccb = TAILQ_FIRST(&sc->sc_ccb_i2t);
309 	if (ccb != NULL)
310 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
311 	mtx_leave(&sc->sc_ccb_mtx);
312 
313 	if (ccb == NULL)
314 		return (EAGAIN);
315 
316 	xs = ccb->ccb_xs;
317 	link = xs->sc_link;
318 
319 	i2t->tag = ccb->ccb_tag;
320 	i2t->target = link->target;
321 	i2t->lun = link->lun;
322 	bcopy(xs->cmd, &i2t->cmd, xs->cmdlen);
323 	i2t->cmdlen = xs->cmdlen;
324 	i2t->datalen = xs->datalen;
325 
326 	switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
327 	case SCSI_DATA_IN:
328 		i2t->direction = VSCSI_DIR_READ;
329 		break;
330 	case SCSI_DATA_OUT:
331 		i2t->direction = VSCSI_DIR_WRITE;
332 		break;
333 	default:
334 		i2t->direction = VSCSI_DIR_NONE;
335 		break;
336 	}
337 
338 	TAILQ_INSERT_TAIL(&sc->sc_ccb_t2i, ccb, ccb_entry);
339 
340 	return (0);
341 }
342 
343 int
344 vscsi_data(struct vscsi_softc *sc, struct vscsi_ioc_data *data, int read)
345 {
346 	struct vscsi_ccb		*ccb;
347 	struct scsi_xfer		*xs;
348 	int				xsread;
349 	u_int8_t			*buf;
350 	int				rv = EINVAL;
351 
352 	TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
353 		if (ccb->ccb_tag == data->tag)
354 			break;
355 	}
356 	if (ccb == NULL)
357 		return (EFAULT);
358 
359 	xs = ccb->ccb_xs;
360 
361 	if (data->datalen + ccb->ccb_datalen > xs->datalen)
362 		return (ENOMEM);
363 
364 	switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
365 	case SCSI_DATA_IN:
366 		xsread = 1;
367 		break;
368 	case SCSI_DATA_OUT:
369 		xsread = 0;
370 		break;
371 	default:
372 		return (EINVAL);
373 	}
374 
375 	if (read != xsread)
376 		return (EINVAL);
377 
378 	buf = xs->data;
379 	buf += ccb->ccb_datalen;
380 
381 	if (read)
382 		rv = copyin(data->data, buf, data->datalen);
383 	else
384 		rv = copyout(buf, data->data, data->datalen);
385 
386 	if (rv == 0)
387 		ccb->ccb_datalen += data->datalen;
388 
389 	return (rv);
390 }
391 
392 int
393 vscsi_t2i(struct vscsi_softc *sc, struct vscsi_ioc_t2i *t2i)
394 {
395 	struct vscsi_ccb		*ccb;
396 	struct scsi_xfer		*xs;
397 	struct scsi_link		*link;
398 	int				rv = 0;
399 	int				polled;
400 	int				s;
401 
402 	TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
403 		if (ccb->ccb_tag == t2i->tag)
404 			break;
405 	}
406 	if (ccb == NULL)
407 		return (EFAULT);
408 
409 	TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry);
410 
411 	xs = ccb->ccb_xs;
412 	link = xs->sc_link;
413 
414 	xs->resid = xs->datalen - ccb->ccb_datalen;
415 	xs->status = SCSI_OK;
416 
417 	switch (t2i->status) {
418 	case VSCSI_STAT_DONE:
419 		xs->error = XS_NOERROR;
420 		break;
421 	case VSCSI_STAT_SENSE:
422 		xs->error = XS_SENSE;
423 		bcopy(&t2i->sense, &xs->sense, t2i->senselen);
424 		xs->req_sense_length = t2i->senselen;
425 		break;
426 	case VSCSI_STAT_ERR:
427 	default:
428 		xs->error = XS_DRIVER_STUFFUP;
429 		break;
430 	}
431 
432 	polled = ISSET(xs->flags, SCSI_POLL);
433 
434 	xs->flags |= ITSDONE;
435 	s = splbio();
436 	scsi_done(xs);
437 	splx(s);
438 
439 	if (polled) {
440 		ccb->ccb_xs = NULL;
441 		wakeup(ccb);
442 	} else
443 		vscsi_ccb_put(sc, ccb);
444 
445 	return (rv);
446 }
447 
448 int
449 vscsipoll(dev_t dev, int events, struct proc *p)
450 {
451 	struct vscsi_softc		*sc = DEV2SC(dev);
452 	int				revents = 0;
453 
454 	if (events & (POLLIN | POLLRDNORM)) {
455 		mtx_enter(&sc->sc_ccb_mtx);
456 		if (!TAILQ_EMPTY(&sc->sc_ccb_i2t))
457 			revents |= events & (POLLIN | POLLRDNORM);
458 		mtx_leave(&sc->sc_ccb_mtx);
459 	}
460 
461 	if (revents == 0) {
462 		if (events & (POLLIN | POLLRDNORM))
463 			selrecord(p, &sc->sc_sel);
464 	}
465 
466 	return (revents);
467 }
468 
469 int
470 vscsikqfilter(dev_t dev, struct knote *kn)
471 {
472 	struct vscsi_softc *sc = DEV2SC(dev);
473 	struct klist *klist = &sc->sc_sel.si_note;
474 
475 	switch (kn->kn_filter) {
476 	case EVFILT_READ:
477 		kn->kn_fop = &vscsi_filtops;
478 		break;
479 	default:
480 		return (1);
481 	}
482 
483 	kn->kn_hook = (caddr_t)sc;
484 
485 	mtx_enter(&sc->sc_sel_mtx);
486 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
487 	mtx_leave(&sc->sc_sel_mtx);
488 
489 	return (0);
490 }
491 
492 void
493 filt_vscsidetach(struct knote *kn)
494 {
495 	struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook;
496 	struct klist *klist = &sc->sc_sel.si_note;
497 
498 	mtx_enter(&sc->sc_sel_mtx);
499 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
500 	mtx_leave(&sc->sc_sel_mtx);
501 }
502 
503 int
504 filt_vscsiread(struct knote *kn, long hint)
505 {
506 	struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook;
507 	int event = 0;
508 
509 	mtx_enter(&sc->sc_ccb_mtx);
510 	if (!TAILQ_EMPTY(&sc->sc_ccb_i2t))
511 		event = 1;
512 	mtx_leave(&sc->sc_ccb_mtx);
513 
514 	return (event);
515 }
516 
517 int
518 vscsiclose(dev_t dev, int flags, int mode, struct proc *p)
519 {
520 	struct vscsi_softc		*sc = DEV2SC(dev);
521 	struct vscsi_ccb		*ccb;
522 	int				polled;
523 	int				i;
524 
525 	sc->sc_opened = 0;
526 
527 	while ((ccb = TAILQ_FIRST(&sc->sc_ccb_t2i)) != NULL) {
528 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
529 		polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL);
530 
531 		vscsi_xs_stuffup(ccb->ccb_xs);
532 
533 		if (polled) {
534 			ccb->ccb_xs = NULL;
535 			wakeup(ccb);
536 		} else
537 			vscsi_ccb_put(sc, ccb);
538 	}
539 
540 	while ((ccb = TAILQ_FIRST(&sc->sc_ccb_i2t)) != NULL) {
541 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
542 		polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL);
543 
544 		vscsi_xs_stuffup(ccb->ccb_xs);
545 
546 		if (polled) {
547 			ccb->ccb_xs = NULL;
548 			wakeup(ccb);
549 		} else
550 			vscsi_ccb_put(sc, ccb);
551 	}
552 
553 	rw_enter_write(&sc->sc_ccb_polling);
554 	pool_destroy(&sc->sc_ccb_pool);
555 	rw_exit_write(&sc->sc_ccb_polling);
556 
557 	for (i = 0; i < sc->sc_link.adapter_buswidth; i++)
558 		scsi_detach_target(sc->sc_scsibus, i, DETACH_FORCE);
559 
560 	rw_exit(&sc->sc_open);
561 
562 	return (0);
563 }
564 
565 struct vscsi_ccb *
566 vscsi_ccb_get(struct vscsi_softc *sc, int waitok)
567 {
568 	struct vscsi_ccb		*ccb;
569 
570 	ccb = pool_get(&sc->sc_ccb_pool, waitok ? PR_WAITOK : PR_NOWAIT);
571 	if (ccb == NULL)
572 		return (NULL);
573 
574 	ccb->ccb_tag = sc->sc_ccb_tag++;
575 	ccb->ccb_datalen = 0;
576 
577 	return (ccb);
578 }
579