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

Cache object: 53005e0aa049004df55d71680b095255


[ 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.