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