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

Cache object: 1db8c964b0c6bce7b4aa671c54587f5d


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