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

Cache object: dc99cf558023e8b90f269ba10ee15361


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