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

Cache object: ce8b9f61bdbf9c5411ab7a3f22bf37fa


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