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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2007 Scott Long
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions, and the following disclaimer,
   12  *    without modification, immediately at the beginning of the file.
   13  * 2. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * scsi_sg peripheral driver.  This driver is meant to implement the Linux
   31  * SG passthrough interface for SCSI.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/kernel.h>
   40 #include <sys/types.h>
   41 #include <sys/bio.h>
   42 #include <sys/malloc.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/ioccom.h>
   45 #include <sys/conf.h>
   46 #include <sys/errno.h>
   47 #include <sys/devicestat.h>
   48 #include <sys/proc.h>
   49 #include <sys/uio.h>
   50 
   51 #include <cam/cam.h>
   52 #include <cam/cam_ccb.h>
   53 #include <cam/cam_periph.h>
   54 #include <cam/cam_queue.h>
   55 #include <cam/cam_xpt_periph.h>
   56 #include <cam/cam_debug.h>
   57 #include <cam/cam_sim.h>
   58 
   59 #include <cam/scsi/scsi_all.h>
   60 #include <cam/scsi/scsi_message.h>
   61 #include <cam/scsi/scsi_sg.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 };
  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_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 static void
  212 sgoninvalidate(struct cam_periph *periph)
  213 {
  214         struct sg_softc *softc;
  215 
  216         softc = (struct sg_softc *)periph->softc;
  217 
  218         /*
  219          * Deregister any async callbacks.
  220          */
  221         xpt_register_async(0, sgasync, periph, periph->path);
  222 
  223         softc->flags |= SG_FLAG_INVALID;
  224 
  225         /*
  226          * Tell devfs this device has gone away, and ask for a callback
  227          * when it has cleaned up its state.
  228          */
  229         destroy_dev_sched_cb(softc->dev, sgdevgonecb, periph);
  230 
  231         /*
  232          * XXX Return all queued I/O with ENXIO.
  233          * XXX Handle any transactions queued to the card
  234          *     with XPT_ABORT_CCB.
  235          */
  236 
  237 }
  238 
  239 static void
  240 sgcleanup(struct cam_periph *periph)
  241 {
  242         struct sg_softc *softc;
  243 
  244         softc = (struct sg_softc *)periph->softc;
  245 
  246         devstat_remove_entry(softc->device_stats);
  247 
  248         free(softc, M_DEVBUF);
  249 }
  250 
  251 static void
  252 sgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
  253 {
  254         struct cam_periph *periph;
  255 
  256         periph = (struct cam_periph *)callback_arg;
  257 
  258         switch (code) {
  259         case AC_FOUND_DEVICE:
  260         {
  261                 struct ccb_getdev *cgd;
  262                 cam_status status;
  263 
  264                 cgd = (struct ccb_getdev *)arg;
  265                 if (cgd == NULL)
  266                         break;
  267 
  268                 if (cgd->protocol != PROTO_SCSI)
  269                         break;
  270 
  271                 /*
  272                  * Allocate a peripheral instance for this device and
  273                  * start the probe process.
  274                  */
  275                 status = cam_periph_alloc(sgregister, sgoninvalidate,
  276                                           sgcleanup, NULL, "sg",
  277                                           CAM_PERIPH_BIO, path,
  278                                           sgasync, AC_FOUND_DEVICE, cgd);
  279                 if ((status != CAM_REQ_CMP) && (status != CAM_REQ_INPROG)) {
  280                         const struct cam_status_entry *entry;
  281 
  282                         entry = cam_fetch_status_entry(status);
  283                         printf("sgasync: Unable to attach new device "
  284                                 "due to status %#x: %s\n", status, entry ?
  285                                 entry->status_text : "Unknown");
  286                 }
  287                 break;
  288         }
  289         default:
  290                 cam_periph_async(periph, code, path, arg);
  291                 break;
  292         }
  293 }
  294 
  295 static cam_status
  296 sgregister(struct cam_periph *periph, void *arg)
  297 {
  298         struct sg_softc *softc;
  299         struct ccb_getdev *cgd;
  300         struct ccb_pathinq cpi;
  301         struct make_dev_args args;
  302         int no_tags, error;
  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         xpt_path_inq(&cpi, periph->path);
  324 
  325         if (cpi.maxio == 0)
  326                 softc->maxio = DFLTPHYS;        /* traditional default */
  327         else if (cpi.maxio > maxphys)
  328                 softc->maxio = maxphys;         /* for safety */
  329         else
  330                 softc->maxio = cpi.maxio;       /* real value */
  331 
  332         /*
  333          * We pass in 0 for all blocksize, since we don't know what the
  334          * blocksize of the device is, if it even has a blocksize.
  335          */
  336         cam_periph_unlock(periph);
  337         no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
  338         softc->device_stats = devstat_new_entry("sg",
  339                         periph->unit_number, 0,
  340                         DEVSTAT_NO_BLOCKSIZE
  341                         | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
  342                         softc->pd_type |
  343                         XPORT_DEVSTAT_TYPE(cpi.transport) |
  344                         DEVSTAT_TYPE_PASS,
  345                         DEVSTAT_PRIORITY_PASS);
  346 
  347         /*
  348          * Acquire a reference to the periph before we create the devfs
  349          * instance for it.  We'll release this reference once the devfs
  350          * instance has been freed.
  351          */
  352         if (cam_periph_acquire(periph) != 0) {
  353                 xpt_print(periph->path, "%s: lost periph during "
  354                           "registration!\n", __func__);
  355                 cam_periph_lock(periph);
  356                 return (CAM_REQ_CMP_ERR);
  357         }
  358 
  359         /* Register the device */
  360         make_dev_args_init(&args);
  361         args.mda_devsw = &sg_cdevsw;
  362         args.mda_unit = periph->unit_number;
  363         args.mda_uid = UID_ROOT;
  364         args.mda_gid = GID_OPERATOR;
  365         args.mda_mode = 0600;
  366         args.mda_si_drv1 = periph;
  367         error = make_dev_s(&args, &softc->dev, "%s%d",
  368             periph->periph_name, periph->unit_number);
  369         if (error != 0) {
  370                 cam_periph_lock(periph);
  371                 cam_periph_release_locked(periph);
  372                 return (CAM_REQ_CMP_ERR);
  373         }
  374         if (periph->unit_number < 26) {
  375                 (void)make_dev_alias(softc->dev, "sg%c",
  376                     periph->unit_number + 'a');
  377         } else {
  378                 (void)make_dev_alias(softc->dev, "sg%c%c",
  379                     ((periph->unit_number / 26) - 1) + 'a',
  380                     (periph->unit_number % 26) + 'a');
  381         }
  382         cam_periph_lock(periph);
  383 
  384         /*
  385          * Add as async callback so that we get
  386          * notified if this device goes away.
  387          */
  388         xpt_register_async(AC_LOST_DEVICE, sgasync, periph, periph->path);
  389 
  390         if (bootverbose)
  391                 xpt_announce_periph(periph, NULL);
  392 
  393         return (CAM_REQ_CMP);
  394 }
  395 
  396 static void
  397 sgdone(struct cam_periph *periph, union ccb *done_ccb)
  398 {
  399         struct sg_softc *softc;
  400         struct ccb_scsiio *csio;
  401 
  402         softc = (struct sg_softc *)periph->softc;
  403         csio = &done_ccb->csio;
  404         switch (csio->ccb_h.ccb_type) {
  405         case SG_CCB_RDWR_IO:
  406         {
  407                 struct sg_rdwr *rdwr;
  408 
  409                 devstat_end_transaction(softc->device_stats,
  410                                         csio->dxfer_len,
  411                                         csio->tag_action & 0xf,
  412                                         ((csio->ccb_h.flags & CAM_DIR_MASK) ==
  413                                         CAM_DIR_NONE) ? DEVSTAT_NO_DATA :
  414                                         (csio->ccb_h.flags & CAM_DIR_OUT) ?
  415                                         DEVSTAT_WRITE : DEVSTAT_READ,
  416                                         NULL, NULL);
  417 
  418                 rdwr = done_ccb->ccb_h.ccb_rdwr;
  419                 rdwr->state = SG_RDWR_DONE;
  420                 wakeup(rdwr);
  421                 break;
  422         }
  423         default:
  424                 panic("unknown sg CCB type");
  425         }
  426 }
  427 
  428 static int
  429 sgopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  430 {
  431         struct cam_periph *periph;
  432         struct sg_softc *softc;
  433         int error = 0;
  434 
  435         periph = (struct cam_periph *)dev->si_drv1;
  436         if (cam_periph_acquire(periph) != 0)
  437                 return (ENXIO);
  438 
  439         /*
  440          * Don't allow access when we're running at a high securelevel.
  441          */
  442         error = securelevel_gt(td->td_ucred, 1);
  443         if (error) {
  444                 cam_periph_release(periph);
  445                 return (error);
  446         }
  447 
  448         cam_periph_lock(periph);
  449 
  450         softc = (struct sg_softc *)periph->softc;
  451         if (softc->flags & SG_FLAG_INVALID) {
  452                 cam_periph_release_locked(periph);
  453                 cam_periph_unlock(periph);
  454                 return (ENXIO);
  455         }
  456 
  457         softc->open_count++;
  458 
  459         cam_periph_unlock(periph);
  460 
  461         return (error);
  462 }
  463 
  464 static int
  465 sgclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  466 {
  467         struct cam_periph *periph;
  468         struct sg_softc   *softc;
  469         struct mtx *mtx;
  470 
  471         periph = (struct cam_periph *)dev->si_drv1;
  472         mtx = cam_periph_mtx(periph);
  473         mtx_lock(mtx);
  474 
  475         softc = periph->softc;
  476         softc->open_count--;
  477 
  478         cam_periph_release_locked(periph);
  479 
  480         /*
  481          * We reference the lock directly here, instead of using
  482          * cam_periph_unlock().  The reason is that the call to
  483          * cam_periph_release_locked() above could result in the periph
  484          * getting freed.  If that is the case, dereferencing the periph
  485          * with a cam_periph_unlock() call would cause a page fault.
  486          *
  487          * cam_periph_release() avoids this problem using the same method,
  488          * but we're manually acquiring and dropping the lock here to
  489          * protect the open count and avoid another lock acquisition and
  490          * release.
  491          */
  492         mtx_unlock(mtx);
  493 
  494         return (0);
  495 }
  496 
  497 static int
  498 sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
  499 {
  500         union ccb *ccb;
  501         struct ccb_scsiio *csio;
  502         struct cam_periph *periph;
  503         struct sg_softc *softc;
  504         struct sg_io_hdr *req;
  505         int dir, error;
  506 
  507         periph = (struct cam_periph *)dev->si_drv1;
  508         cam_periph_lock(periph);
  509 
  510         softc = (struct sg_softc *)periph->softc;
  511         error = 0;
  512 
  513         switch (cmd) {
  514         case SG_GET_VERSION_NUM:
  515         {
  516                 int *version = (int *)arg;
  517 
  518                 *version = sg_version;
  519                 break;
  520         }
  521         case SG_SET_TIMEOUT:
  522         {
  523                 u_int user_timeout = *(u_int *)arg;
  524 
  525                 softc->sg_user_timeout = user_timeout;
  526                 softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
  527                 break;
  528         }
  529         case SG_GET_TIMEOUT:
  530                 /*
  531                  * The value is returned directly to the syscall.
  532                  */
  533                 td->td_retval[0] = softc->sg_user_timeout;
  534                 error = 0;
  535                 break;
  536         case SG_IO:
  537                 req = (struct sg_io_hdr *)arg;
  538 
  539                 if (req->cmd_len > IOCDBLEN) {
  540                         error = EINVAL;
  541                         break;
  542                 }
  543 
  544                 if (req->iovec_count != 0) {
  545                         error = EOPNOTSUPP;
  546                         break;
  547                 }
  548 
  549                 ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
  550                 csio = &ccb->csio;
  551 
  552                 error = copyin(req->cmdp, &csio->cdb_io.cdb_bytes,
  553                     req->cmd_len);
  554                 if (error) {
  555                         xpt_release_ccb(ccb);
  556                         break;
  557                 }
  558 
  559                 switch(req->dxfer_direction) {
  560                 case SG_DXFER_TO_DEV:
  561                         dir = CAM_DIR_OUT;
  562                         break;
  563                 case SG_DXFER_FROM_DEV:
  564                         dir = CAM_DIR_IN;
  565                         break;
  566                 case SG_DXFER_TO_FROM_DEV:
  567                         dir = CAM_DIR_BOTH;
  568                         break;
  569                 case SG_DXFER_NONE:
  570                 default:
  571                         dir = CAM_DIR_NONE;
  572                         break;
  573                 }
  574 
  575                 cam_fill_csio(csio,
  576                               /*retries*/1,
  577                               /*cbfcnp*/NULL,
  578                               dir|CAM_DEV_QFRZDIS,
  579                               MSG_SIMPLE_Q_TAG,
  580                               req->dxferp,
  581                               req->dxfer_len,
  582                               req->mx_sb_len,
  583                               req->cmd_len,
  584                               req->timeout);
  585 
  586                 error = sgsendccb(periph, ccb);
  587                 if (error) {
  588                         req->host_status = DID_ERROR;
  589                         req->driver_status = DRIVER_INVALID;
  590                         xpt_release_ccb(ccb);
  591                         break;
  592                 }
  593 
  594                 req->status = csio->scsi_status;
  595                 req->masked_status = (csio->scsi_status >> 1) & 0x7f;
  596                 sg_scsiio_status(csio, &req->host_status, &req->driver_status);
  597                 req->resid = csio->resid;
  598                 req->duration = csio->ccb_h.timeout;
  599                 req->info = 0;
  600 
  601                 if ((csio->ccb_h.status & CAM_AUTOSNS_VALID)
  602                     && (req->sbp != NULL)) {
  603                         req->sb_len_wr = req->mx_sb_len - csio->sense_resid;
  604                         error = copyout(&csio->sense_data, req->sbp,
  605                                         req->sb_len_wr);
  606                 }
  607 
  608                 xpt_release_ccb(ccb);
  609                 break;
  610                 
  611         case SG_GET_RESERVED_SIZE:
  612         {
  613                 int *size = (int *)arg;
  614                 *size = DFLTPHYS;
  615                 break;
  616         }
  617 
  618         case SG_GET_SCSI_ID:
  619         {
  620                 struct sg_scsi_id *id = (struct sg_scsi_id *)arg;
  621 
  622                 id->host_no = cam_sim_path(xpt_path_sim(periph->path));
  623                 id->channel = xpt_path_path_id(periph->path);
  624                 id->scsi_id = xpt_path_target_id(periph->path);
  625                 id->lun = xpt_path_lun_id(periph->path);
  626                 id->scsi_type = softc->pd_type;
  627                 id->h_cmd_per_lun = 1;
  628                 id->d_queue_depth = 1;
  629                 id->unused[0] = 0;
  630                 id->unused[1] = 0;
  631                 break;
  632         }
  633 
  634         case SG_GET_SG_TABLESIZE:
  635         {
  636                 int *size = (int *)arg;
  637                 *size = 0;
  638                 break;
  639         }
  640 
  641         case SG_EMULATED_HOST:
  642         case SG_SET_TRANSFORM:
  643         case SG_GET_TRANSFORM:
  644         case SG_GET_NUM_WAITING:
  645         case SG_SCSI_RESET:
  646         case SG_GET_REQUEST_TABLE:
  647         case SG_SET_KEEP_ORPHAN:
  648         case SG_GET_KEEP_ORPHAN:
  649         case SG_GET_ACCESS_COUNT:
  650         case SG_SET_FORCE_LOW_DMA:
  651         case SG_GET_LOW_DMA:
  652         case SG_SET_FORCE_PACK_ID:
  653         case SG_GET_PACK_ID:
  654         case SG_SET_RESERVED_SIZE:
  655         case SG_GET_COMMAND_Q:
  656         case SG_SET_COMMAND_Q:
  657         case SG_SET_DEBUG:
  658         case SG_NEXT_CMD_LEN:
  659         default:
  660 #ifdef CAMDEBUG
  661                 printf("sgioctl: rejecting cmd 0x%lx\n", cmd);
  662 #endif
  663                 error = ENODEV;
  664                 break;
  665         }
  666 
  667         cam_periph_unlock(periph);
  668         return (error);
  669 }
  670 
  671 static int
  672 sgwrite(struct cdev *dev, struct uio *uio, int ioflag)
  673 {
  674         union ccb *ccb;
  675         struct cam_periph *periph;
  676         struct ccb_scsiio *csio;
  677         struct sg_softc *sc;
  678         struct sg_header *hdr;
  679         struct sg_rdwr *rdwr;
  680         u_char cdb_cmd;
  681         char *buf;
  682         int error = 0, cdb_len, buf_len, dir;
  683 
  684         periph = dev->si_drv1;
  685         rdwr = malloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO);
  686         hdr = &rdwr->hdr.hdr;
  687 
  688         /* Copy in the header block and sanity check it */
  689         if (uio->uio_resid < sizeof(*hdr)) {
  690                 error = EINVAL;
  691                 goto out_hdr;
  692         }
  693         error = uiomove(hdr, sizeof(*hdr), uio);
  694         if (error)
  695                 goto out_hdr;
  696 
  697         /* XXX: We don't support SG 3.x read/write API. */
  698         if (hdr->reply_len < 0) {
  699                 error = ENODEV;
  700                 goto out_hdr;
  701         }
  702 
  703         ccb = xpt_alloc_ccb();
  704         if (ccb == NULL) {
  705                 error = ENOMEM;
  706                 goto out_hdr;
  707         }
  708         csio = &ccb->csio;
  709 
  710         /*
  711          * Copy in the CDB block.  The designers of the interface didn't
  712          * bother to provide a size for this in the header, so we have to
  713          * figure it out ourselves.
  714          */
  715         if (uio->uio_resid < 1)
  716                 goto out_ccb;
  717         error = uiomove(&cdb_cmd, 1, uio);
  718         if (error)
  719                 goto out_ccb;
  720         if (hdr->twelve_byte)
  721                 cdb_len = 12;
  722         else
  723                 cdb_len = scsi_group_len(cdb_cmd);
  724         /*
  725          * We've already read the first byte of the CDB and advanced the uio
  726          * pointer.  Just read the rest.
  727          */
  728         csio->cdb_io.cdb_bytes[0] = cdb_cmd;
  729         error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio);
  730         if (error)
  731                 goto out_ccb;
  732 
  733         /*
  734          * Now set up the data block.  Again, the designers didn't bother
  735          * to make this reliable.
  736          */
  737         buf_len = uio->uio_resid;
  738         if (buf_len != 0) {
  739                 buf = malloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO);
  740                 error = uiomove(buf, buf_len, uio);
  741                 if (error)
  742                         goto out_buf;
  743                 dir = CAM_DIR_OUT;
  744         } else if (hdr->reply_len != 0) {
  745                 buf = malloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO);
  746                 buf_len = hdr->reply_len;
  747                 dir = CAM_DIR_IN;
  748         } else {
  749                 buf = NULL;
  750                 buf_len = 0;
  751                 dir = CAM_DIR_NONE;
  752         }
  753 
  754         cam_periph_lock(periph);
  755         sc = periph->softc;
  756         xpt_setup_ccb(&ccb->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  757         cam_fill_csio(csio,
  758                       /*retries*/1,
  759                       sgdone,
  760                       dir|CAM_DEV_QFRZDIS,
  761                       MSG_SIMPLE_Q_TAG,
  762                       buf,
  763                       buf_len,
  764                       SG_MAX_SENSE,
  765                       cdb_len,
  766                       sc->sg_timeout);
  767 
  768         /*
  769          * Send off the command and hope that it works. This path does not
  770          * go through sgstart because the I/O is supposed to be asynchronous.
  771          */
  772         rdwr->buf = buf;
  773         rdwr->buf_len = buf_len;
  774         rdwr->tag = hdr->pack_id;
  775         rdwr->ccb = ccb;
  776         rdwr->state = SG_RDWR_INPROG;
  777         ccb->ccb_h.ccb_rdwr = rdwr;
  778         ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO;
  779         TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link);
  780         error = sgsendrdwr(periph, ccb);
  781         cam_periph_unlock(periph);
  782         return (error);
  783 
  784 out_buf:
  785         free(buf, M_DEVBUF);
  786 out_ccb:
  787         xpt_free_ccb(ccb);
  788 out_hdr:
  789         free(rdwr, M_DEVBUF);
  790         return (error);
  791 }
  792 
  793 static int
  794 sgread(struct cdev *dev, struct uio *uio, int ioflag)
  795 {
  796         struct ccb_scsiio *csio;
  797         struct cam_periph *periph;
  798         struct sg_softc *sc;
  799         struct sg_header *hdr;
  800         struct sg_rdwr *rdwr;
  801         u_short hstat, dstat;
  802         int error, pack_len, reply_len, pack_id;
  803 
  804         periph = dev->si_drv1;
  805 
  806         /* XXX The pack len field needs to be updated and written out instead
  807          * of discarded.  Not sure how to do that.
  808          */
  809         uio->uio_rw = UIO_WRITE;
  810         if ((error = uiomove(&pack_len, 4, uio)) != 0)
  811                 return (error);
  812         if ((error = uiomove(&reply_len, 4, uio)) != 0)
  813                 return (error);
  814         if ((error = uiomove(&pack_id, 4, uio)) != 0)
  815                 return (error);
  816         uio->uio_rw = UIO_READ;
  817 
  818         cam_periph_lock(periph);
  819         sc = periph->softc;
  820 search:
  821         TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) {
  822                 if (rdwr->tag == pack_id)
  823                         break;
  824         }
  825         if ((rdwr == NULL) || (rdwr->state != SG_RDWR_DONE)) {
  826                 if (cam_periph_sleep(periph, rdwr, PCATCH, "sgread", 0) == ERESTART)
  827                         return (EAGAIN);
  828                 goto search;
  829         }
  830         TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link);
  831         cam_periph_unlock(periph);
  832 
  833         hdr = &rdwr->hdr.hdr;
  834         csio = &rdwr->ccb->csio;
  835         sg_scsiio_status(csio, &hstat, &dstat);
  836         hdr->host_status = hstat;
  837         hdr->driver_status = dstat;
  838         hdr->target_status = csio->scsi_status >> 1;
  839 
  840         switch (hstat) {
  841         case DID_OK:
  842         case DID_PASSTHROUGH:
  843         case DID_SOFT_ERROR:
  844                 hdr->result = 0;
  845                 break;
  846         case DID_NO_CONNECT:
  847         case DID_BUS_BUSY:
  848         case DID_TIME_OUT:
  849                 hdr->result = EBUSY;
  850                 break;
  851         case DID_BAD_TARGET:
  852         case DID_ABORT:
  853         case DID_PARITY:
  854         case DID_RESET:
  855         case DID_BAD_INTR:
  856         case DID_ERROR:
  857         default:
  858                 hdr->result = EIO;
  859                 break;
  860         }
  861 
  862         if (dstat == DRIVER_SENSE) {
  863                 bcopy(&csio->sense_data, hdr->sense_buffer,
  864                       min(csio->sense_len, SG_MAX_SENSE));
  865 #ifdef CAMDEBUG
  866                 scsi_sense_print(csio);
  867 #endif
  868         }
  869 
  870         error = uiomove(&hdr->result, sizeof(*hdr) -
  871                         offsetof(struct sg_header, result), uio);
  872         if ((error == 0) && (hdr->result == 0))
  873                 error = uiomove(rdwr->buf, rdwr->buf_len, uio);
  874 
  875         cam_periph_lock(periph);
  876         xpt_free_ccb(rdwr->ccb);
  877         cam_periph_unlock(periph);
  878         free(rdwr->buf, M_DEVBUF);
  879         free(rdwr, M_DEVBUF);
  880         return (error);
  881 }
  882 
  883 static int
  884 sgsendccb(struct cam_periph *periph, union ccb *ccb)
  885 {
  886         struct sg_softc *softc;
  887         struct cam_periph_map_info mapinfo;
  888         int error;
  889 
  890         softc = periph->softc;
  891         bzero(&mapinfo, sizeof(mapinfo));
  892 
  893         /*
  894          * cam_periph_mapmem calls into proc and vm functions that can
  895          * sleep as well as trigger I/O, so we can't hold the lock.
  896          * Dropping it here is reasonably safe.
  897          * The only CCB opcode that is possible here is XPT_SCSI_IO, no
  898          * need for additional checks.
  899          */
  900         cam_periph_unlock(periph);
  901         error = cam_periph_mapmem(ccb, &mapinfo, softc->maxio);
  902         cam_periph_lock(periph);
  903         if (error)
  904                 return (error);
  905 
  906         error = cam_periph_runccb(ccb,
  907                                   sgerror,
  908                                   CAM_RETRY_SELTO,
  909                                   SF_RETRY_UA,
  910                                   softc->device_stats);
  911 
  912         cam_periph_unlock(periph);
  913         cam_periph_unmapmem(ccb, &mapinfo);
  914         cam_periph_lock(periph);
  915 
  916         return (error);
  917 }
  918 
  919 static int
  920 sgsendrdwr(struct cam_periph *periph, union ccb *ccb)
  921 {
  922         struct sg_softc *softc;
  923 
  924         softc = periph->softc;
  925         devstat_start_transaction(softc->device_stats, NULL);
  926         xpt_action(ccb);
  927         return (0);
  928 }
  929 
  930 static int
  931 sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
  932 {
  933 
  934         return (cam_periph_error(ccb, cam_flags, sense_flags));
  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 }

Cache object: 72989e493ed5ece937f2d48ce6799bf1


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