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_sg.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) 2007 Scott Long
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions, and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   11  * 2. The name of the author may not be used to endorse or promote products
   12  *    derived from this software without specific prior written permission.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * scsi_sg peripheral driver.  This driver is meant to implement the Linux
   29  * SG passthrough interface for SCSI.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/10.1/sys/cam/scsi/scsi_sg.c 268255 2014-07-04 15:09:56Z mav $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/types.h>
   39 #include <sys/bio.h>
   40 #include <sys/malloc.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/ioccom.h>
   43 #include <sys/conf.h>
   44 #include <sys/errno.h>
   45 #include <sys/devicestat.h>
   46 #include <sys/proc.h>
   47 #include <sys/uio.h>
   48 
   49 #include <cam/cam.h>
   50 #include <cam/cam_ccb.h>
   51 #include <cam/cam_periph.h>
   52 #include <cam/cam_queue.h>
   53 #include <cam/cam_xpt_periph.h>
   54 #include <cam/cam_debug.h>
   55 #include <cam/cam_sim.h>
   56 
   57 #include <cam/scsi/scsi_all.h>
   58 #include <cam/scsi/scsi_message.h>
   59 #include <cam/scsi/scsi_sg.h>
   60 
   61 #include <compat/linux/linux_ioctl.h>
   62 
   63 typedef enum {
   64         SG_FLAG_LOCKED          = 0x01,
   65         SG_FLAG_INVALID         = 0x02
   66 } sg_flags;
   67 
   68 typedef enum {
   69         SG_STATE_NORMAL
   70 } sg_state;
   71 
   72 typedef enum {
   73         SG_RDWR_FREE,
   74         SG_RDWR_INPROG,
   75         SG_RDWR_DONE
   76 } sg_rdwr_state;
   77 
   78 typedef enum {
   79         SG_CCB_RDWR_IO
   80 } sg_ccb_types;
   81 
   82 #define ccb_type        ppriv_field0
   83 #define ccb_rdwr        ppriv_ptr1
   84 
   85 struct sg_rdwr {
   86         TAILQ_ENTRY(sg_rdwr)    rdwr_link;
   87         int                     tag;
   88         int                     state;
   89         int                     buf_len;
   90         char                    *buf;
   91         union ccb               *ccb;
   92         union {
   93                 struct sg_header hdr;
   94                 struct sg_io_hdr io_hdr;
   95         } hdr;
   96 };
   97 
   98 struct sg_softc {
   99         sg_state                state;
  100         sg_flags                flags;
  101         int                     open_count;
  102         struct devstat          *device_stats;
  103         TAILQ_HEAD(, sg_rdwr)   rdwr_done;
  104         struct cdev             *dev;
  105         int                     sg_timeout;
  106         int                     sg_user_timeout;
  107         uint8_t                 pd_type;
  108         union ccb               saved_ccb;
  109 };
  110 
  111 static d_open_t         sgopen;
  112 static d_close_t        sgclose;
  113 static d_ioctl_t        sgioctl;
  114 static d_write_t        sgwrite;
  115 static d_read_t         sgread;
  116 
  117 static periph_init_t    sginit;
  118 static periph_ctor_t    sgregister;
  119 static periph_oninv_t   sgoninvalidate;
  120 static periph_dtor_t    sgcleanup;
  121 static void             sgasync(void *callback_arg, uint32_t code,
  122                                 struct cam_path *path, void *arg);
  123 static void             sgdone(struct cam_periph *periph, union ccb *done_ccb);
  124 static int              sgsendccb(struct cam_periph *periph, union ccb *ccb);
  125 static int              sgsendrdwr(struct cam_periph *periph, union ccb *ccb);
  126 static int              sgerror(union ccb *ccb, uint32_t cam_flags,
  127                                 uint32_t sense_flags);
  128 static void             sg_scsiio_status(struct ccb_scsiio *csio,
  129                                          u_short *hoststat, u_short *drvstat);
  130 
  131 static int              scsi_group_len(u_char cmd);
  132 
  133 static struct periph_driver sgdriver =
  134 {
  135         sginit, "sg",
  136         TAILQ_HEAD_INITIALIZER(sgdriver.units), /* gen */ 0
  137 };
  138 PERIPHDRIVER_DECLARE(sg, sgdriver);
  139 
  140 static struct cdevsw sg_cdevsw = {
  141         .d_version =    D_VERSION,
  142         .d_flags =      D_NEEDGIANT | D_TRACKCLOSE,
  143         .d_open =       sgopen,
  144         .d_close =      sgclose,
  145         .d_ioctl =      sgioctl,
  146         .d_write =      sgwrite,
  147         .d_read =       sgread,
  148         .d_name =       "sg",
  149 };
  150 
  151 static int sg_version = 30125;
  152 
  153 static void
  154 sginit(void)
  155 {
  156         cam_status status;
  157 
  158         /*
  159          * Install a global async callback.  This callback will receive aync
  160          * callbacks like "new device found".
  161          */
  162         status = xpt_register_async(AC_FOUND_DEVICE, sgasync, NULL, NULL);
  163 
  164         if (status != CAM_REQ_CMP) {
  165                 printf("sg: Failed to attach master async callbac "
  166                         "due to status 0x%x!\n", status);
  167         }
  168 }
  169 
  170 static void
  171 sgdevgonecb(void *arg)
  172 {
  173         struct cam_periph *periph;
  174         struct sg_softc *softc;
  175         struct mtx *mtx;
  176         int i;
  177 
  178         periph = (struct cam_periph *)arg;
  179         mtx = cam_periph_mtx(periph);
  180         mtx_lock(mtx);
  181 
  182         softc = (struct sg_softc *)periph->softc;
  183         KASSERT(softc->open_count >= 0, ("Negative open count %d",
  184                 softc->open_count));
  185 
  186         /*
  187          * When we get this callback, we will get no more close calls from
  188          * devfs.  So if we have any dangling opens, we need to release the
  189          * reference held for that particular context.
  190          */
  191         for (i = 0; i < softc->open_count; i++)
  192                 cam_periph_release_locked(periph);
  193 
  194         softc->open_count = 0;
  195 
  196         /*
  197          * Release the reference held for the device node, it is gone now.
  198          */
  199         cam_periph_release_locked(periph);
  200 
  201         /*
  202          * We reference the lock directly here, instead of using
  203          * cam_periph_unlock().  The reason is that the final call to
  204          * cam_periph_release_locked() above could result in the periph
  205          * getting freed.  If that is the case, dereferencing the periph
  206          * with a cam_periph_unlock() call would cause a page fault.
  207          */
  208         mtx_unlock(mtx);
  209 }
  210 
  211 
  212 static void
  213 sgoninvalidate(struct cam_periph *periph)
  214 {
  215         struct sg_softc *softc;
  216 
  217         softc = (struct sg_softc *)periph->softc;
  218 
  219         /*
  220          * Deregister any async callbacks.
  221          */
  222         xpt_register_async(0, sgasync, periph, periph->path);
  223 
  224         softc->flags |= SG_FLAG_INVALID;
  225 
  226         /*
  227          * Tell devfs this device has gone away, and ask for a callback
  228          * when it has cleaned up its state.
  229          */
  230         destroy_dev_sched_cb(softc->dev, sgdevgonecb, periph);
  231 
  232         /*
  233          * XXX Return all queued I/O with ENXIO.
  234          * XXX Handle any transactions queued to the card
  235          *     with XPT_ABORT_CCB.
  236          */
  237 
  238 }
  239 
  240 static void
  241 sgcleanup(struct cam_periph *periph)
  242 {
  243         struct sg_softc *softc;
  244 
  245         softc = (struct sg_softc *)periph->softc;
  246 
  247         devstat_remove_entry(softc->device_stats);
  248 
  249         free(softc, M_DEVBUF);
  250 }
  251 
  252 static void
  253 sgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
  254 {
  255         struct cam_periph *periph;
  256 
  257         periph = (struct cam_periph *)callback_arg;
  258 
  259         switch (code) {
  260         case AC_FOUND_DEVICE:
  261         {
  262                 struct ccb_getdev *cgd;
  263                 cam_status status;
  264 
  265                 cgd = (struct ccb_getdev *)arg;
  266                 if (cgd == NULL)
  267                         break;
  268 
  269                 if (cgd->protocol != PROTO_SCSI)
  270                         break;
  271 
  272                 /*
  273                  * Allocate a peripheral instance for this device and
  274                  * start the probe process.
  275                  */
  276                 status = cam_periph_alloc(sgregister, sgoninvalidate,
  277                                           sgcleanup, NULL, "sg",
  278                                           CAM_PERIPH_BIO, path,
  279                                           sgasync, AC_FOUND_DEVICE, cgd);
  280                 if ((status != CAM_REQ_CMP) && (status != CAM_REQ_INPROG)) {
  281                         const struct cam_status_entry *entry;
  282 
  283                         entry = cam_fetch_status_entry(status);
  284                         printf("sgasync: Unable to attach new device "
  285                                 "due to status %#x: %s\n", status, entry ?
  286                                 entry->status_text : "Unknown");
  287                 }
  288                 break;
  289         }
  290         default:
  291                 cam_periph_async(periph, code, path, arg);
  292                 break;
  293         }
  294 }
  295 
  296 static cam_status
  297 sgregister(struct cam_periph *periph, void *arg)
  298 {
  299         struct sg_softc *softc;
  300         struct ccb_getdev *cgd;
  301         struct ccb_pathinq cpi;
  302         int no_tags;
  303 
  304         cgd = (struct ccb_getdev *)arg;
  305         if (cgd == NULL) {
  306                 printf("sgregister: no getdev CCB, can't register device\n");
  307                 return (CAM_REQ_CMP_ERR);
  308         }
  309 
  310         softc = malloc(sizeof(*softc), M_DEVBUF, M_ZERO | M_NOWAIT);
  311         if (softc == NULL) {
  312                 printf("sgregister: Unable to allocate softc\n");
  313                 return (CAM_REQ_CMP_ERR);
  314         }
  315 
  316         softc->state = SG_STATE_NORMAL;
  317         softc->pd_type = SID_TYPE(&cgd->inq_data);
  318         softc->sg_timeout = SG_DEFAULT_TIMEOUT / SG_DEFAULT_HZ * hz;
  319         softc->sg_user_timeout = SG_DEFAULT_TIMEOUT;
  320         TAILQ_INIT(&softc->rdwr_done);
  321         periph->softc = softc;
  322 
  323         bzero(&cpi, sizeof(cpi));
  324         xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  325         cpi.ccb_h.func_code = XPT_PATH_INQ;
  326         xpt_action((union ccb *)&cpi);
  327 
  328         /*
  329          * We pass in 0 for all blocksize, since we don't know what the
  330          * blocksize of the device is, if it even has a blocksize.
  331          */
  332         cam_periph_unlock(periph);
  333         no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
  334         softc->device_stats = devstat_new_entry("sg",
  335                         periph->unit_number, 0,
  336                         DEVSTAT_NO_BLOCKSIZE
  337                         | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
  338                         softc->pd_type |
  339                         XPORT_DEVSTAT_TYPE(cpi.transport) |
  340                         DEVSTAT_TYPE_PASS,
  341                         DEVSTAT_PRIORITY_PASS);
  342 
  343         /*
  344          * Acquire a reference to the periph before we create the devfs
  345          * instance for it.  We'll release this reference once the devfs
  346          * instance has been freed.
  347          */
  348         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
  349                 xpt_print(periph->path, "%s: lost periph during "
  350                           "registration!\n", __func__);
  351                 cam_periph_lock(periph);
  352                 return (CAM_REQ_CMP_ERR);
  353         }
  354 
  355         /* Register the device */
  356         softc->dev = make_dev(&sg_cdevsw, periph->unit_number,
  357                               UID_ROOT, GID_OPERATOR, 0600, "%s%d",
  358                               periph->periph_name, periph->unit_number);
  359         if (periph->unit_number < 26) {
  360                 (void)make_dev_alias(softc->dev, "sg%c",
  361                     periph->unit_number + 'a');
  362         } else {
  363                 (void)make_dev_alias(softc->dev, "sg%c%c",
  364                     ((periph->unit_number / 26) - 1) + 'a',
  365                     (periph->unit_number % 26) + 'a');
  366         }
  367         cam_periph_lock(periph);
  368         softc->dev->si_drv1 = periph;
  369 
  370         /*
  371          * Add as async callback so that we get
  372          * notified if this device goes away.
  373          */
  374         xpt_register_async(AC_LOST_DEVICE, sgasync, periph, periph->path);
  375 
  376         if (bootverbose)
  377                 xpt_announce_periph(periph, NULL);
  378 
  379         return (CAM_REQ_CMP);
  380 }
  381 
  382 static void
  383 sgdone(struct cam_periph *periph, union ccb *done_ccb)
  384 {
  385         struct sg_softc *softc;
  386         struct ccb_scsiio *csio;
  387 
  388         softc = (struct sg_softc *)periph->softc;
  389         csio = &done_ccb->csio;
  390         switch (csio->ccb_h.ccb_type) {
  391         case SG_CCB_RDWR_IO:
  392         {
  393                 struct sg_rdwr *rdwr;
  394                 int state;
  395 
  396                 devstat_end_transaction(softc->device_stats,
  397                                         csio->dxfer_len,
  398                                         csio->tag_action & 0xf,
  399                                         ((csio->ccb_h.flags & CAM_DIR_MASK) ==
  400                                         CAM_DIR_NONE) ? DEVSTAT_NO_DATA :
  401                                         (csio->ccb_h.flags & CAM_DIR_OUT) ?
  402                                         DEVSTAT_WRITE : DEVSTAT_READ,
  403                                         NULL, NULL);
  404 
  405                 rdwr = done_ccb->ccb_h.ccb_rdwr;
  406                 state = rdwr->state;
  407                 rdwr->state = SG_RDWR_DONE;
  408                 wakeup(rdwr);
  409                 break;
  410         }
  411         default:
  412                 panic("unknown sg CCB type");
  413         }
  414 }
  415 
  416 static int
  417 sgopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  418 {
  419         struct cam_periph *periph;
  420         struct sg_softc *softc;
  421         int error = 0;
  422 
  423         periph = (struct cam_periph *)dev->si_drv1;
  424         if (periph == NULL)
  425                 return (ENXIO);
  426 
  427         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  428                 return (ENXIO);
  429 
  430         /*
  431          * Don't allow access when we're running at a high securelevel.
  432          */
  433         error = securelevel_gt(td->td_ucred, 1);
  434         if (error) {
  435                 cam_periph_release(periph);
  436                 return (error);
  437         }
  438 
  439         cam_periph_lock(periph);
  440 
  441         softc = (struct sg_softc *)periph->softc;
  442         if (softc->flags & SG_FLAG_INVALID) {
  443                 cam_periph_release_locked(periph);
  444                 cam_periph_unlock(periph);
  445                 return (ENXIO);
  446         }
  447 
  448         softc->open_count++;
  449 
  450         cam_periph_unlock(periph);
  451 
  452         return (error);
  453 }
  454 
  455 static int
  456 sgclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  457 {
  458         struct cam_periph *periph;
  459         struct sg_softc   *softc;
  460         struct mtx *mtx;
  461 
  462         periph = (struct cam_periph *)dev->si_drv1;
  463         if (periph == NULL)
  464                 return (ENXIO);
  465         mtx = cam_periph_mtx(periph);
  466         mtx_lock(mtx);
  467 
  468         softc = periph->softc;
  469         softc->open_count--;
  470 
  471         cam_periph_release_locked(periph);
  472 
  473         /*
  474          * We reference the lock directly here, instead of using
  475          * cam_periph_unlock().  The reason is that the call to
  476          * cam_periph_release_locked() above could result in the periph
  477          * getting freed.  If that is the case, dereferencing the periph
  478          * with a cam_periph_unlock() call would cause a page fault.
  479          *
  480          * cam_periph_release() avoids this problem using the same method,
  481          * but we're manually acquiring and dropping the lock here to
  482          * protect the open count and avoid another lock acquisition and
  483          * release.
  484          */
  485         mtx_unlock(mtx);
  486 
  487         return (0);
  488 }
  489 
  490 static int
  491 sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
  492 {
  493         union ccb *ccb;
  494         struct ccb_scsiio *csio;
  495         struct cam_periph *periph;
  496         struct sg_softc *softc;
  497         struct sg_io_hdr *req;
  498         int dir, error;
  499 
  500         periph = (struct cam_periph *)dev->si_drv1;
  501         if (periph == NULL)
  502                 return (ENXIO);
  503 
  504         cam_periph_lock(periph);
  505 
  506         softc = (struct sg_softc *)periph->softc;
  507         error = 0;
  508 
  509         switch (cmd) {
  510         case SG_GET_VERSION_NUM:
  511         {
  512                 int *version = (int *)arg;
  513 
  514                 *version = sg_version;
  515                 break;
  516         }
  517         case SG_SET_TIMEOUT:
  518         {
  519                 u_int user_timeout = *(u_int *)arg;
  520 
  521                 softc->sg_user_timeout = user_timeout;
  522                 softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
  523                 break;
  524         }
  525         case SG_GET_TIMEOUT:
  526                 /*
  527                  * The value is returned directly to the syscall.
  528                  */
  529                 td->td_retval[0] = softc->sg_user_timeout;
  530                 error = 0;
  531                 break;
  532         case SG_IO:
  533                 req = (struct sg_io_hdr *)arg;
  534 
  535                 if (req->cmd_len > IOCDBLEN) {
  536                         error = EINVAL;
  537                         break;
  538                 }
  539 
  540                 if (req->iovec_count != 0) {
  541                         error = EOPNOTSUPP;
  542                         break;
  543                 }
  544 
  545                 ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
  546                 csio = &ccb->csio;
  547 
  548                 error = copyin(req->cmdp, &csio->cdb_io.cdb_bytes,
  549                     req->cmd_len);
  550                 if (error) {
  551                         xpt_release_ccb(ccb);
  552                         break;
  553                 }
  554 
  555                 switch(req->dxfer_direction) {
  556                 case SG_DXFER_TO_DEV:
  557                         dir = CAM_DIR_OUT;
  558                         break;
  559                 case SG_DXFER_FROM_DEV:
  560                         dir = CAM_DIR_IN;
  561                         break;
  562                 case SG_DXFER_TO_FROM_DEV:
  563                         dir = CAM_DIR_IN | CAM_DIR_OUT;
  564                         break;
  565                 case SG_DXFER_NONE:
  566                 default:
  567                         dir = CAM_DIR_NONE;
  568                         break;
  569                 }
  570 
  571                 cam_fill_csio(csio,
  572                               /*retries*/1,
  573                               sgdone,
  574                               dir|CAM_DEV_QFRZDIS,
  575                               MSG_SIMPLE_Q_TAG,
  576                               req->dxferp,
  577                               req->dxfer_len,
  578                               req->mx_sb_len,
  579                               req->cmd_len,
  580                               req->timeout);
  581 
  582                 error = sgsendccb(periph, ccb);
  583                 if (error) {
  584                         req->host_status = DID_ERROR;
  585                         req->driver_status = DRIVER_INVALID;
  586                         xpt_release_ccb(ccb);
  587                         break;
  588                 }
  589 
  590                 req->status = csio->scsi_status;
  591                 req->masked_status = (csio->scsi_status >> 1) & 0x7f;
  592                 sg_scsiio_status(csio, &req->host_status, &req->driver_status);
  593                 req->resid = csio->resid;
  594                 req->duration = csio->ccb_h.timeout;
  595                 req->info = 0;
  596 
  597                 if ((csio->ccb_h.status & CAM_AUTOSNS_VALID)
  598                     && (req->sbp != NULL)) {
  599                         req->sb_len_wr = req->mx_sb_len - csio->sense_resid;
  600                         error = copyout(&csio->sense_data, req->sbp,
  601                                         req->sb_len_wr);
  602                 }
  603 
  604                 xpt_release_ccb(ccb);
  605                 break;
  606                 
  607         case SG_GET_RESERVED_SIZE:
  608         {
  609                 int *size = (int *)arg;
  610                 *size = DFLTPHYS;
  611                 break;
  612         }
  613 
  614         case SG_GET_SCSI_ID:
  615         {
  616                 struct sg_scsi_id *id = (struct sg_scsi_id *)arg;
  617 
  618                 id->host_no = cam_sim_path(xpt_path_sim(periph->path));
  619                 id->channel = xpt_path_path_id(periph->path);
  620                 id->scsi_id = xpt_path_target_id(periph->path);
  621                 id->lun = xpt_path_lun_id(periph->path);
  622                 id->scsi_type = softc->pd_type;
  623                 id->h_cmd_per_lun = 1;
  624                 id->d_queue_depth = 1;
  625                 id->unused[0] = 0;
  626                 id->unused[1] = 0;
  627                 break;
  628         }
  629 
  630         case SG_GET_SG_TABLESIZE:
  631         {
  632                 int *size = (int *)arg;
  633                 *size = 0;
  634                 break;
  635         }
  636 
  637         case SG_EMULATED_HOST:
  638         case SG_SET_TRANSFORM:
  639         case SG_GET_TRANSFORM:
  640         case SG_GET_NUM_WAITING:
  641         case SG_SCSI_RESET:
  642         case SG_GET_REQUEST_TABLE:
  643         case SG_SET_KEEP_ORPHAN:
  644         case SG_GET_KEEP_ORPHAN:
  645         case SG_GET_ACCESS_COUNT:
  646         case SG_SET_FORCE_LOW_DMA:
  647         case SG_GET_LOW_DMA:
  648         case SG_SET_FORCE_PACK_ID:
  649         case SG_GET_PACK_ID:
  650         case SG_SET_RESERVED_SIZE:
  651         case SG_GET_COMMAND_Q:
  652         case SG_SET_COMMAND_Q:
  653         case SG_SET_DEBUG:
  654         case SG_NEXT_CMD_LEN:
  655         default:
  656 #ifdef CAMDEBUG
  657                 printf("sgioctl: rejecting cmd 0x%lx\n", cmd);
  658 #endif
  659                 error = ENODEV;
  660                 break;
  661         }
  662 
  663         cam_periph_unlock(periph);
  664         return (error);
  665 }
  666 
  667 static int
  668 sgwrite(struct cdev *dev, struct uio *uio, int ioflag)
  669 {
  670         union ccb *ccb;
  671         struct cam_periph *periph;
  672         struct ccb_scsiio *csio;
  673         struct sg_softc *sc;
  674         struct sg_header *hdr;
  675         struct sg_rdwr *rdwr;
  676         u_char cdb_cmd;
  677         char *buf;
  678         int error = 0, cdb_len, buf_len, dir;
  679 
  680         periph = dev->si_drv1;
  681         rdwr = malloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO);
  682         hdr = &rdwr->hdr.hdr;
  683 
  684         /* Copy in the header block and sanity check it */
  685         if (uio->uio_resid < sizeof(*hdr)) {
  686                 error = EINVAL;
  687                 goto out_hdr;
  688         }
  689         error = uiomove(hdr, sizeof(*hdr), uio);
  690         if (error)
  691                 goto out_hdr;
  692 
  693         /* XXX: We don't support SG 3.x read/write API. */
  694         if (hdr->reply_len < 0) {
  695                 error = ENODEV;
  696                 goto out_hdr;
  697         }
  698 
  699         ccb = xpt_alloc_ccb();
  700         if (ccb == NULL) {
  701                 error = ENOMEM;
  702                 goto out_hdr;
  703         }
  704         csio = &ccb->csio;
  705 
  706         /*
  707          * Copy in the CDB block.  The designers of the interface didn't
  708          * bother to provide a size for this in the header, so we have to
  709          * figure it out ourselves.
  710          */
  711         if (uio->uio_resid < 1)
  712                 goto out_ccb;
  713         error = uiomove(&cdb_cmd, 1, uio);
  714         if (error)
  715                 goto out_ccb;
  716         if (hdr->twelve_byte)
  717                 cdb_len = 12;
  718         else
  719                 cdb_len = scsi_group_len(cdb_cmd);
  720         /*
  721          * We've already read the first byte of the CDB and advanced the uio
  722          * pointer.  Just read the rest.
  723          */
  724         csio->cdb_io.cdb_bytes[0] = cdb_cmd;
  725         error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio);
  726         if (error)
  727                 goto out_ccb;
  728 
  729         /*
  730          * Now set up the data block.  Again, the designers didn't bother
  731          * to make this reliable.
  732          */
  733         buf_len = uio->uio_resid;
  734         if (buf_len != 0) {
  735                 buf = malloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO);
  736                 error = uiomove(buf, buf_len, uio);
  737                 if (error)
  738                         goto out_buf;
  739                 dir = CAM_DIR_OUT;
  740         } else if (hdr->reply_len != 0) {
  741                 buf = malloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO);
  742                 buf_len = hdr->reply_len;
  743                 dir = CAM_DIR_IN;
  744         } else {
  745                 buf = NULL;
  746                 buf_len = 0;
  747                 dir = CAM_DIR_NONE;
  748         }
  749 
  750         cam_periph_lock(periph);
  751         sc = periph->softc;
  752         xpt_setup_ccb(&ccb->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  753         cam_fill_csio(csio,
  754                       /*retries*/1,
  755                       sgdone,
  756                       dir|CAM_DEV_QFRZDIS,
  757                       MSG_SIMPLE_Q_TAG,
  758                       buf,
  759                       buf_len,
  760                       SG_MAX_SENSE,
  761                       cdb_len,
  762                       sc->sg_timeout);
  763 
  764         /*
  765          * Send off the command and hope that it works. This path does not
  766          * go through sgstart because the I/O is supposed to be asynchronous.
  767          */
  768         rdwr->buf = buf;
  769         rdwr->buf_len = buf_len;
  770         rdwr->tag = hdr->pack_id;
  771         rdwr->ccb = ccb;
  772         rdwr->state = SG_RDWR_INPROG;
  773         ccb->ccb_h.ccb_rdwr = rdwr;
  774         ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO;
  775         TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link);
  776         error = sgsendrdwr(periph, ccb);
  777         cam_periph_unlock(periph);
  778         return (error);
  779 
  780 out_buf:
  781         free(buf, M_DEVBUF);
  782 out_ccb:
  783         xpt_free_ccb(ccb);
  784 out_hdr:
  785         free(rdwr, M_DEVBUF);
  786         return (error);
  787 }
  788 
  789 static int
  790 sgread(struct cdev *dev, struct uio *uio, int ioflag)
  791 {
  792         struct ccb_scsiio *csio;
  793         struct cam_periph *periph;
  794         struct sg_softc *sc;
  795         struct sg_header *hdr;
  796         struct sg_rdwr *rdwr;
  797         u_short hstat, dstat;
  798         int error, pack_len, reply_len, pack_id;
  799 
  800         periph = dev->si_drv1;
  801 
  802         /* XXX The pack len field needs to be updated and written out instead
  803          * of discarded.  Not sure how to do that.
  804          */
  805         uio->uio_rw = UIO_WRITE;
  806         if ((error = uiomove(&pack_len, 4, uio)) != 0)
  807                 return (error);
  808         if ((error = uiomove(&reply_len, 4, uio)) != 0)
  809                 return (error);
  810         if ((error = uiomove(&pack_id, 4, uio)) != 0)
  811                 return (error);
  812         uio->uio_rw = UIO_READ;
  813 
  814         cam_periph_lock(periph);
  815         sc = periph->softc;
  816 search:
  817         TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) {
  818                 if (rdwr->tag == pack_id)
  819                         break;
  820         }
  821         if ((rdwr == NULL) || (rdwr->state != SG_RDWR_DONE)) {
  822                 if (cam_periph_sleep(periph, rdwr, PCATCH, "sgread", 0) == ERESTART)
  823                         return (EAGAIN);
  824                 goto search;
  825         }
  826         TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link);
  827         cam_periph_unlock(periph);
  828 
  829         hdr = &rdwr->hdr.hdr;
  830         csio = &rdwr->ccb->csio;
  831         sg_scsiio_status(csio, &hstat, &dstat);
  832         hdr->host_status = hstat;
  833         hdr->driver_status = dstat;
  834         hdr->target_status = csio->scsi_status >> 1;
  835 
  836         switch (hstat) {
  837         case DID_OK:
  838         case DID_PASSTHROUGH:
  839         case DID_SOFT_ERROR:
  840                 hdr->result = 0;
  841                 break;
  842         case DID_NO_CONNECT:
  843         case DID_BUS_BUSY:
  844         case DID_TIME_OUT:
  845                 hdr->result = EBUSY;
  846                 break;
  847         case DID_BAD_TARGET:
  848         case DID_ABORT:
  849         case DID_PARITY:
  850         case DID_RESET:
  851         case DID_BAD_INTR:
  852         case DID_ERROR:
  853         default:
  854                 hdr->result = EIO;
  855                 break;
  856         }
  857 
  858         if (dstat == DRIVER_SENSE) {
  859                 bcopy(&csio->sense_data, hdr->sense_buffer,
  860                       min(csio->sense_len, SG_MAX_SENSE));
  861 #ifdef CAMDEBUG
  862                 scsi_sense_print(csio);
  863 #endif
  864         }
  865 
  866         error = uiomove(&hdr->result, sizeof(*hdr) -
  867                         offsetof(struct sg_header, result), uio);
  868         if ((error == 0) && (hdr->result == 0))
  869                 error = uiomove(rdwr->buf, rdwr->buf_len, uio);
  870 
  871         cam_periph_lock(periph);
  872         xpt_free_ccb(rdwr->ccb);
  873         cam_periph_unlock(periph);
  874         free(rdwr->buf, M_DEVBUF);
  875         free(rdwr, M_DEVBUF);
  876         return (error);
  877 }
  878 
  879 static int
  880 sgsendccb(struct cam_periph *periph, union ccb *ccb)
  881 {
  882         struct sg_softc *softc;
  883         struct cam_periph_map_info mapinfo;
  884         int error;
  885 
  886         softc = periph->softc;
  887         bzero(&mapinfo, sizeof(mapinfo));
  888 
  889         /*
  890          * cam_periph_mapmem calls into proc and vm functions that can
  891          * sleep as well as trigger I/O, so we can't hold the lock.
  892          * Dropping it here is reasonably safe.
  893          * The only CCB opcode that is possible here is XPT_SCSI_IO, no
  894          * need for additional checks.
  895          */
  896         cam_periph_unlock(periph);
  897         error = cam_periph_mapmem(ccb, &mapinfo);
  898         cam_periph_lock(periph);
  899         if (error)
  900                 return (error);
  901 
  902         error = cam_periph_runccb(ccb,
  903                                   sgerror,
  904                                   CAM_RETRY_SELTO,
  905                                   SF_RETRY_UA,
  906                                   softc->device_stats);
  907 
  908         cam_periph_unmapmem(ccb, &mapinfo);
  909 
  910         return (error);
  911 }
  912 
  913 static int
  914 sgsendrdwr(struct cam_periph *periph, union ccb *ccb)
  915 {
  916         struct sg_softc *softc;
  917 
  918         softc = periph->softc;
  919         devstat_start_transaction(softc->device_stats, NULL);
  920         xpt_action(ccb);
  921         return (0);
  922 }
  923 
  924 static int
  925 sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
  926 {
  927         struct cam_periph *periph;
  928         struct sg_softc *softc;
  929 
  930         periph = xpt_path_periph(ccb->ccb_h.path);
  931         softc = (struct sg_softc *)periph->softc;
  932 
  933         return (cam_periph_error(ccb, cam_flags, sense_flags,
  934                                  &softc->saved_ccb));
  935 }
  936 
  937 static void
  938 sg_scsiio_status(struct ccb_scsiio *csio, u_short *hoststat, u_short *drvstat)
  939 {
  940         int status;
  941 
  942         status = csio->ccb_h.status;
  943 
  944         switch (status & CAM_STATUS_MASK) {
  945         case CAM_REQ_CMP:
  946                 *hoststat = DID_OK;
  947                 *drvstat = 0;
  948                 break;
  949         case CAM_REQ_CMP_ERR:
  950                 *hoststat = DID_ERROR;
  951                 *drvstat = 0;
  952                 break;
  953         case CAM_REQ_ABORTED:
  954                 *hoststat = DID_ABORT;
  955                 *drvstat = 0;
  956                 break;
  957         case CAM_REQ_INVALID:
  958                 *hoststat = DID_ERROR;
  959                 *drvstat = DRIVER_INVALID;
  960                 break;
  961         case CAM_DEV_NOT_THERE:
  962                 *hoststat = DID_BAD_TARGET;
  963                 *drvstat = 0;
  964                 break;
  965         case CAM_SEL_TIMEOUT:
  966                 *hoststat = DID_NO_CONNECT;
  967                 *drvstat = 0;
  968                 break;
  969         case CAM_CMD_TIMEOUT:
  970                 *hoststat = DID_TIME_OUT;
  971                 *drvstat = 0;
  972                 break;
  973         case CAM_SCSI_STATUS_ERROR:
  974                 *hoststat = DID_ERROR;
  975                 *drvstat = 0;
  976                 break;
  977         case CAM_SCSI_BUS_RESET:
  978                 *hoststat = DID_RESET;
  979                 *drvstat = 0;
  980                 break;
  981         case CAM_UNCOR_PARITY:
  982                 *hoststat = DID_PARITY;
  983                 *drvstat = 0;
  984                 break;
  985         case CAM_SCSI_BUSY:
  986                 *hoststat = DID_BUS_BUSY;
  987                 *drvstat = 0;
  988                 break;
  989         default:
  990                 *hoststat = DID_ERROR;
  991                 *drvstat = DRIVER_ERROR;
  992         }
  993 
  994         if (status & CAM_AUTOSNS_VALID)
  995                 *drvstat = DRIVER_SENSE;
  996 }
  997 
  998 static int
  999 scsi_group_len(u_char cmd)
 1000 {
 1001         int len[] = {6, 10, 10, 12, 12, 12, 10, 10};
 1002         int group;
 1003 
 1004         group = (cmd >> 5) & 0x7;
 1005         return (len[group]);
 1006 }
 1007 

Cache object: 2919d0915dbfeacdfe41dd2eb0c683d3


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