xref: /openbsd-src/sys/dev/vscsi.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /*	$OpenBSD: vscsi.c,v 1.4 2009/11/09 17:53:39 nicm 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 
198 	if (polled) {
199 		rw_enter_read(&sc->sc_ccb_polling);
200 		while (ccb->ccb_xs != NULL)
201 			tsleep(ccb, PRIBIO, "vscsipoll", 0);
202 		vscsi_ccb_put(sc, ccb);
203 		rw_exit_read(&sc->sc_ccb_polling);
204 		return (COMPLETE);
205 	}
206 
207 	return (SUCCESSFULLY_QUEUED);
208 }
209 
210 void
211 vscsi_xs_stuffup(struct scsi_xfer *xs)
212 {
213 	int				s;
214 
215 	xs->error = XS_DRIVER_STUFFUP;
216 	xs->flags |= ITSDONE;
217 	s = splbio();
218 	scsi_done(xs);
219 	splx(s);
220 }
221 
222 int
223 vscsi_probe(struct scsi_link *link)
224 {
225 	struct vscsi_softc		*sc = link->adapter_softc;
226 
227 	if (sc->sc_opened == 0)
228 		return (ENXIO);
229 
230 	return (0);
231 }
232 
233 int
234 vscsiopen(dev_t dev, int flags, int mode, struct proc *p)
235 {
236 	struct vscsi_softc		*sc = DEV2SC(dev);
237 	int				rv;
238 
239 	if (sc == NULL)
240 		return (ENXIO);
241 
242 	rv = rw_enter(&sc->sc_open, RW_WRITE | RW_NOSLEEP);
243 	if (rv != 0)
244 		return (rv);
245 
246 	pool_init(&sc->sc_ccb_pool, sizeof(struct vscsi_ccb), 0, 0, 0,
247 	    "vscsiccb", NULL);
248 	pool_setipl(&sc->sc_ccb_pool, IPL_BIO);
249 	TAILQ_INIT(&sc->sc_ccb_i2t);
250 	TAILQ_INIT(&sc->sc_ccb_t2i);
251 	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
252 	mtx_init(&sc->sc_sel_mtx, IPL_BIO);
253 
254 	sc->sc_opened = 1;
255 
256 	return (0);
257 }
258 
259 int
260 vscsiioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
261 {
262 	struct vscsi_softc		*sc = DEV2SC(dev);
263 	struct vscsi_ioc_devevent	*de = (struct vscsi_ioc_devevent *)addr;
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 	case VSCSI_REQPROBE:
283 		err = scsi_req_probe(sc->sc_scsibus, de->target, de->lun);
284 		break;
285 
286 	case VSCSI_REQDETACH:
287 		err = scsi_req_detach(sc->sc_scsibus, de->target, de->lun,
288 		    DETACH_FORCE);
289 		break;
290 
291 	default:
292 		err = ENOTTY;
293 		break;
294 	}
295 
296 	return (err);
297 }
298 
299 int
300 vscsi_i2t(struct vscsi_softc *sc, struct vscsi_ioc_i2t *i2t)
301 {
302 	struct vscsi_ccb		*ccb;
303 	struct scsi_xfer		*xs;
304 	struct scsi_link		*link;
305 
306 	mtx_enter(&sc->sc_ccb_mtx);
307 	ccb = TAILQ_FIRST(&sc->sc_ccb_i2t);
308 	if (ccb != NULL)
309 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
310 	mtx_leave(&sc->sc_ccb_mtx);
311 
312 	if (ccb == NULL)
313 		return (EAGAIN);
314 
315 	xs = ccb->ccb_xs;
316 	link = xs->sc_link;
317 
318 	i2t->tag = ccb->ccb_tag;
319 	i2t->target = link->target;
320 	i2t->lun = link->lun;
321 	bcopy(xs->cmd, &i2t->cmd, xs->cmdlen);
322 	i2t->cmdlen = xs->cmdlen;
323 	i2t->datalen = xs->datalen;
324 
325 	switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
326 	case SCSI_DATA_IN:
327 		i2t->direction = VSCSI_DIR_READ;
328 		break;
329 	case SCSI_DATA_OUT:
330 		i2t->direction = VSCSI_DIR_WRITE;
331 		break;
332 	default:
333 		i2t->direction = VSCSI_DIR_NONE;
334 		break;
335 	}
336 
337 	TAILQ_INSERT_TAIL(&sc->sc_ccb_t2i, ccb, ccb_entry);
338 
339 	return (0);
340 }
341 
342 int
343 vscsi_data(struct vscsi_softc *sc, struct vscsi_ioc_data *data, int read)
344 {
345 	struct vscsi_ccb		*ccb;
346 	struct scsi_xfer		*xs;
347 	int				xsread;
348 	u_int8_t			*buf;
349 	int				rv = EINVAL;
350 
351 	TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
352 		if (ccb->ccb_tag == data->tag)
353 			break;
354 	}
355 	if (ccb == NULL)
356 		return (EFAULT);
357 
358 	xs = ccb->ccb_xs;
359 
360 	if (data->datalen + ccb->ccb_datalen > xs->datalen)
361 		return (ENOMEM);
362 
363 	switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
364 	case SCSI_DATA_IN:
365 		xsread = 1;
366 		break;
367 	case SCSI_DATA_OUT:
368 		xsread = 0;
369 		break;
370 	default:
371 		return (EINVAL);
372 	}
373 
374 	if (read != xsread)
375 		return (EINVAL);
376 
377 	buf = xs->data;
378 	buf += ccb->ccb_datalen;
379 
380 	if (read)
381 		rv = copyin(data->data, buf, data->datalen);
382 	else
383 		rv = copyout(buf, data->data, data->datalen);
384 
385 	if (rv == 0)
386 		ccb->ccb_datalen += data->datalen;
387 
388 	return (rv);
389 }
390 
391 int
392 vscsi_t2i(struct vscsi_softc *sc, struct vscsi_ioc_t2i *t2i)
393 {
394 	struct vscsi_ccb		*ccb;
395 	struct scsi_xfer		*xs;
396 	struct scsi_link		*link;
397 	int				rv = 0;
398 	int				polled;
399 	int				s;
400 
401 	TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
402 		if (ccb->ccb_tag == t2i->tag)
403 			break;
404 	}
405 	if (ccb == NULL)
406 		return (EFAULT);
407 
408 	TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry);
409 
410 	xs = ccb->ccb_xs;
411 	link = xs->sc_link;
412 
413 	xs->resid = xs->datalen - ccb->ccb_datalen;
414 	xs->status = SCSI_OK;
415 
416 	switch (t2i->status) {
417 	case VSCSI_STAT_DONE:
418 		xs->error = XS_NOERROR;
419 		break;
420 	case VSCSI_STAT_SENSE:
421 		xs->error = XS_SENSE;
422 		bcopy(&t2i->sense, &xs->sense, t2i->senselen);
423 		xs->req_sense_length = t2i->senselen;
424 		break;
425 	case VSCSI_STAT_ERR:
426 	default:
427 		xs->error = XS_DRIVER_STUFFUP;
428 		break;
429 	}
430 
431 	polled = ISSET(xs->flags, SCSI_POLL);
432 
433 	xs->flags |= ITSDONE;
434 	s = splbio();
435 	scsi_done(xs);
436 	splx(s);
437 
438 	if (polled) {
439 		ccb->ccb_xs = NULL;
440 		wakeup(ccb);
441 	} else
442 		vscsi_ccb_put(sc, ccb);
443 
444 	return (rv);
445 }
446 
447 int
448 vscsipoll(dev_t dev, int events, struct proc *p)
449 {
450 	struct vscsi_softc		*sc = DEV2SC(dev);
451 	int				revents = 0;
452 
453 	if (events & (POLLIN | POLLRDNORM)) {
454 		mtx_enter(&sc->sc_ccb_mtx);
455 		if (!TAILQ_EMPTY(&sc->sc_ccb_i2t))
456 			revents |= events & (POLLIN | POLLRDNORM);
457 		mtx_leave(&sc->sc_ccb_mtx);
458 	}
459 
460 	if (revents == 0) {
461 		if (events & (POLLIN | POLLRDNORM))
462 			selrecord(p, &sc->sc_sel);
463 	}
464 
465 	return (revents);
466 }
467 
468 int
469 vscsikqfilter(dev_t dev, struct knote *kn)
470 {
471 	struct vscsi_softc *sc = DEV2SC(dev);
472 	struct klist *klist = &sc->sc_sel.si_note;
473 
474 	switch (kn->kn_filter) {
475 	case EVFILT_READ:
476 		kn->kn_fop = &vscsi_filtops;
477 		break;
478 	default:
479 		return (1);
480 	}
481 
482 	kn->kn_hook = (caddr_t)sc;
483 
484 	mtx_enter(&sc->sc_sel_mtx);
485 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
486 	mtx_leave(&sc->sc_sel_mtx);
487 
488 	return (0);
489 }
490 
491 void
492 filt_vscsidetach(struct knote *kn)
493 {
494 	struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook;
495 	struct klist *klist = &sc->sc_sel.si_note;
496 
497 	mtx_enter(&sc->sc_sel_mtx);
498 	SLIST_REMOVE(klist, kn, knote, kn_selnext);
499 	mtx_leave(&sc->sc_sel_mtx);
500 }
501 
502 int
503 filt_vscsiread(struct knote *kn, long hint)
504 {
505 	struct vscsi_softc *sc = (struct vscsi_softc *)kn->kn_hook;
506 	int event = 0;
507 
508 	mtx_enter(&sc->sc_ccb_mtx);
509 	if (!TAILQ_EMPTY(&sc->sc_ccb_i2t))
510 		event = 1;
511 	mtx_leave(&sc->sc_ccb_mtx);
512 
513 	return (event);
514 }
515 
516 int
517 vscsiclose(dev_t dev, int flags, int mode, struct proc *p)
518 {
519 	struct vscsi_softc		*sc = DEV2SC(dev);
520 	struct vscsi_ccb		*ccb;
521 	int				polled;
522 	int				i;
523 
524 	sc->sc_opened = 0;
525 
526 	while ((ccb = TAILQ_FIRST(&sc->sc_ccb_t2i)) != NULL) {
527 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
528 		polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL);
529 
530 		vscsi_xs_stuffup(ccb->ccb_xs);
531 
532 		if (polled) {
533 			ccb->ccb_xs = NULL;
534 			wakeup(ccb);
535 		} else
536 			vscsi_ccb_put(sc, ccb);
537 	}
538 
539 	while ((ccb = TAILQ_FIRST(&sc->sc_ccb_i2t)) != NULL) {
540 		TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
541 		polled = ISSET(ccb->ccb_xs->flags, SCSI_POLL);
542 
543 		vscsi_xs_stuffup(ccb->ccb_xs);
544 
545 		if (polled) {
546 			ccb->ccb_xs = NULL;
547 			wakeup(ccb);
548 		} else
549 			vscsi_ccb_put(sc, ccb);
550 	}
551 
552 	rw_enter_write(&sc->sc_ccb_polling);
553 	pool_destroy(&sc->sc_ccb_pool);
554 	rw_exit_write(&sc->sc_ccb_polling);
555 
556 	for (i = 0; i < sc->sc_link.adapter_buswidth; i++)
557 		scsi_detach_target(sc->sc_scsibus, i, DETACH_FORCE);
558 
559 	rw_exit(&sc->sc_open);
560 
561 	return (0);
562 }
563 
564 struct vscsi_ccb *
565 vscsi_ccb_get(struct vscsi_softc *sc, int waitok)
566 {
567 	struct vscsi_ccb		*ccb;
568 
569 	ccb = pool_get(&sc->sc_ccb_pool, waitok ? PR_WAITOK : PR_NOWAIT);
570 	if (ccb == NULL)
571 		return (NULL);
572 
573 	ccb->ccb_tag = sc->sc_ccb_tag++;
574 	ccb->ccb_datalen = 0;
575 
576 	return (ccb);
577 }
578