FreeBSD/Linux Kernel Cross Reference
sys/dev/vscsi.c
1 /* $OpenBSD: vscsi.c,v 1.61 2022/07/02 08:50:41 visa 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/kernel.h>
22 #include <sys/malloc.h>
23 #include <sys/device.h>
24 #include <sys/conf.h>
25 #include <sys/queue.h>
26 #include <sys/rwlock.h>
27 #include <sys/pool.h>
28 #include <sys/task.h>
29 #include <sys/ioctl.h>
30 #include <sys/selinfo.h>
31
32 #include <scsi/scsi_all.h>
33 #include <scsi/scsiconf.h>
34
35 #include <dev/vscsivar.h>
36
37 int vscsi_match(struct device *, void *, void *);
38 void vscsi_attach(struct device *, struct device *, void *);
39 void vscsi_shutdown(void *);
40
41 struct vscsi_ccb {
42 TAILQ_ENTRY(vscsi_ccb) ccb_entry;
43 int ccb_tag;
44 struct scsi_xfer *ccb_xs;
45 size_t ccb_datalen;
46 };
47
48 TAILQ_HEAD(vscsi_ccb_list, vscsi_ccb);
49
50 enum vscsi_state {
51 VSCSI_S_CLOSED,
52 VSCSI_S_CONFIG,
53 VSCSI_S_RUNNING
54 };
55
56 struct vscsi_softc {
57 struct device sc_dev;
58 struct scsibus_softc *sc_scsibus;
59
60 struct mutex sc_state_mtx;
61 enum vscsi_state sc_state;
62 u_int sc_ref_count;
63 struct pool sc_ccb_pool;
64
65 struct scsi_iopool sc_iopool;
66
67 struct vscsi_ccb_list sc_ccb_i2t;
68 struct vscsi_ccb_list sc_ccb_t2i;
69 int sc_ccb_tag;
70 struct mutex sc_poll_mtx;
71 struct rwlock sc_ioc_lock;
72
73 struct selinfo sc_sel;
74 struct mutex sc_sel_mtx;
75 };
76
77 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
78 #define DEV2SC(_d) ((struct vscsi_softc *)device_lookup(&vscsi_cd, minor(_d)))
79
80 const struct cfattach vscsi_ca = {
81 sizeof(struct vscsi_softc),
82 vscsi_match,
83 vscsi_attach
84 };
85
86 struct cfdriver vscsi_cd = {
87 NULL,
88 "vscsi",
89 DV_DULL
90 };
91
92 void vscsi_cmd(struct scsi_xfer *);
93 int vscsi_probe(struct scsi_link *);
94 void vscsi_free(struct scsi_link *);
95
96 const struct scsi_adapter vscsi_switch = {
97 vscsi_cmd, NULL, vscsi_probe, vscsi_free, NULL
98 };
99
100 int vscsi_i2t(struct vscsi_softc *, struct vscsi_ioc_i2t *);
101 int vscsi_data(struct vscsi_softc *, struct vscsi_ioc_data *, int);
102 int vscsi_t2i(struct vscsi_softc *, struct vscsi_ioc_t2i *);
103 int vscsi_devevent(struct vscsi_softc *, u_long,
104 struct vscsi_ioc_devevent *);
105 void vscsi_devevent_task(void *);
106 void vscsi_done(struct vscsi_softc *, struct vscsi_ccb *);
107
108 void * vscsi_ccb_get(void *);
109 void vscsi_ccb_put(void *, void *);
110
111 void filt_vscsidetach(struct knote *);
112 int filt_vscsiread(struct knote *, long);
113
114 const struct filterops vscsi_filtops = {
115 .f_flags = FILTEROP_ISFD,
116 .f_attach = NULL,
117 .f_detach = filt_vscsidetach,
118 .f_event = filt_vscsiread,
119 };
120
121
122 int
123 vscsi_match(struct device *parent, void *match, void *aux)
124 {
125 return (1);
126 }
127
128 void
129 vscsi_attach(struct device *parent, struct device *self, void *aux)
130 {
131 struct vscsi_softc *sc = (struct vscsi_softc *)self;
132 struct scsibus_attach_args saa;
133
134 printf("\n");
135
136 mtx_init(&sc->sc_state_mtx, IPL_BIO);
137 sc->sc_state = VSCSI_S_CLOSED;
138
139 TAILQ_INIT(&sc->sc_ccb_i2t);
140 TAILQ_INIT(&sc->sc_ccb_t2i);
141 mtx_init(&sc->sc_poll_mtx, IPL_BIO);
142 mtx_init(&sc->sc_sel_mtx, IPL_BIO);
143 rw_init(&sc->sc_ioc_lock, "vscsiioc");
144 scsi_iopool_init(&sc->sc_iopool, sc, vscsi_ccb_get, vscsi_ccb_put);
145
146 saa.saa_adapter = &vscsi_switch;
147 saa.saa_adapter_softc = sc;
148 saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET;
149 saa.saa_adapter_buswidth = 256;
150 saa.saa_luns = 8;
151 saa.saa_openings = 16;
152 saa.saa_pool = &sc->sc_iopool;
153 saa.saa_quirks = saa.saa_flags = 0;
154 saa.saa_wwpn = saa.saa_wwnn = 0;
155
156 sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dev,
157 &saa, scsiprint);
158 }
159
160 void
161 vscsi_cmd(struct scsi_xfer *xs)
162 {
163 struct scsi_link *link = xs->sc_link;
164 struct vscsi_softc *sc = link->bus->sb_adapter_softc;
165 struct vscsi_ccb *ccb = xs->io;
166 int polled = ISSET(xs->flags, SCSI_POLL);
167 int running = 0;
168
169 if (ISSET(xs->flags, SCSI_POLL) && ISSET(xs->flags, SCSI_NOSLEEP)) {
170 printf("%s: POLL && NOSLEEP for 0x%02x\n", DEVNAME(sc),
171 xs->cmd.opcode);
172 xs->error = XS_DRIVER_STUFFUP;
173 scsi_done(xs);
174 return;
175 }
176
177 ccb->ccb_xs = xs;
178
179 mtx_enter(&sc->sc_state_mtx);
180 if (sc->sc_state == VSCSI_S_RUNNING) {
181 running = 1;
182 TAILQ_INSERT_TAIL(&sc->sc_ccb_i2t, ccb, ccb_entry);
183 }
184 mtx_leave(&sc->sc_state_mtx);
185
186 if (!running) {
187 xs->error = XS_DRIVER_STUFFUP;
188 scsi_done(xs);
189 return;
190 }
191
192 selwakeup(&sc->sc_sel);
193
194 if (polled) {
195 mtx_enter(&sc->sc_poll_mtx);
196 while (ccb->ccb_xs != NULL)
197 msleep_nsec(ccb, &sc->sc_poll_mtx, PRIBIO, "vscsipoll",
198 INFSLP);
199 mtx_leave(&sc->sc_poll_mtx);
200 scsi_done(xs);
201 }
202 }
203
204 void
205 vscsi_done(struct vscsi_softc *sc, struct vscsi_ccb *ccb)
206 {
207 struct scsi_xfer *xs = ccb->ccb_xs;
208
209 if (ISSET(xs->flags, SCSI_POLL)) {
210 mtx_enter(&sc->sc_poll_mtx);
211 ccb->ccb_xs = NULL;
212 wakeup(ccb);
213 mtx_leave(&sc->sc_poll_mtx);
214 } else
215 scsi_done(xs);
216 }
217
218 int
219 vscsi_probe(struct scsi_link *link)
220 {
221 struct vscsi_softc *sc = link->bus->sb_adapter_softc;
222 int rv = 0;
223
224 mtx_enter(&sc->sc_state_mtx);
225 if (sc->sc_state == VSCSI_S_RUNNING)
226 sc->sc_ref_count++;
227 else
228 rv = ENXIO;
229 mtx_leave(&sc->sc_state_mtx);
230
231 return (rv);
232 }
233
234 void
235 vscsi_free(struct scsi_link *link)
236 {
237 struct vscsi_softc *sc = link->bus->sb_adapter_softc;
238
239 mtx_enter(&sc->sc_state_mtx);
240 sc->sc_ref_count--;
241 if (sc->sc_state != VSCSI_S_RUNNING && sc->sc_ref_count == 0)
242 wakeup(&sc->sc_ref_count);
243 mtx_leave(&sc->sc_state_mtx);
244 }
245
246 int
247 vscsiopen(dev_t dev, int flags, int mode, struct proc *p)
248 {
249 struct vscsi_softc *sc = DEV2SC(dev);
250 enum vscsi_state state = VSCSI_S_RUNNING;
251 int rv = 0;
252
253 if (sc == NULL)
254 return (ENXIO);
255
256 mtx_enter(&sc->sc_state_mtx);
257 if (sc->sc_state != VSCSI_S_CLOSED)
258 rv = EBUSY;
259 else
260 sc->sc_state = VSCSI_S_CONFIG;
261 mtx_leave(&sc->sc_state_mtx);
262
263 if (rv != 0) {
264 device_unref(&sc->sc_dev);
265 return (rv);
266 }
267
268 pool_init(&sc->sc_ccb_pool, sizeof(struct vscsi_ccb), 0, IPL_BIO, 0,
269 "vscsiccb", NULL);
270
271 /* we need to guarantee some ccbs will be available for the iopool */
272 rv = pool_prime(&sc->sc_ccb_pool, 8);
273 if (rv != 0) {
274 pool_destroy(&sc->sc_ccb_pool);
275 state = VSCSI_S_CLOSED;
276 }
277
278 /* commit changes */
279 mtx_enter(&sc->sc_state_mtx);
280 sc->sc_state = state;
281 mtx_leave(&sc->sc_state_mtx);
282
283 device_unref(&sc->sc_dev);
284 return (rv);
285 }
286
287 int
288 vscsiioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
289 {
290 struct vscsi_softc *sc = DEV2SC(dev);
291 int read = 0;
292 int err = 0;
293
294 if (sc == NULL)
295 return (ENXIO);
296
297 rw_enter_write(&sc->sc_ioc_lock);
298
299 switch (cmd) {
300 case VSCSI_I2T:
301 err = vscsi_i2t(sc, (struct vscsi_ioc_i2t *)addr);
302 break;
303
304 case VSCSI_DATA_READ:
305 read = 1;
306 case VSCSI_DATA_WRITE:
307 err = vscsi_data(sc, (struct vscsi_ioc_data *)addr, read);
308 break;
309
310 case VSCSI_T2I:
311 err = vscsi_t2i(sc, (struct vscsi_ioc_t2i *)addr);
312 break;
313
314 case VSCSI_REQPROBE:
315 case VSCSI_REQDETACH:
316 err = vscsi_devevent(sc, cmd,
317 (struct vscsi_ioc_devevent *)addr);
318 break;
319
320 default:
321 err = ENOTTY;
322 break;
323 }
324
325 rw_exit_write(&sc->sc_ioc_lock);
326
327 device_unref(&sc->sc_dev);
328 return (err);
329 }
330
331 int
332 vscsi_i2t(struct vscsi_softc *sc, struct vscsi_ioc_i2t *i2t)
333 {
334 struct vscsi_ccb *ccb;
335 struct scsi_xfer *xs;
336 struct scsi_link *link;
337
338 mtx_enter(&sc->sc_state_mtx);
339 ccb = TAILQ_FIRST(&sc->sc_ccb_i2t);
340 if (ccb != NULL)
341 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
342 mtx_leave(&sc->sc_state_mtx);
343
344 if (ccb == NULL)
345 return (EAGAIN);
346
347 xs = ccb->ccb_xs;
348 link = xs->sc_link;
349
350 i2t->tag = ccb->ccb_tag;
351 i2t->target = link->target;
352 i2t->lun = link->lun;
353 memcpy(&i2t->cmd, &xs->cmd, xs->cmdlen);
354 i2t->cmdlen = xs->cmdlen;
355 i2t->datalen = xs->datalen;
356
357 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
358 case SCSI_DATA_IN:
359 i2t->direction = VSCSI_DIR_READ;
360 break;
361 case SCSI_DATA_OUT:
362 i2t->direction = VSCSI_DIR_WRITE;
363 break;
364 default:
365 i2t->direction = VSCSI_DIR_NONE;
366 break;
367 }
368
369 TAILQ_INSERT_TAIL(&sc->sc_ccb_t2i, ccb, ccb_entry);
370
371 return (0);
372 }
373
374 int
375 vscsi_data(struct vscsi_softc *sc, struct vscsi_ioc_data *data, int read)
376 {
377 struct vscsi_ccb *ccb;
378 struct scsi_xfer *xs;
379 int xsread;
380 u_int8_t *buf;
381 int rv = EINVAL;
382
383 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
384 if (ccb->ccb_tag == data->tag)
385 break;
386 }
387 if (ccb == NULL)
388 return (EFAULT);
389
390 xs = ccb->ccb_xs;
391
392 if (data->datalen > xs->datalen - ccb->ccb_datalen)
393 return (ENOMEM);
394
395 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
396 case SCSI_DATA_IN:
397 xsread = 1;
398 break;
399 case SCSI_DATA_OUT:
400 xsread = 0;
401 break;
402 default:
403 return (EINVAL);
404 }
405
406 if (read != xsread)
407 return (EINVAL);
408
409 buf = xs->data;
410 buf += ccb->ccb_datalen;
411
412 if (read)
413 rv = copyin(data->data, buf, data->datalen);
414 else
415 rv = copyout(buf, data->data, data->datalen);
416
417 if (rv == 0)
418 ccb->ccb_datalen += data->datalen;
419
420 return (rv);
421 }
422
423 int
424 vscsi_t2i(struct vscsi_softc *sc, struct vscsi_ioc_t2i *t2i)
425 {
426 struct vscsi_ccb *ccb;
427 struct scsi_xfer *xs;
428 int rv = 0;
429
430 TAILQ_FOREACH(ccb, &sc->sc_ccb_t2i, ccb_entry) {
431 if (ccb->ccb_tag == t2i->tag)
432 break;
433 }
434 if (ccb == NULL)
435 return (EFAULT);
436
437 TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry);
438
439 xs = ccb->ccb_xs;
440
441 xs->resid = xs->datalen - ccb->ccb_datalen;
442 xs->status = SCSI_OK;
443
444 switch (t2i->status) {
445 case VSCSI_STAT_DONE:
446 xs->error = XS_NOERROR;
447 break;
448 case VSCSI_STAT_SENSE:
449 xs->error = XS_SENSE;
450 memcpy(&xs->sense, &t2i->sense, sizeof(xs->sense));
451 break;
452 case VSCSI_STAT_RESET:
453 xs->error = XS_RESET;
454 break;
455 case VSCSI_STAT_ERR:
456 default:
457 xs->error = XS_DRIVER_STUFFUP;
458 break;
459 }
460
461 vscsi_done(sc, ccb);
462
463 return (rv);
464 }
465
466 struct vscsi_devevent_task {
467 struct vscsi_softc *sc;
468 struct task t;
469 struct vscsi_ioc_devevent de;
470 u_long cmd;
471 };
472
473 int
474 vscsi_devevent(struct vscsi_softc *sc, u_long cmd,
475 struct vscsi_ioc_devevent *de)
476 {
477 struct vscsi_devevent_task *dt;
478
479 dt = malloc(sizeof(*dt), M_TEMP, M_WAITOK | M_CANFAIL);
480 if (dt == NULL)
481 return (ENOMEM);
482
483 task_set(&dt->t, vscsi_devevent_task, dt);
484 dt->sc = sc;
485 dt->de = *de;
486 dt->cmd = cmd;
487
488 device_ref(&sc->sc_dev);
489 task_add(systq, &dt->t);
490
491 return (0);
492 }
493
494 void
495 vscsi_devevent_task(void *xdt)
496 {
497 struct vscsi_devevent_task *dt = xdt;
498 struct vscsi_softc *sc = dt->sc;
499 int state;
500
501 mtx_enter(&sc->sc_state_mtx);
502 state = sc->sc_state;
503 mtx_leave(&sc->sc_state_mtx);
504
505 if (state != VSCSI_S_RUNNING)
506 goto gone;
507
508 switch (dt->cmd) {
509 case VSCSI_REQPROBE:
510 scsi_probe(sc->sc_scsibus, dt->de.target, dt->de.lun);
511 break;
512 case VSCSI_REQDETACH:
513 scsi_detach(sc->sc_scsibus, dt->de.target, dt->de.lun,
514 DETACH_FORCE);
515 break;
516 #ifdef DIAGNOSTIC
517 default:
518 panic("unexpected vscsi_devevent cmd");
519 /* NOTREACHED */
520 #endif
521 }
522
523 gone:
524 device_unref(&sc->sc_dev);
525
526 free(dt, M_TEMP, sizeof(*dt));
527 }
528
529 int
530 vscsikqfilter(dev_t dev, struct knote *kn)
531 {
532 struct vscsi_softc *sc = DEV2SC(dev);
533 struct klist *klist;
534
535 if (sc == NULL)
536 return (ENXIO);
537
538 klist = &sc->sc_sel.si_note;
539
540 switch (kn->kn_filter) {
541 case EVFILT_READ:
542 kn->kn_fop = &vscsi_filtops;
543 break;
544 default:
545 device_unref(&sc->sc_dev);
546 return (EINVAL);
547 }
548
549 kn->kn_hook = sc;
550
551 mtx_enter(&sc->sc_sel_mtx);
552 klist_insert_locked(klist, kn);
553 mtx_leave(&sc->sc_sel_mtx);
554
555 /* device ref is given to the knote in the klist */
556
557 return (0);
558 }
559
560 void
561 filt_vscsidetach(struct knote *kn)
562 {
563 struct vscsi_softc *sc = kn->kn_hook;
564 struct klist *klist = &sc->sc_sel.si_note;
565
566 mtx_enter(&sc->sc_sel_mtx);
567 klist_remove_locked(klist, kn);
568 mtx_leave(&sc->sc_sel_mtx);
569
570 device_unref(&sc->sc_dev);
571 }
572
573 int
574 filt_vscsiread(struct knote *kn, long hint)
575 {
576 struct vscsi_softc *sc = kn->kn_hook;
577 int event = 0;
578
579 mtx_enter(&sc->sc_state_mtx);
580 if (!TAILQ_EMPTY(&sc->sc_ccb_i2t))
581 event = 1;
582 mtx_leave(&sc->sc_state_mtx);
583
584 return (event);
585 }
586
587 int
588 vscsiclose(dev_t dev, int flags, int mode, struct proc *p)
589 {
590 struct vscsi_softc *sc = DEV2SC(dev);
591 struct vscsi_ccb *ccb;
592
593 if (sc == NULL)
594 return (ENXIO);
595
596 mtx_enter(&sc->sc_state_mtx);
597 KASSERT(sc->sc_state == VSCSI_S_RUNNING);
598 sc->sc_state = VSCSI_S_CONFIG;
599 mtx_leave(&sc->sc_state_mtx);
600
601 scsi_activate(sc->sc_scsibus, -1, -1, DVACT_DEACTIVATE);
602
603 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_t2i)) != NULL) {
604 TAILQ_REMOVE(&sc->sc_ccb_t2i, ccb, ccb_entry);
605 ccb->ccb_xs->error = XS_RESET;
606 vscsi_done(sc, ccb);
607 }
608
609 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_i2t)) != NULL) {
610 TAILQ_REMOVE(&sc->sc_ccb_i2t, ccb, ccb_entry);
611 ccb->ccb_xs->error = XS_RESET;
612 vscsi_done(sc, ccb);
613 }
614
615 scsi_req_detach(sc->sc_scsibus, -1, -1, DETACH_FORCE);
616
617 mtx_enter(&sc->sc_state_mtx);
618 while (sc->sc_ref_count > 0) {
619 msleep_nsec(&sc->sc_ref_count, &sc->sc_state_mtx,
620 PRIBIO, "vscsiref", INFSLP);
621 }
622 mtx_leave(&sc->sc_state_mtx);
623
624 pool_destroy(&sc->sc_ccb_pool);
625
626 mtx_enter(&sc->sc_state_mtx);
627 sc->sc_state = VSCSI_S_CLOSED;
628 mtx_leave(&sc->sc_state_mtx);
629
630 device_unref(&sc->sc_dev);
631 return (0);
632 }
633
634 void *
635 vscsi_ccb_get(void *cookie)
636 {
637 struct vscsi_softc *sc = cookie;
638 struct vscsi_ccb *ccb = NULL;
639
640 ccb = pool_get(&sc->sc_ccb_pool, PR_NOWAIT);
641 if (ccb != NULL) {
642 ccb->ccb_tag = sc->sc_ccb_tag++;
643 ccb->ccb_datalen = 0;
644 }
645
646 return (ccb);
647 }
648
649 void
650 vscsi_ccb_put(void *cookie, void *io)
651 {
652 struct vscsi_softc *sc = cookie;
653 struct vscsi_ccb *ccb = io;
654
655 pool_put(&sc->sc_ccb_pool, ccb);
656 }
Cache object: fdb444f025f86ad9a4badfe747739ac1
|