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

Cache object: 5731afa72a664598ce0c9261a8ab4173


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