The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/scsi/scsi_target.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Generic SCSI Target Kernel Mode Driver
    3  *
    4  * Copyright (c) 2002 Nate Lawson.
    5  * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions, and the following disclaimer,
   13  *    without modification, immediately at the beginning of the file.
   14  * 2. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/conf.h>
   38 #include <sys/malloc.h>
   39 #include <sys/poll.h>
   40 #include <sys/vnode.h>
   41 #include <sys/lock.h>
   42 #include <sys/mutex.h>
   43 #include <sys/devicestat.h>
   44 #include <sys/proc.h>
   45 
   46 #include <cam/cam.h>
   47 #include <cam/cam_ccb.h>
   48 #include <cam/cam_periph.h>
   49 #include <cam/cam_xpt_periph.h>
   50 #include <cam/cam_sim.h>
   51 #include <cam/scsi/scsi_targetio.h>
   52 
   53 /* Transaction information attached to each CCB sent by the user */
   54 struct targ_cmd_descr {
   55         struct cam_periph_map_info  mapinfo;
   56         TAILQ_ENTRY(targ_cmd_descr) tqe;
   57         union ccb *user_ccb;
   58         int        priority;
   59         int        func_code;
   60 };
   61 
   62 /* Offset into the private CCB area for storing our descriptor */
   63 #define targ_descr      periph_priv.entries[1].ptr
   64 
   65 TAILQ_HEAD(descr_queue, targ_cmd_descr);
   66 
   67 typedef enum {
   68         TARG_STATE_RESV         = 0x00, /* Invalid state */
   69         TARG_STATE_OPENED       = 0x01, /* Device opened, softc initialized */
   70         TARG_STATE_LUN_ENABLED  = 0x02  /* Device enabled for a path */
   71 } targ_state;
   72 
   73 /* Per-instance device software context */
   74 struct targ_softc {
   75         /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
   76         struct ccb_queue         pending_ccb_queue;
   77 
   78         /* Command descriptors awaiting CTIO resources from the XPT */
   79         struct descr_queue       work_queue;
   80 
   81         /* Command descriptors that have been aborted back to the user. */
   82         struct descr_queue       abort_queue;
   83 
   84         /*
   85          * Queue of CCBs that have been copied out to userland, but our
   86          * userland daemon has not yet seen.
   87          */
   88         struct ccb_queue         user_ccb_queue;
   89 
   90         struct cam_periph       *periph;
   91         struct cam_path         *path;
   92         targ_state               state;
   93         struct selinfo           read_select;
   94         struct devstat           device_stats;
   95 };
   96 
   97 static d_open_t         targopen;
   98 static d_close_t        targclose;
   99 static d_read_t         targread;
  100 static d_write_t        targwrite;
  101 static d_ioctl_t        targioctl;
  102 static d_poll_t         targpoll;
  103 static d_kqfilter_t     targkqfilter;
  104 static void             targreadfiltdetach(struct knote *kn);
  105 static int              targreadfilt(struct knote *kn, long hint);
  106 static struct filterops targread_filtops =
  107         { 1, NULL, targreadfiltdetach, targreadfilt };
  108 
  109 static struct cdevsw targ_cdevsw = {
  110         .d_version =    D_VERSION,
  111         .d_flags =      D_NEEDGIANT,
  112         .d_open =       targopen,
  113         .d_close =      targclose,
  114         .d_read =       targread,
  115         .d_write =      targwrite,
  116         .d_ioctl =      targioctl,
  117         .d_poll =       targpoll,
  118         .d_name =       "targ",
  119         .d_kqfilter =   targkqfilter
  120 };
  121 
  122 static cam_status       targendislun(struct cam_path *path, int enable,
  123                                      int grp6_len, int grp7_len);
  124 static cam_status       targenable(struct targ_softc *softc,
  125                                    struct cam_path *path,
  126                                    int grp6_len, int grp7_len);
  127 static cam_status       targdisable(struct targ_softc *softc);
  128 static periph_ctor_t    targctor;
  129 static periph_dtor_t    targdtor;
  130 static periph_start_t   targstart;
  131 static int              targusermerge(struct targ_softc *softc,
  132                                       struct targ_cmd_descr *descr,
  133                                       union ccb *ccb);
  134 static int              targsendccb(struct targ_softc *softc, union ccb *ccb,
  135                                     struct targ_cmd_descr *descr);
  136 static void             targdone(struct cam_periph *periph,
  137                                  union  ccb *done_ccb);
  138 static int              targreturnccb(struct targ_softc *softc,
  139                                       union  ccb *ccb);
  140 static union ccb *      targgetccb(struct targ_softc *softc, xpt_opcode type,
  141                                    int priority);
  142 static void             targfreeccb(struct targ_softc *softc, union ccb *ccb);
  143 static struct targ_cmd_descr *
  144                         targgetdescr(struct targ_softc *softc);
  145 static periph_init_t    targinit;
  146 static void             targclone(void *arg, struct ucred *cred, char *name,
  147                                   int namelen, struct cdev **dev);
  148 static void             targasync(void *callback_arg, u_int32_t code,
  149                                   struct cam_path *path, void *arg);
  150 static void             abort_all_pending(struct targ_softc *softc);
  151 static void             notify_user(struct targ_softc *softc);
  152 static int              targcamstatus(cam_status status);
  153 static size_t           targccblen(xpt_opcode func_code);
  154 
  155 static struct periph_driver targdriver =
  156 {
  157         targinit, "targ",
  158         TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0
  159 };
  160 PERIPHDRIVER_DECLARE(targ, targdriver);
  161 
  162 static MALLOC_DEFINE(M_TARG, "TARG", "TARG data");
  163 
  164 /*
  165  * Create softc and initialize it. Only one proc can open each targ device.
  166  * There is no locking here because a periph doesn't get created until an
  167  * ioctl is issued to do so, and that can't happen until this method returns.
  168  */
  169 static int
  170 targopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  171 {
  172         struct targ_softc *softc;
  173 
  174         if (dev->si_drv1 != 0) {
  175                 return (EBUSY);
  176         }
  177         
  178         /* Mark device busy before any potentially blocking operations */
  179         dev->si_drv1 = (void *)~0;
  180 
  181         /* Create the targ device, allocate its softc, initialize it */
  182         if ((dev->si_flags & SI_NAMED) == 0) {
  183                 make_dev(&targ_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 0600,
  184                          "targ%d", dev2unit(dev));
  185         }
  186         MALLOC(softc, struct targ_softc *, sizeof(*softc), M_TARG,
  187                M_WAITOK | M_ZERO);
  188         dev->si_drv1 = softc;
  189         softc->state = TARG_STATE_OPENED;
  190         softc->periph = NULL;
  191         softc->path = NULL;
  192 
  193         TAILQ_INIT(&softc->pending_ccb_queue);
  194         TAILQ_INIT(&softc->work_queue);
  195         TAILQ_INIT(&softc->abort_queue);
  196         TAILQ_INIT(&softc->user_ccb_queue);
  197         knlist_init(&softc->read_select.si_note, NULL, NULL, NULL, NULL);
  198 
  199         return (0);
  200 }
  201 
  202 /* Disable LUN if enabled and teardown softc */
  203 static int
  204 targclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  205 {
  206         struct targ_softc     *softc;
  207         struct cam_periph     *periph;
  208         int    error;
  209 
  210         softc = (struct targ_softc *)dev->si_drv1;
  211         if ((softc->periph == NULL) ||
  212             (softc->state & TARG_STATE_LUN_ENABLED) == 0) {
  213                 destroy_dev(dev);
  214                 FREE(softc, M_TARG);
  215                 return (0);
  216         }
  217 
  218         /*
  219          * Acquire a hold on the periph so that it doesn't go away before
  220          * we are ready at the end of the function.
  221          */
  222         periph = softc->periph;
  223         cam_periph_acquire(periph);
  224         cam_periph_lock(periph);
  225         error = targdisable(softc);
  226         if (error == CAM_REQ_CMP) {
  227                 dev->si_drv1 = 0;
  228                 if (softc->periph != NULL) {
  229                         cam_periph_invalidate(softc->periph);
  230                         softc->periph = NULL;
  231                 }
  232                 destroy_dev(dev);
  233                 FREE(softc, M_TARG);
  234         }
  235         cam_periph_unlock(periph);
  236         cam_periph_release(periph);
  237 
  238         return (error);
  239 }
  240 
  241 /* Enable/disable LUNs, set debugging level */
  242 static int
  243 targioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  244 {
  245         struct targ_softc *softc;
  246         cam_status         status;
  247 
  248         softc = (struct targ_softc *)dev->si_drv1;
  249 
  250         switch (cmd) {
  251         case TARGIOCENABLE:
  252         {
  253                 struct ioc_enable_lun   *new_lun;
  254                 struct cam_path         *path;
  255                 struct cam_sim          *sim;
  256 
  257                 new_lun = (struct ioc_enable_lun *)addr;
  258                 status = xpt_create_path_unlocked(&path, /*periph*/NULL,
  259                                                   new_lun->path_id,
  260                                                   new_lun->target_id,
  261                                                   new_lun->lun_id);
  262                 if (status != CAM_REQ_CMP) {
  263                         printf("Couldn't create path, status %#x\n", status);
  264                         break;
  265                 }
  266                 sim = xpt_path_sim(path);
  267                 mtx_lock(sim->mtx);
  268                 status = targenable(softc, path, new_lun->grp6_len,
  269                                     new_lun->grp7_len);
  270                 xpt_free_path(path);
  271                 mtx_unlock(sim->mtx);
  272                 break;
  273         }
  274         case TARGIOCDISABLE:
  275                 if (softc->periph == NULL) {
  276                         status = CAM_DEV_NOT_THERE;
  277                         break;
  278                 }
  279                 cam_periph_lock(softc->periph);
  280                 status = targdisable(softc);
  281                 cam_periph_unlock(softc->periph);
  282                 break;
  283         case TARGIOCDEBUG:
  284         {
  285 #ifdef  CAMDEBUG
  286                 struct ccb_debug cdbg;
  287 
  288                 /* If no periph available, disallow debugging changes */
  289                 if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
  290                         status = CAM_DEV_NOT_THERE;
  291                         break;
  292                 }
  293                 bzero(&cdbg, sizeof cdbg);
  294                 if (*((int *)addr) != 0)
  295                         cdbg.flags = CAM_DEBUG_PERIPH;
  296                 else
  297                         cdbg.flags = CAM_DEBUG_NONE;
  298                 cam_periph_lock(softc->periph);
  299                 xpt_setup_ccb(&cdbg.ccb_h, softc->path, /*priority*/0);
  300                 cdbg.ccb_h.func_code = XPT_DEBUG;
  301                 cdbg.ccb_h.cbfcnp = targdone;
  302 
  303                 xpt_action((union ccb *)&cdbg);
  304                 cam_periph_unlock(softc->periph);
  305                 status = cdbg.ccb_h.status & CAM_STATUS_MASK;
  306 #else
  307                 status = CAM_FUNC_NOTAVAIL;
  308 #endif
  309                 break;
  310         }
  311         default:
  312                 status = CAM_PROVIDE_FAIL;
  313                 break;
  314         }
  315 
  316         return (targcamstatus(status));
  317 }
  318 
  319 /* Writes are always ready, reads wait for user_ccb_queue or abort_queue */
  320 static int
  321 targpoll(struct cdev *dev, int poll_events, struct thread *td)
  322 {
  323         struct targ_softc *softc;
  324         int     revents;
  325 
  326         softc = (struct targ_softc *)dev->si_drv1;
  327 
  328         /* Poll for write() is always ok. */
  329         revents = poll_events & (POLLOUT | POLLWRNORM);
  330         if ((poll_events & (POLLIN | POLLRDNORM)) != 0) {
  331                 /* Poll for read() depends on user and abort queues. */
  332                 cam_periph_lock(softc->periph);
  333                 if (!TAILQ_EMPTY(&softc->user_ccb_queue) ||
  334                     !TAILQ_EMPTY(&softc->abort_queue)) {
  335                         revents |= poll_events & (POLLIN | POLLRDNORM);
  336                 }
  337                 cam_periph_unlock(softc->periph);
  338                 /* Only sleep if the user didn't poll for write. */
  339                 if (revents == 0)
  340                         selrecord(td, &softc->read_select);
  341         }
  342 
  343         return (revents);
  344 }
  345 
  346 static int
  347 targkqfilter(struct cdev *dev, struct knote *kn)
  348 {
  349         struct  targ_softc *softc;
  350 
  351         softc = (struct targ_softc *)dev->si_drv1;
  352         kn->kn_hook = (caddr_t)softc;
  353         kn->kn_fop = &targread_filtops;
  354         knlist_add(&softc->read_select.si_note, kn, 0);
  355         return (0);
  356 }
  357 
  358 static void
  359 targreadfiltdetach(struct knote *kn)
  360 {
  361         struct  targ_softc *softc;
  362 
  363         softc = (struct targ_softc *)kn->kn_hook;
  364         knlist_remove(&softc->read_select.si_note, kn, 0);
  365 }
  366 
  367 /* Notify the user's kqueue when the user queue or abort queue gets a CCB */
  368 static int
  369 targreadfilt(struct knote *kn, long hint)
  370 {
  371         struct targ_softc *softc;
  372         int     retval;
  373 
  374         softc = (struct targ_softc *)kn->kn_hook;
  375         cam_periph_lock(softc->periph);
  376         retval = !TAILQ_EMPTY(&softc->user_ccb_queue) ||
  377                  !TAILQ_EMPTY(&softc->abort_queue);
  378         cam_periph_unlock(softc->periph);
  379         return (retval);
  380 }
  381 
  382 /* Send the HBA the enable/disable message */
  383 static cam_status
  384 targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len)
  385 {
  386         struct ccb_en_lun en_ccb;
  387         cam_status        status;
  388 
  389         /* Tell the lun to begin answering selects */
  390         xpt_setup_ccb(&en_ccb.ccb_h, path, /*priority*/1);
  391         en_ccb.ccb_h.func_code = XPT_EN_LUN;
  392         /* Don't need support for any vendor specific commands */
  393         en_ccb.grp6_len = grp6_len;
  394         en_ccb.grp7_len = grp7_len;
  395         en_ccb.enable = enable ? 1 : 0;
  396         xpt_action((union ccb *)&en_ccb);
  397         status = en_ccb.ccb_h.status & CAM_STATUS_MASK;
  398         if (status != CAM_REQ_CMP) {
  399                 xpt_print(path, "%sable lun CCB rejected, status %#x\n",
  400                     enable ? "en" : "dis", status);
  401         }
  402         return (status);
  403 }
  404 
  405 /* Enable target mode on a LUN, given its path */
  406 static cam_status
  407 targenable(struct targ_softc *softc, struct cam_path *path, int grp6_len,
  408            int grp7_len)
  409 {
  410         struct cam_periph *periph;
  411         struct ccb_pathinq cpi;
  412         cam_status         status;
  413 
  414         if ((softc->state & TARG_STATE_LUN_ENABLED) != 0)
  415                 return (CAM_LUN_ALRDY_ENA);
  416 
  417         /* Make sure SIM supports target mode */
  418         xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1);
  419         cpi.ccb_h.func_code = XPT_PATH_INQ;
  420         xpt_action((union ccb *)&cpi);
  421         status = cpi.ccb_h.status & CAM_STATUS_MASK;
  422         if (status != CAM_REQ_CMP) {
  423                 printf("pathinq failed, status %#x\n", status);
  424                 goto enable_fail;
  425         }
  426         if ((cpi.target_sprt & PIT_PROCESSOR) == 0) {
  427                 printf("controller does not support target mode\n");
  428                 status = CAM_FUNC_NOTAVAIL;
  429                 goto enable_fail;
  430         }
  431 
  432         /* Destroy any periph on our path if it is disabled */
  433         periph = cam_periph_find(path, "targ");
  434         if (periph != NULL) {
  435                 struct targ_softc *del_softc;
  436 
  437                 del_softc = (struct targ_softc *)periph->softc;
  438                 if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) {
  439                         cam_periph_invalidate(del_softc->periph);
  440                         del_softc->periph = NULL;
  441                 } else {
  442                         printf("Requested path still in use by targ%d\n",
  443                                periph->unit_number);
  444                         status = CAM_LUN_ALRDY_ENA;
  445                         goto enable_fail;
  446                 }
  447         }
  448 
  449         /* Create a periph instance attached to this path */
  450         status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
  451                         "targ", CAM_PERIPH_BIO, path, targasync, 0, softc);
  452         if (status != CAM_REQ_CMP) {
  453                 printf("cam_periph_alloc failed, status %#x\n", status);
  454                 goto enable_fail;
  455         }
  456 
  457         /* Ensure that the periph now exists. */
  458         if (cam_periph_find(path, "targ") == NULL) {
  459                 panic("targenable: succeeded but no periph?");
  460                 /* NOTREACHED */
  461         }
  462 
  463         /* Send the enable lun message */
  464         status = targendislun(path, /*enable*/1, grp6_len, grp7_len);
  465         if (status != CAM_REQ_CMP) {
  466                 printf("enable lun failed, status %#x\n", status);
  467                 goto enable_fail;
  468         }
  469         softc->state |= TARG_STATE_LUN_ENABLED;
  470 
  471 enable_fail:
  472         return (status);
  473 }
  474 
  475 /* Disable this softc's target instance if enabled */
  476 static cam_status
  477 targdisable(struct targ_softc *softc)
  478 {
  479         cam_status status;
  480 
  481         if ((softc->state & TARG_STATE_LUN_ENABLED) == 0)
  482                 return (CAM_REQ_CMP);
  483 
  484         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n"));
  485 
  486         /* Abort any ccbs pending on the controller */
  487         abort_all_pending(softc);
  488 
  489         /* Disable this lun */
  490         status = targendislun(softc->path, /*enable*/0,
  491                               /*grp6_len*/0, /*grp7_len*/0);
  492         if (status == CAM_REQ_CMP)
  493                 softc->state &= ~TARG_STATE_LUN_ENABLED;
  494         else
  495                 printf("Disable lun failed, status %#x\n", status);
  496 
  497         return (status);
  498 }
  499 
  500 /* Initialize a periph (called from cam_periph_alloc) */
  501 static cam_status
  502 targctor(struct cam_periph *periph, void *arg)
  503 {
  504         struct targ_softc *softc;
  505 
  506         /* Store pointer to softc for periph-driven routines */
  507         softc = (struct targ_softc *)arg;
  508         periph->softc = softc;
  509         softc->periph = periph;
  510         softc->path = periph->path;
  511         return (CAM_REQ_CMP);
  512 }
  513 
  514 static void
  515 targdtor(struct cam_periph *periph)
  516 {
  517         struct targ_softc     *softc;
  518         struct ccb_hdr        *ccb_h;
  519         struct targ_cmd_descr *descr;
  520 
  521         softc = (struct targ_softc *)periph->softc;
  522 
  523         /* 
  524          * targdisable() aborts CCBs back to the user and leaves them
  525          * on user_ccb_queue and abort_queue in case the user is still
  526          * interested in them.  We free them now.
  527          */
  528         while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)) != NULL) {
  529                 TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe);
  530                 targfreeccb(softc, (union ccb *)ccb_h);
  531         }
  532         while ((descr = TAILQ_FIRST(&softc->abort_queue)) != NULL) {
  533                 TAILQ_REMOVE(&softc->abort_queue, descr, tqe);
  534                 FREE(descr, M_TARG);
  535         }
  536 
  537         softc->periph = NULL;
  538         softc->path = NULL;
  539         periph->softc = NULL;
  540 }
  541 
  542 /* Receive CCBs from user mode proc and send them to the HBA */
  543 static int
  544 targwrite(struct cdev *dev, struct uio *uio, int ioflag)
  545 {
  546         union ccb *user_ccb;
  547         struct targ_softc *softc;
  548         struct targ_cmd_descr *descr;
  549         int write_len, error;
  550         int func_code, priority;
  551 
  552         softc = (struct targ_softc *)dev->si_drv1;
  553         write_len = error = 0;
  554         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  555                   ("write - uio_resid %d\n", uio->uio_resid));
  556         while (uio->uio_resid >= sizeof(user_ccb) && error == 0) {
  557                 union ccb *ccb;
  558 
  559                 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
  560                 if (error != 0) {
  561                         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  562                                   ("write - uiomove failed (%d)\n", error));
  563                         break;
  564                 }
  565                 priority = fuword32(&user_ccb->ccb_h.pinfo.priority);
  566                 if (priority == -1) {
  567                         error = EINVAL;
  568                         break;
  569                 }
  570                 func_code = fuword32(&user_ccb->ccb_h.func_code);
  571                 switch (func_code) {
  572                 case XPT_ACCEPT_TARGET_IO:
  573                 case XPT_IMMED_NOTIFY:
  574                         cam_periph_lock(softc->periph);
  575                         ccb = targgetccb(softc, func_code, priority);
  576                         descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
  577                         descr->user_ccb = user_ccb;
  578                         descr->func_code = func_code;
  579                         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  580                                   ("Sent ATIO/INOT (%p)\n", user_ccb));
  581                         xpt_action(ccb);
  582                         TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,
  583                                           &ccb->ccb_h,
  584                                           periph_links.tqe);
  585                         cam_periph_unlock(softc->periph);
  586                         break;
  587                 default:
  588                         cam_periph_lock(softc->periph);
  589                         if ((func_code & XPT_FC_QUEUED) != 0) {
  590                                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  591                                           ("Sending queued ccb %#x (%p)\n",
  592                                           func_code, user_ccb));
  593                                 descr = targgetdescr(softc);
  594                                 descr->user_ccb = user_ccb;
  595                                 descr->priority = priority;
  596                                 descr->func_code = func_code;
  597                                 TAILQ_INSERT_TAIL(&softc->work_queue,
  598                                                   descr, tqe);
  599                                 xpt_schedule(softc->periph, priority);
  600                         } else {
  601                                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  602                                           ("Sending inline ccb %#x (%p)\n",
  603                                           func_code, user_ccb));
  604                                 ccb = targgetccb(softc, func_code, priority);
  605                                 descr = (struct targ_cmd_descr *)
  606                                          ccb->ccb_h.targ_descr;
  607                                 descr->user_ccb = user_ccb;
  608                                 descr->priority = priority;
  609                                 descr->func_code = func_code;
  610                                 if (targusermerge(softc, descr, ccb) != EFAULT)
  611                                         targsendccb(softc, ccb, descr);
  612                                 targreturnccb(softc, ccb);
  613                         }
  614                         cam_periph_unlock(softc->periph);
  615                         break;
  616                 }
  617                 write_len += sizeof(user_ccb);
  618         }
  619         
  620         /*
  621          * If we've successfully taken in some amount of
  622          * data, return success for that data first.  If
  623          * an error is persistent, it will be reported
  624          * on the next write.
  625          */
  626         if (error != 0 && write_len == 0)
  627                 return (error);
  628         if (write_len == 0 && uio->uio_resid != 0)
  629                 return (ENOSPC);
  630         return (0);
  631 }
  632 
  633 /* Process requests (descrs) via the periph-supplied CCBs */
  634 static void
  635 targstart(struct cam_periph *periph, union ccb *start_ccb)
  636 {
  637         struct targ_softc *softc;
  638         struct targ_cmd_descr *descr, *next_descr;
  639         int error;
  640 
  641         softc = (struct targ_softc *)periph->softc;
  642         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb));
  643 
  644         descr = TAILQ_FIRST(&softc->work_queue);
  645         if (descr == NULL) {
  646                 xpt_release_ccb(start_ccb);
  647         } else {
  648                 TAILQ_REMOVE(&softc->work_queue, descr, tqe);
  649                 next_descr = TAILQ_FIRST(&softc->work_queue);
  650 
  651                 /* Initiate a transaction using the descr and supplied CCB */
  652                 error = targusermerge(softc, descr, start_ccb);
  653                 if (error == 0)
  654                         error = targsendccb(softc, start_ccb, descr);
  655                 if (error != 0) {
  656                         xpt_print(periph->path,
  657                             "targsendccb failed, err %d\n", error);
  658                         xpt_release_ccb(start_ccb);
  659                         suword(&descr->user_ccb->ccb_h.status,
  660                                CAM_REQ_CMP_ERR);
  661                         TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
  662                         notify_user(softc);
  663                 }
  664 
  665                 /* If we have more work to do, stay scheduled */
  666                 if (next_descr != NULL)
  667                         xpt_schedule(periph, next_descr->priority);
  668         }
  669 }
  670 
  671 static int
  672 targusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr,
  673               union ccb *ccb)
  674 {
  675         struct ccb_hdr *u_ccbh, *k_ccbh;
  676         size_t ccb_len;
  677         int error;
  678 
  679         u_ccbh = &descr->user_ccb->ccb_h;
  680         k_ccbh = &ccb->ccb_h;
  681 
  682         /*
  683          * There are some fields in the CCB header that need to be
  684          * preserved, the rest we get from the user ccb. (See xpt_merge_ccb)
  685          */
  686         xpt_setup_ccb(k_ccbh, softc->path, descr->priority);
  687         k_ccbh->retry_count = fuword32(&u_ccbh->retry_count);
  688         k_ccbh->func_code = descr->func_code;
  689         k_ccbh->flags = fuword32(&u_ccbh->flags);
  690         k_ccbh->timeout = fuword32(&u_ccbh->timeout);
  691         ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr);
  692         error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len);
  693         if (error != 0) {
  694                 k_ccbh->status = CAM_REQ_CMP_ERR;
  695                 return (error);
  696         }
  697 
  698         /* Translate usermode abort_ccb pointer to its kernel counterpart */
  699         if (k_ccbh->func_code == XPT_ABORT) {
  700                 struct ccb_abort *cab;
  701                 struct ccb_hdr *ccb_h;
  702 
  703                 cab = (struct ccb_abort *)ccb;
  704                 TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue,
  705                     periph_links.tqe) {
  706                         struct targ_cmd_descr *ab_descr;
  707 
  708                         ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
  709                         if (ab_descr->user_ccb == cab->abort_ccb) {
  710                                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  711                                           ("Changing abort for %p to %p\n",
  712                                           cab->abort_ccb, ccb_h));
  713                                 cab->abort_ccb = (union ccb *)ccb_h;
  714                                 break;
  715                         }
  716                 }
  717                 /* CCB not found, set appropriate status */
  718                 if (ccb_h == NULL) {
  719                         k_ccbh->status = CAM_PATH_INVALID;
  720                         error = ESRCH;
  721                 }
  722         }
  723 
  724         return (error);
  725 }
  726 
  727 /* Build and send a kernel CCB formed from descr->user_ccb */
  728 static int
  729 targsendccb(struct targ_softc *softc, union ccb *ccb,
  730             struct targ_cmd_descr *descr)
  731 {
  732         struct cam_periph_map_info *mapinfo;
  733         struct ccb_hdr *ccb_h;
  734         int error;
  735 
  736         ccb_h = &ccb->ccb_h;
  737         mapinfo = &descr->mapinfo;
  738         mapinfo->num_bufs_used = 0;
  739 
  740         /*
  741          * There's no way for the user to have a completion
  742          * function, so we put our own completion function in here.
  743          * We also stash in a reference to our descriptor so targreturnccb()
  744          * can find our mapping info.
  745          */
  746         ccb_h->cbfcnp = targdone;
  747         ccb_h->targ_descr = descr;
  748 
  749         /*
  750          * We only attempt to map the user memory into kernel space
  751          * if they haven't passed in a physical memory pointer,
  752          * and if there is actually an I/O operation to perform.
  753          * Right now cam_periph_mapmem() only supports SCSI and device
  754          * match CCBs.  For the SCSI CCBs, we only pass the CCB in if
  755          * there's actually data to map.  cam_periph_mapmem() will do the
  756          * right thing, even if there isn't data to map, but since CCBs
  757          * without data are a reasonably common occurance (e.g. test unit
  758          * ready), it will save a few cycles if we check for it here.
  759          */
  760         if (((ccb_h->flags & CAM_DATA_PHYS) == 0)
  761          && (((ccb_h->func_code == XPT_CONT_TARGET_IO)
  762             && ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE))
  763           || (ccb_h->func_code == XPT_DEV_MATCH))) {
  764 
  765                 error = cam_periph_mapmem(ccb, mapinfo);
  766 
  767                 /*
  768                  * cam_periph_mapmem returned an error, we can't continue.
  769                  * Return the error to the user.
  770                  */
  771                 if (error) {
  772                         ccb_h->status = CAM_REQ_CMP_ERR;
  773                         mapinfo->num_bufs_used = 0;
  774                         return (error);
  775                 }
  776         }
  777 
  778         /*
  779          * Once queued on the pending CCB list, this CCB will be protected
  780          * by our error recovery handler.
  781          */
  782         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb));
  783         if (XPT_FC_IS_QUEUED(ccb)) {
  784                 TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h,
  785                                   periph_links.tqe);
  786         }
  787         xpt_action(ccb);
  788 
  789         return (0);
  790 }
  791 
  792 /* Completion routine for CCBs (called at splsoftcam) */
  793 static void
  794 targdone(struct cam_periph *periph, union ccb *done_ccb)
  795 {
  796         struct targ_softc *softc;
  797         cam_status status;
  798 
  799         CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb));
  800         softc = (struct targ_softc *)periph->softc;
  801         TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h,
  802                      periph_links.tqe);
  803         status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
  804 
  805         /* If we're no longer enabled, throw away CCB */
  806         if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
  807                 targfreeccb(softc, done_ccb);
  808                 return;
  809         }
  810         /* abort_all_pending() waits for pending queue to be empty */
  811         if (TAILQ_EMPTY(&softc->pending_ccb_queue))
  812                 wakeup(&softc->pending_ccb_queue);
  813 
  814         switch (done_ccb->ccb_h.func_code) {
  815         /* All FC_*_QUEUED CCBs go back to userland */
  816         case XPT_IMMED_NOTIFY:
  817         case XPT_ACCEPT_TARGET_IO:
  818         case XPT_CONT_TARGET_IO:
  819                 TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,
  820                                   periph_links.tqe);
  821                 notify_user(softc);
  822                 break;
  823         default:
  824                 panic("targdone: impossible xpt opcode %#x",
  825                       done_ccb->ccb_h.func_code);
  826                 /* NOTREACHED */
  827         }
  828 }
  829 
  830 /* Return CCBs to the user from the user queue and abort queue */
  831 static int
  832 targread(struct cdev *dev, struct uio *uio, int ioflag)
  833 {
  834         struct descr_queue      *abort_queue;
  835         struct targ_cmd_descr   *user_descr;
  836         struct targ_softc       *softc;
  837         struct ccb_queue  *user_queue;
  838         struct ccb_hdr    *ccb_h;
  839         union  ccb        *user_ccb;
  840         int                read_len, error;
  841 
  842         error = 0;
  843         read_len = 0;
  844         softc = (struct targ_softc *)dev->si_drv1;
  845         user_queue = &softc->user_ccb_queue;
  846         abort_queue = &softc->abort_queue;
  847         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"));
  848 
  849         /* If no data is available, wait or return immediately */
  850         cam_periph_lock(softc->periph);
  851         ccb_h = TAILQ_FIRST(user_queue);
  852         user_descr = TAILQ_FIRST(abort_queue);
  853         while (ccb_h == NULL && user_descr == NULL) {
  854                 if ((ioflag & IO_NDELAY) == 0) {
  855                         error = msleep(user_queue, softc->periph->sim->mtx,
  856                             PRIBIO | PCATCH, "targrd", 0);
  857                         ccb_h = TAILQ_FIRST(user_queue);
  858                         user_descr = TAILQ_FIRST(abort_queue);
  859                         if (error != 0) {
  860                                 if (error == ERESTART) {
  861                                         continue;
  862                                 } else {
  863                                         goto read_fail;
  864                                 }
  865                         }
  866                 } else {
  867                         cam_periph_unlock(softc->periph);
  868                         return (EAGAIN);
  869                 }
  870         }
  871 
  872         /* Data is available so fill the user's buffer */
  873         while (ccb_h != NULL) {
  874                 struct targ_cmd_descr *descr;
  875 
  876                 if (uio->uio_resid < sizeof(user_ccb))
  877                         break;
  878                 TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe);
  879                 descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
  880                 user_ccb = descr->user_ccb;
  881                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  882                           ("targread ccb %p (%p)\n", ccb_h, user_ccb));
  883                 error = targreturnccb(softc, (union ccb *)ccb_h);
  884                 if (error != 0)
  885                         goto read_fail;
  886                 cam_periph_unlock(softc->periph);
  887                 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
  888                 cam_periph_lock(softc->periph);
  889                 if (error != 0)
  890                         goto read_fail;
  891                 read_len += sizeof(user_ccb);
  892 
  893                 ccb_h = TAILQ_FIRST(user_queue);
  894         }
  895 
  896         /* Flush out any aborted descriptors */
  897         while (user_descr != NULL) {
  898                 if (uio->uio_resid < sizeof(user_ccb))
  899                         break;
  900                 TAILQ_REMOVE(abort_queue, user_descr, tqe);
  901                 user_ccb = user_descr->user_ccb;
  902                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
  903                           ("targread aborted descr %p (%p)\n",
  904                           user_descr, user_ccb));
  905                 suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED);
  906                 cam_periph_unlock(softc->periph);
  907                 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
  908                 cam_periph_lock(softc->periph);
  909                 if (error != 0)
  910                         goto read_fail;
  911                 read_len += sizeof(user_ccb);
  912 
  913                 user_descr = TAILQ_FIRST(abort_queue);
  914         }
  915 
  916         /*
  917          * If we've successfully read some amount of data, don't report an
  918          * error.  If the error is persistent, it will be reported on the
  919          * next read().
  920          */
  921         if (read_len == 0 && uio->uio_resid != 0)
  922                 error = ENOSPC;
  923 
  924 read_fail:
  925         cam_periph_unlock(softc->periph);
  926         return (error);
  927 }
  928 
  929 /* Copy completed ccb back to the user */
  930 static int
  931 targreturnccb(struct targ_softc *softc, union ccb *ccb)
  932 {
  933         struct targ_cmd_descr *descr;
  934         struct ccb_hdr *u_ccbh;
  935         size_t ccb_len;
  936         int error;
  937 
  938         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb));
  939         descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
  940         u_ccbh = &descr->user_ccb->ccb_h;
  941 
  942         /* Copy out the central portion of the ccb_hdr */
  943         copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count,
  944                 offsetof(struct ccb_hdr, periph_priv) -
  945                 offsetof(struct ccb_hdr, retry_count));
  946 
  947         /* Copy out the rest of the ccb (after the ccb_hdr) */
  948         ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr);
  949         if (descr->mapinfo.num_bufs_used != 0)
  950                 cam_periph_unmapmem(ccb, &descr->mapinfo);
  951         error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len);
  952         if (error != 0) {
  953                 xpt_print(softc->path,
  954                     "targreturnccb - CCB copyout failed (%d)\n", error);
  955         }
  956         /* Free CCB or send back to devq. */
  957         targfreeccb(softc, ccb);
  958 
  959         return (error);
  960 }
  961 
  962 static union ccb *
  963 targgetccb(struct targ_softc *softc, xpt_opcode type, int priority)
  964 {
  965         union ccb *ccb;
  966         int ccb_len;
  967 
  968         ccb_len = targccblen(type);
  969         MALLOC(ccb, union ccb *, ccb_len, M_TARG, M_WAITOK);
  970         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb));
  971 
  972         xpt_setup_ccb(&ccb->ccb_h, softc->path, priority);
  973         ccb->ccb_h.func_code = type;
  974         ccb->ccb_h.cbfcnp = targdone;
  975         ccb->ccb_h.targ_descr = targgetdescr(softc);
  976         return (ccb);
  977 }
  978 
  979 static void
  980 targfreeccb(struct targ_softc *softc, union ccb *ccb)
  981 {
  982         CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n",
  983                         ccb->ccb_h.targ_descr));
  984         FREE(ccb->ccb_h.targ_descr, M_TARG);
  985 
  986         switch (ccb->ccb_h.func_code) {
  987         case XPT_ACCEPT_TARGET_IO:
  988         case XPT_IMMED_NOTIFY:
  989                 CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb));
  990                 FREE(ccb, M_TARG);
  991                 break;
  992         default:
  993                 /* Send back CCB if we got it from the periph */
  994                 if (XPT_FC_IS_QUEUED(ccb)) {
  995                         CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
  996                                         ("returning queued ccb %p\n", ccb));
  997                         xpt_release_ccb(ccb);
  998                 } else {
  999                         CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
 1000                                         ("freeing ccb %p\n", ccb));
 1001                         FREE(ccb, M_TARG);
 1002                 }
 1003                 break;
 1004         }
 1005 }
 1006 
 1007 static struct targ_cmd_descr *
 1008 targgetdescr(struct targ_softc *softc)
 1009 {
 1010         struct targ_cmd_descr *descr;
 1011 
 1012         MALLOC(descr, struct targ_cmd_descr *, sizeof(*descr), M_TARG,
 1013                M_WAITOK);
 1014         descr->mapinfo.num_bufs_used = 0;
 1015         return (descr);
 1016 }
 1017 
 1018 static void
 1019 targinit(void)
 1020 {
 1021         EVENTHANDLER_REGISTER(dev_clone, targclone, 0, 1000);
 1022 }
 1023 
 1024 static void
 1025 targclone(void *arg, struct ucred *cred, char *name, int namelen,
 1026     struct cdev **dev)
 1027 {
 1028         int u;
 1029 
 1030         if (*dev != NULL)
 1031                 return;
 1032         if (dev_stdclone(name, NULL, "targ", &u) != 1)
 1033                 return;
 1034         *dev = make_dev(&targ_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL,
 1035                         0600, "targ%d", u);
 1036         dev_ref(*dev);
 1037         (*dev)->si_flags |= SI_CHEAPCLONE;
 1038 }
 1039 
 1040 static void
 1041 targasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
 1042 {
 1043         /* All events are handled in usermode by INOTs */
 1044         panic("targasync() called, should be an INOT instead");
 1045 }
 1046 
 1047 /* Cancel all pending requests and CCBs awaiting work. */
 1048 static void
 1049 abort_all_pending(struct targ_softc *softc)
 1050 {
 1051         struct targ_cmd_descr   *descr;
 1052         struct ccb_abort         cab;
 1053         struct ccb_hdr          *ccb_h;
 1054         struct cam_sim          *sim;
 1055 
 1056         CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"));
 1057 
 1058         /* First abort the descriptors awaiting resources */
 1059         while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) {
 1060                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
 1061                           ("Aborting descr from workq %p\n", descr));
 1062                 TAILQ_REMOVE(&softc->work_queue, descr, tqe);
 1063                 TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
 1064         }
 1065 
 1066         /* 
 1067          * Then abort all pending CCBs.
 1068          * targdone() will return the aborted CCB via user_ccb_queue
 1069          */
 1070         xpt_setup_ccb(&cab.ccb_h, softc->path, /*priority*/0);
 1071         cab.ccb_h.func_code = XPT_ABORT;
 1072         cab.ccb_h.status = CAM_REQ_CMP_ERR;
 1073         TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe) {
 1074                 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
 1075                           ("Aborting pending CCB %p\n", ccb_h));
 1076                 cab.abort_ccb = (union ccb *)ccb_h;
 1077                 xpt_action((union ccb *)&cab);
 1078                 if (cab.ccb_h.status != CAM_REQ_CMP) {
 1079                         xpt_print(cab.ccb_h.path,
 1080                             "Unable to abort CCB, status %#x\n",
 1081                             cab.ccb_h.status);
 1082                 }
 1083         }
 1084 
 1085         /* If we aborted at least one pending CCB ok, wait for it. */
 1086         if (cab.ccb_h.status == CAM_REQ_CMP) {
 1087                 sim = xpt_path_sim(softc->path);
 1088                 msleep(&softc->pending_ccb_queue, sim->mtx,
 1089                        PRIBIO | PCATCH, "tgabrt", 0);
 1090         }
 1091 
 1092         /* If we aborted anything from the work queue, wakeup user. */
 1093         if (!TAILQ_EMPTY(&softc->user_ccb_queue)
 1094          || !TAILQ_EMPTY(&softc->abort_queue))
 1095                 notify_user(softc);
 1096 }
 1097 
 1098 /* Notify the user that data is ready */
 1099 static void
 1100 notify_user(struct targ_softc *softc)
 1101 {
 1102         /*
 1103          * Notify users sleeping via poll(), kqueue(), and
 1104          * blocking read().
 1105          */
 1106         selwakeuppri(&softc->read_select, PRIBIO);
 1107         KNOTE_UNLOCKED(&softc->read_select.si_note, 0);
 1108         wakeup(&softc->user_ccb_queue);
 1109 }
 1110 
 1111 /* Convert CAM status to errno values */
 1112 static int
 1113 targcamstatus(cam_status status)
 1114 {
 1115         switch (status & CAM_STATUS_MASK) {
 1116         case CAM_REQ_CMP:       /* CCB request completed without error */
 1117                 return (0);
 1118         case CAM_REQ_INPROG:    /* CCB request is in progress */
 1119                 return (EINPROGRESS);
 1120         case CAM_REQ_CMP_ERR:   /* CCB request completed with an error */
 1121                 return (EIO);
 1122         case CAM_PROVIDE_FAIL:  /* Unable to provide requested capability */
 1123                 return (ENOTTY);
 1124         case CAM_FUNC_NOTAVAIL: /* The requested function is not available */
 1125                 return (ENOTSUP);
 1126         case CAM_LUN_ALRDY_ENA: /* LUN is already enabled for target mode */
 1127                 return (EADDRINUSE);
 1128         case CAM_PATH_INVALID:  /* Supplied Path ID is invalid */
 1129         case CAM_DEV_NOT_THERE: /* SCSI Device Not Installed/there */
 1130                 return (ENOENT);
 1131         case CAM_REQ_ABORTED:   /* CCB request aborted by the host */
 1132                 return (ECANCELED);
 1133         case CAM_CMD_TIMEOUT:   /* Command timeout */
 1134                 return (ETIMEDOUT);
 1135         case CAM_REQUEUE_REQ:   /* Requeue to preserve transaction ordering */
 1136                 return (EAGAIN);
 1137         case CAM_REQ_INVALID:   /* CCB request was invalid */
 1138                 return (EINVAL);
 1139         case CAM_RESRC_UNAVAIL: /* Resource Unavailable */
 1140                 return (ENOMEM);
 1141         case CAM_BUSY:          /* CAM subsytem is busy */
 1142         case CAM_UA_ABORT:      /* Unable to abort CCB request */
 1143                 return (EBUSY);
 1144         default:
 1145                 return (ENXIO);
 1146         }
 1147 }
 1148 
 1149 static size_t
 1150 targccblen(xpt_opcode func_code)
 1151 {
 1152         int len;
 1153 
 1154         /* Codes we expect to see as a target */
 1155         switch (func_code) {
 1156         case XPT_CONT_TARGET_IO:
 1157         case XPT_SCSI_IO:
 1158                 len = sizeof(struct ccb_scsiio);
 1159                 break;
 1160         case XPT_ACCEPT_TARGET_IO:
 1161                 len = sizeof(struct ccb_accept_tio);
 1162                 break;
 1163         case XPT_IMMED_NOTIFY:
 1164                 len = sizeof(struct ccb_immed_notify);
 1165                 break;
 1166         case XPT_REL_SIMQ:
 1167                 len = sizeof(struct ccb_relsim);
 1168                 break;
 1169         case XPT_PATH_INQ:
 1170                 len = sizeof(struct ccb_pathinq);
 1171                 break;
 1172         case XPT_DEBUG:
 1173                 len = sizeof(struct ccb_debug);
 1174                 break;
 1175         case XPT_ABORT:
 1176                 len = sizeof(struct ccb_abort);
 1177                 break;
 1178         case XPT_EN_LUN:
 1179                 len = sizeof(struct ccb_en_lun);
 1180                 break;
 1181         default:
 1182                 len = sizeof(union ccb);
 1183                 break;
 1184         }
 1185 
 1186         return (len);
 1187 }

Cache object: c53af9fa250cadaa243c4c9d50fd10e3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.