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_pass.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  * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
    3  * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions, and the following disclaimer,
   11  *    without modification, immediately at the beginning of the file.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/10.1/sys/cam/scsi/scsi_pass.c 260387 2014-01-07 01:51:48Z scottl $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/types.h>
   35 #include <sys/bio.h>
   36 #include <sys/malloc.h>
   37 #include <sys/fcntl.h>
   38 #include <sys/conf.h>
   39 #include <sys/errno.h>
   40 #include <sys/devicestat.h>
   41 #include <sys/proc.h>
   42 #include <sys/taskqueue.h>
   43 
   44 #include <cam/cam.h>
   45 #include <cam/cam_ccb.h>
   46 #include <cam/cam_periph.h>
   47 #include <cam/cam_queue.h>
   48 #include <cam/cam_xpt_periph.h>
   49 #include <cam/cam_debug.h>
   50 #include <cam/cam_sim.h>
   51 #include <cam/cam_compat.h>
   52 
   53 #include <cam/scsi/scsi_all.h>
   54 #include <cam/scsi/scsi_pass.h>
   55 
   56 typedef enum {
   57         PASS_FLAG_OPEN                  = 0x01,
   58         PASS_FLAG_LOCKED                = 0x02,
   59         PASS_FLAG_INVALID               = 0x04,
   60         PASS_FLAG_INITIAL_PHYSPATH      = 0x08
   61 } pass_flags;
   62 
   63 typedef enum {
   64         PASS_STATE_NORMAL
   65 } pass_state;
   66 
   67 typedef enum {
   68         PASS_CCB_BUFFER_IO
   69 } pass_ccb_types;
   70 
   71 #define ccb_type        ppriv_field0
   72 #define ccb_bp          ppriv_ptr1
   73 
   74 struct pass_softc {
   75         pass_state       state;
   76         pass_flags       flags;
   77         u_int8_t         pd_type;
   78         union ccb        saved_ccb;
   79         int              open_count;
   80         struct devstat  *device_stats;
   81         struct cdev     *dev;
   82         struct cdev     *alias_dev;
   83         struct task      add_physpath_task;
   84 };
   85 
   86 
   87 static  d_open_t        passopen;
   88 static  d_close_t       passclose;
   89 static  d_ioctl_t       passioctl;
   90 static  d_ioctl_t       passdoioctl;
   91 
   92 static  periph_init_t   passinit;
   93 static  periph_ctor_t   passregister;
   94 static  periph_oninv_t  passoninvalidate;
   95 static  periph_dtor_t   passcleanup;
   96 static void             pass_add_physpath(void *context, int pending);
   97 static  void            passasync(void *callback_arg, u_int32_t code,
   98                                   struct cam_path *path, void *arg);
   99 static  int             passerror(union ccb *ccb, u_int32_t cam_flags, 
  100                                   u_int32_t sense_flags);
  101 static  int             passsendccb(struct cam_periph *periph, union ccb *ccb,
  102                                     union ccb *inccb);
  103 
  104 static struct periph_driver passdriver =
  105 {
  106         passinit, "pass",
  107         TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0
  108 };
  109 
  110 PERIPHDRIVER_DECLARE(pass, passdriver);
  111 
  112 static struct cdevsw pass_cdevsw = {
  113         .d_version =    D_VERSION,
  114         .d_flags =      D_TRACKCLOSE,
  115         .d_open =       passopen,
  116         .d_close =      passclose,
  117         .d_ioctl =      passioctl,
  118         .d_name =       "pass",
  119 };
  120 
  121 static void
  122 passinit(void)
  123 {
  124         cam_status status;
  125 
  126         /*
  127          * Install a global async callback.  This callback will
  128          * receive async callbacks like "new device found".
  129          */
  130         status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL);
  131 
  132         if (status != CAM_REQ_CMP) {
  133                 printf("pass: Failed to attach master async callback "
  134                        "due to status 0x%x!\n", status);
  135         }
  136 
  137 }
  138 
  139 static void
  140 passdevgonecb(void *arg)
  141 {
  142         struct cam_periph *periph;
  143         struct mtx *mtx;
  144         struct pass_softc *softc;
  145         int i;
  146 
  147         periph = (struct cam_periph *)arg;
  148         mtx = cam_periph_mtx(periph);
  149         mtx_lock(mtx);
  150 
  151         softc = (struct pass_softc *)periph->softc;
  152         KASSERT(softc->open_count >= 0, ("Negative open count %d",
  153                 softc->open_count));
  154 
  155         /*
  156          * When we get this callback, we will get no more close calls from
  157          * devfs.  So if we have any dangling opens, we need to release the
  158          * reference held for that particular context.
  159          */
  160         for (i = 0; i < softc->open_count; i++)
  161                 cam_periph_release_locked(periph);
  162 
  163         softc->open_count = 0;
  164 
  165         /*
  166          * Release the reference held for the device node, it is gone now.
  167          */
  168         cam_periph_release_locked(periph);
  169 
  170         /*
  171          * We reference the lock directly here, instead of using
  172          * cam_periph_unlock().  The reason is that the final call to
  173          * cam_periph_release_locked() above could result in the periph
  174          * getting freed.  If that is the case, dereferencing the periph
  175          * with a cam_periph_unlock() call would cause a page fault.
  176          */
  177         mtx_unlock(mtx);
  178 }
  179 
  180 static void
  181 passoninvalidate(struct cam_periph *periph)
  182 {
  183         struct pass_softc *softc;
  184 
  185         softc = (struct pass_softc *)periph->softc;
  186 
  187         /*
  188          * De-register any async callbacks.
  189          */
  190         xpt_register_async(0, passasync, periph, periph->path);
  191 
  192         softc->flags |= PASS_FLAG_INVALID;
  193 
  194         /*
  195          * Tell devfs this device has gone away, and ask for a callback
  196          * when it has cleaned up its state.
  197          */
  198         destroy_dev_sched_cb(softc->dev, passdevgonecb, periph);
  199 
  200         /*
  201          * XXX Return all queued I/O with ENXIO.
  202          * XXX Handle any transactions queued to the card
  203          *     with XPT_ABORT_CCB.
  204          */
  205 }
  206 
  207 static void
  208 passcleanup(struct cam_periph *periph)
  209 {
  210         struct pass_softc *softc;
  211 
  212         softc = (struct pass_softc *)periph->softc;
  213 
  214         devstat_remove_entry(softc->device_stats);
  215 
  216         cam_periph_unlock(periph);
  217         taskqueue_drain(taskqueue_thread, &softc->add_physpath_task);
  218 
  219         cam_periph_lock(periph);
  220 
  221         free(softc, M_DEVBUF);
  222 }
  223 
  224 static void
  225 pass_add_physpath(void *context, int pending)
  226 {
  227         struct cam_periph *periph;
  228         struct pass_softc *softc;
  229         char *physpath;
  230 
  231         /*
  232          * If we have one, create a devfs alias for our
  233          * physical path.
  234          */
  235         periph = context;
  236         softc = periph->softc;
  237         physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK);
  238         cam_periph_lock(periph);
  239         if (periph->flags & CAM_PERIPH_INVALID) {
  240                 cam_periph_unlock(periph);
  241                 goto out;
  242         }
  243         if (xpt_getattr(physpath, MAXPATHLEN,
  244                         "GEOM::physpath", periph->path) == 0
  245          && strlen(physpath) != 0) {
  246 
  247                 cam_periph_unlock(periph);
  248                 make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev,
  249                                         softc->dev, softc->alias_dev, physpath);
  250                 cam_periph_lock(periph);
  251         }
  252 
  253         /*
  254          * Now that we've made our alias, we no longer have to have a
  255          * reference to the device.
  256          */
  257         if ((softc->flags & PASS_FLAG_INITIAL_PHYSPATH) == 0) {
  258                 softc->flags |= PASS_FLAG_INITIAL_PHYSPATH;
  259                 cam_periph_unlock(periph);
  260                 dev_rel(softc->dev);
  261         }
  262         else
  263                 cam_periph_unlock(periph);
  264 
  265 out:
  266         free(physpath, M_DEVBUF);
  267 }
  268 
  269 static void
  270 passasync(void *callback_arg, u_int32_t code,
  271           struct cam_path *path, void *arg)
  272 {
  273         struct cam_periph *periph;
  274 
  275         periph = (struct cam_periph *)callback_arg;
  276 
  277         switch (code) {
  278         case AC_FOUND_DEVICE:
  279         {
  280                 struct ccb_getdev *cgd;
  281                 cam_status status;
  282  
  283                 cgd = (struct ccb_getdev *)arg;
  284                 if (cgd == NULL)
  285                         break;
  286 
  287                 /*
  288                  * Allocate a peripheral instance for
  289                  * this device and start the probe
  290                  * process.
  291                  */
  292                 status = cam_periph_alloc(passregister, passoninvalidate,
  293                                           passcleanup, NULL, "pass",
  294                                           CAM_PERIPH_BIO, path,
  295                                           passasync, AC_FOUND_DEVICE, cgd);
  296 
  297                 if (status != CAM_REQ_CMP
  298                  && status != CAM_REQ_INPROG) {
  299                         const struct cam_status_entry *entry;
  300 
  301                         entry = cam_fetch_status_entry(status);
  302 
  303                         printf("passasync: Unable to attach new device "
  304                                "due to status %#x: %s\n", status, entry ?
  305                                entry->status_text : "Unknown");
  306                 }
  307 
  308                 break;
  309         }
  310         case AC_ADVINFO_CHANGED:
  311         {
  312                 uintptr_t buftype;
  313 
  314                 buftype = (uintptr_t)arg;
  315                 if (buftype == CDAI_TYPE_PHYS_PATH) {
  316                         struct pass_softc *softc;
  317 
  318                         softc = (struct pass_softc *)periph->softc;
  319                         taskqueue_enqueue(taskqueue_thread,
  320                                           &softc->add_physpath_task);
  321                 }
  322                 break;
  323         }
  324         default:
  325                 cam_periph_async(periph, code, path, arg);
  326                 break;
  327         }
  328 }
  329 
  330 static cam_status
  331 passregister(struct cam_periph *periph, void *arg)
  332 {
  333         struct pass_softc *softc;
  334         struct ccb_getdev *cgd;
  335         struct ccb_pathinq cpi;
  336         int    no_tags;
  337 
  338         cgd = (struct ccb_getdev *)arg;
  339         if (cgd == NULL) {
  340                 printf("%s: no getdev CCB, can't register device\n", __func__);
  341                 return(CAM_REQ_CMP_ERR);
  342         }
  343 
  344         softc = (struct pass_softc *)malloc(sizeof(*softc),
  345                                             M_DEVBUF, M_NOWAIT);
  346 
  347         if (softc == NULL) {
  348                 printf("%s: Unable to probe new device. "
  349                        "Unable to allocate softc\n", __func__);
  350                 return(CAM_REQ_CMP_ERR);
  351         }
  352 
  353         bzero(softc, sizeof(*softc));
  354         softc->state = PASS_STATE_NORMAL;
  355         if (cgd->protocol == PROTO_SCSI || cgd->protocol == PROTO_ATAPI)
  356                 softc->pd_type = SID_TYPE(&cgd->inq_data);
  357         else if (cgd->protocol == PROTO_SATAPM)
  358                 softc->pd_type = T_ENCLOSURE;
  359         else
  360                 softc->pd_type = T_DIRECT;
  361 
  362         periph->softc = softc;
  363 
  364         bzero(&cpi, sizeof(cpi));
  365         xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  366         cpi.ccb_h.func_code = XPT_PATH_INQ;
  367         xpt_action((union ccb *)&cpi);
  368 
  369         /*
  370          * We pass in 0 for a blocksize, since we don't 
  371          * know what the blocksize of this device is, if 
  372          * it even has a blocksize.
  373          */
  374         cam_periph_unlock(periph);
  375         no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
  376         softc->device_stats = devstat_new_entry("pass",
  377                           periph->unit_number, 0,
  378                           DEVSTAT_NO_BLOCKSIZE
  379                           | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
  380                           softc->pd_type |
  381                           XPORT_DEVSTAT_TYPE(cpi.transport) |
  382                           DEVSTAT_TYPE_PASS,
  383                           DEVSTAT_PRIORITY_PASS);
  384 
  385         /*
  386          * Acquire a reference to the periph before we create the devfs
  387          * instance for it.  We'll release this reference once the devfs
  388          * instance has been freed.
  389          */
  390         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
  391                 xpt_print(periph->path, "%s: lost periph during "
  392                           "registration!\n", __func__);
  393                 cam_periph_lock(periph);
  394                 return (CAM_REQ_CMP_ERR);
  395         }
  396 
  397         /* Register the device */
  398         softc->dev = make_dev(&pass_cdevsw, periph->unit_number,
  399                               UID_ROOT, GID_OPERATOR, 0600, "%s%d",
  400                               periph->periph_name, periph->unit_number);
  401 
  402         /*
  403          * Now that we have made the devfs instance, hold a reference to it
  404          * until the task queue has run to setup the physical path alias.
  405          * That way devfs won't get rid of the device before we add our
  406          * alias.
  407          */
  408         dev_ref(softc->dev);
  409 
  410         cam_periph_lock(periph);
  411         softc->dev->si_drv1 = periph;
  412 
  413         TASK_INIT(&softc->add_physpath_task, /*priority*/0,
  414                   pass_add_physpath, periph);
  415 
  416         /*
  417          * See if physical path information is already available.
  418          */
  419         taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task);
  420 
  421         /*
  422          * Add an async callback so that we get notified if
  423          * this device goes away or its physical path
  424          * (stored in the advanced info data of the EDT) has
  425          * changed.
  426          */
  427         xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
  428                            passasync, periph, periph->path);
  429 
  430         if (bootverbose)
  431                 xpt_announce_periph(periph, NULL);
  432 
  433         return(CAM_REQ_CMP);
  434 }
  435 
  436 static int
  437 passopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  438 {
  439         struct cam_periph *periph;
  440         struct pass_softc *softc;
  441         int error;
  442 
  443         periph = (struct cam_periph *)dev->si_drv1;
  444         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  445                 return (ENXIO);
  446 
  447         cam_periph_lock(periph);
  448 
  449         softc = (struct pass_softc *)periph->softc;
  450 
  451         if (softc->flags & PASS_FLAG_INVALID) {
  452                 cam_periph_release_locked(periph);
  453                 cam_periph_unlock(periph);
  454                 return(ENXIO);
  455         }
  456 
  457         /*
  458          * Don't allow access when we're running at a high securelevel.
  459          */
  460         error = securelevel_gt(td->td_ucred, 1);
  461         if (error) {
  462                 cam_periph_release_locked(periph);
  463                 cam_periph_unlock(periph);
  464                 return(error);
  465         }
  466 
  467         /*
  468          * Only allow read-write access.
  469          */
  470         if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {
  471                 cam_periph_release_locked(periph);
  472                 cam_periph_unlock(periph);
  473                 return(EPERM);
  474         }
  475 
  476         /*
  477          * We don't allow nonblocking access.
  478          */
  479         if ((flags & O_NONBLOCK) != 0) {
  480                 xpt_print(periph->path, "can't do nonblocking access\n");
  481                 cam_periph_release_locked(periph);
  482                 cam_periph_unlock(periph);
  483                 return(EINVAL);
  484         }
  485 
  486         softc->open_count++;
  487 
  488         cam_periph_unlock(periph);
  489 
  490         return (error);
  491 }
  492 
  493 static int
  494 passclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  495 {
  496         struct  cam_periph *periph;
  497         struct  pass_softc *softc;
  498         struct mtx *mtx;
  499 
  500         periph = (struct cam_periph *)dev->si_drv1;
  501         if (periph == NULL)
  502                 return (ENXIO); 
  503         mtx = cam_periph_mtx(periph);
  504         mtx_lock(mtx);
  505 
  506         softc = periph->softc;
  507         softc->open_count--;
  508 
  509         cam_periph_release_locked(periph);
  510 
  511         /*
  512          * We reference the lock directly here, instead of using
  513          * cam_periph_unlock().  The reason is that the call to
  514          * cam_periph_release_locked() above could result in the periph
  515          * getting freed.  If that is the case, dereferencing the periph
  516          * with a cam_periph_unlock() call would cause a page fault.
  517          *
  518          * cam_periph_release() avoids this problem using the same method,
  519          * but we're manually acquiring and dropping the lock here to
  520          * protect the open count and avoid another lock acquisition and
  521          * release.
  522          */
  523         mtx_unlock(mtx);
  524 
  525         return (0);
  526 }
  527 
  528 static int
  529 passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  530 {
  531         int error;
  532 
  533         if ((error = passdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) {
  534                 error = cam_compat_ioctl(dev, cmd, addr, flag, td, passdoioctl);
  535         }
  536         return (error);
  537 }
  538 
  539 static int
  540 passdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  541 {
  542         struct  cam_periph *periph;
  543         struct  pass_softc *softc;
  544         int     error;
  545         uint32_t priority;
  546 
  547         periph = (struct cam_periph *)dev->si_drv1;
  548         if (periph == NULL)
  549                 return(ENXIO);
  550 
  551         cam_periph_lock(periph);
  552         softc = (struct pass_softc *)periph->softc;
  553 
  554         error = 0;
  555 
  556         switch (cmd) {
  557 
  558         case CAMIOCOMMAND:
  559         {
  560                 union ccb *inccb;
  561                 union ccb *ccb;
  562                 int ccb_malloced;
  563 
  564                 inccb = (union ccb *)addr;
  565 
  566                 /*
  567                  * Some CCB types, like scan bus and scan lun can only go
  568                  * through the transport layer device.
  569                  */
  570                 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
  571                         xpt_print(periph->path, "CCB function code %#x is "
  572                             "restricted to the XPT device\n",
  573                             inccb->ccb_h.func_code);
  574                         error = ENODEV;
  575                         break;
  576                 }
  577 
  578                 /* Compatibility for RL/priority-unaware code. */
  579                 priority = inccb->ccb_h.pinfo.priority;
  580                 if (priority <= CAM_PRIORITY_OOB)
  581                     priority += CAM_PRIORITY_OOB + 1;
  582 
  583                 /*
  584                  * Non-immediate CCBs need a CCB from the per-device pool
  585                  * of CCBs, which is scheduled by the transport layer.
  586                  * Immediate CCBs and user-supplied CCBs should just be
  587                  * malloced.
  588                  */
  589                 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
  590                  && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
  591                         ccb = cam_periph_getccb(periph, priority);
  592                         ccb_malloced = 0;
  593                 } else {
  594                         ccb = xpt_alloc_ccb_nowait();
  595 
  596                         if (ccb != NULL)
  597                                 xpt_setup_ccb(&ccb->ccb_h, periph->path,
  598                                               priority);
  599                         ccb_malloced = 1;
  600                 }
  601 
  602                 if (ccb == NULL) {
  603                         xpt_print(periph->path, "unable to allocate CCB\n");
  604                         error = ENOMEM;
  605                         break;
  606                 }
  607 
  608                 error = passsendccb(periph, ccb, inccb);
  609 
  610                 if (ccb_malloced)
  611                         xpt_free_ccb(ccb);
  612                 else
  613                         xpt_release_ccb(ccb);
  614 
  615                 break;
  616         }
  617         default:
  618                 error = cam_periph_ioctl(periph, cmd, addr, passerror);
  619                 break;
  620         }
  621 
  622         cam_periph_unlock(periph);
  623         return(error);
  624 }
  625 
  626 /*
  627  * Generally, "ccb" should be the CCB supplied by the kernel.  "inccb"
  628  * should be the CCB that is copied in from the user.
  629  */
  630 static int
  631 passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
  632 {
  633         struct pass_softc *softc;
  634         struct cam_periph_map_info mapinfo;
  635         xpt_opcode fc;
  636         int error;
  637 
  638         softc = (struct pass_softc *)periph->softc;
  639 
  640         /*
  641          * There are some fields in the CCB header that need to be
  642          * preserved, the rest we get from the user.
  643          */
  644         xpt_merge_ccb(ccb, inccb);
  645 
  646         /*
  647          * Let cam_periph_mapmem do a sanity check on the data pointer format.
  648          * Even if no data transfer is needed, it's a cheap check and it
  649          * simplifies the code.
  650          */
  651         fc = ccb->ccb_h.func_code;
  652         if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO)
  653          || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) {
  654                 bzero(&mapinfo, sizeof(mapinfo));
  655 
  656                 /*
  657                  * cam_periph_mapmem calls into proc and vm functions that can
  658                  * sleep as well as trigger I/O, so we can't hold the lock.
  659                  * Dropping it here is reasonably safe.
  660                  */
  661                 cam_periph_unlock(periph);
  662                 error = cam_periph_mapmem(ccb, &mapinfo); 
  663                 cam_periph_lock(periph);
  664 
  665                 /*
  666                  * cam_periph_mapmem returned an error, we can't continue.
  667                  * Return the error to the user.
  668                  */
  669                 if (error)
  670                         return(error);
  671         } else
  672                 /* Ensure that the unmap call later on is a no-op. */
  673                 mapinfo.num_bufs_used = 0;
  674 
  675         /*
  676          * If the user wants us to perform any error recovery, then honor
  677          * that request.  Otherwise, it's up to the user to perform any
  678          * error recovery.
  679          */
  680         cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO,
  681             /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
  682              SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT,
  683             softc->device_stats);
  684 
  685         cam_periph_unmapmem(ccb, &mapinfo);
  686 
  687         ccb->ccb_h.cbfcnp = NULL;
  688         ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
  689         bcopy(ccb, inccb, sizeof(union ccb));
  690 
  691         return(0);
  692 }
  693 
  694 static int
  695 passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  696 {
  697         struct cam_periph *periph;
  698         struct pass_softc *softc;
  699 
  700         periph = xpt_path_periph(ccb->ccb_h.path);
  701         softc = (struct pass_softc *)periph->softc;
  702         
  703         return(cam_periph_error(ccb, cam_flags, sense_flags, 
  704                                  &softc->saved_ccb));
  705 }

Cache object: 01752aecb5f5bc51625afffb8d3a9073


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