LCOV - code coverage report
Current view: top level - dev - vscsi.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 310 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13