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_pt.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  * Implementation of SCSI Processor Target Peripheral driver for CAM.
    5  *
    6  * Copyright (c) 1998 Justin T. Gibbs.
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions, and the following disclaimer,
   14  *    without modification, immediately at the beginning of the file.
   15  * 2. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/queue.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/types.h>
   39 #include <sys/bio.h>
   40 #include <sys/devicestat.h>
   41 #include <sys/malloc.h>
   42 #include <sys/conf.h>
   43 #include <sys/ptio.h>
   44 
   45 #include <cam/cam.h>
   46 #include <cam/cam_ccb.h>
   47 #include <cam/cam_periph.h>
   48 #include <cam/cam_xpt_periph.h>
   49 #include <cam/cam_debug.h>
   50 
   51 #include <cam/scsi/scsi_all.h>
   52 #include <cam/scsi/scsi_message.h>
   53 #include <cam/scsi/scsi_pt.h>
   54 
   55 #include "opt_pt.h"
   56 
   57 typedef enum {
   58         PT_STATE_PROBE,
   59         PT_STATE_NORMAL
   60 } pt_state;
   61 
   62 typedef enum {
   63         PT_FLAG_NONE            = 0x00,
   64         PT_FLAG_OPEN            = 0x01,
   65         PT_FLAG_DEVICE_INVALID  = 0x02,
   66         PT_FLAG_RETRY_UA        = 0x04
   67 } pt_flags;
   68 
   69 typedef enum {
   70         PT_CCB_BUFFER_IO        = 0x01,
   71         PT_CCB_RETRY_UA         = 0x04,
   72         PT_CCB_BUFFER_IO_UA     = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
   73 } pt_ccb_state;
   74 
   75 /* Offsets into our private area for storing information */
   76 #define ccb_state       ppriv_field0
   77 #define ccb_bp          ppriv_ptr1
   78 
   79 struct pt_softc {
   80         struct   bio_queue_head bio_queue;
   81         struct   devstat *device_stats;
   82         LIST_HEAD(, ccb_hdr) pending_ccbs;
   83         pt_state state;
   84         pt_flags flags; 
   85         int      io_timeout;
   86         struct cdev *dev;
   87 };
   88 
   89 static  d_open_t        ptopen;
   90 static  d_close_t       ptclose;
   91 static  d_strategy_t    ptstrategy;
   92 static  periph_init_t   ptinit;
   93 static  void            ptasync(void *callback_arg, u_int32_t code,
   94                                 struct cam_path *path, void *arg);
   95 static  periph_ctor_t   ptctor;
   96 static  periph_oninv_t  ptoninvalidate;
   97 static  periph_dtor_t   ptdtor;
   98 static  periph_start_t  ptstart;
   99 static  void            ptdone(struct cam_periph *periph,
  100                                union ccb *done_ccb);
  101 static  d_ioctl_t       ptioctl;
  102 static  int             pterror(union ccb *ccb, u_int32_t cam_flags,
  103                                 u_int32_t sense_flags);
  104 
  105 void    scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
  106                           void (*cbfcnp)(struct cam_periph *, union ccb *),
  107                           u_int tag_action, int readop, u_int byte2,
  108                           u_int32_t xfer_len, u_int8_t *data_ptr,
  109                           u_int8_t sense_len, u_int32_t timeout);
  110 
  111 static struct periph_driver ptdriver =
  112 {
  113         ptinit, "pt",
  114         TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
  115 };
  116 
  117 PERIPHDRIVER_DECLARE(pt, ptdriver);
  118 
  119 static struct cdevsw pt_cdevsw = {
  120         .d_version =    D_VERSION,
  121         .d_flags =      0,
  122         .d_open =       ptopen,
  123         .d_close =      ptclose,
  124         .d_read =       physread,
  125         .d_write =      physwrite,
  126         .d_ioctl =      ptioctl,
  127         .d_strategy =   ptstrategy,
  128         .d_name =       "pt",
  129 };
  130 
  131 #ifndef SCSI_PT_DEFAULT_TIMEOUT
  132 #define SCSI_PT_DEFAULT_TIMEOUT         60
  133 #endif
  134 
  135 static int
  136 ptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  137 {
  138         struct cam_periph *periph;
  139         struct pt_softc *softc;
  140         int error = 0;
  141 
  142         periph = (struct cam_periph *)dev->si_drv1;
  143         if (cam_periph_acquire(periph) != 0)
  144                 return (ENXIO); 
  145 
  146         softc = (struct pt_softc *)periph->softc;
  147 
  148         cam_periph_lock(periph);
  149         if (softc->flags & PT_FLAG_DEVICE_INVALID) {
  150                 cam_periph_release_locked(periph);
  151                 cam_periph_unlock(periph);
  152                 return(ENXIO);
  153         }
  154 
  155         if ((softc->flags & PT_FLAG_OPEN) == 0)
  156                 softc->flags |= PT_FLAG_OPEN;
  157         else {
  158                 error = EBUSY;
  159                 cam_periph_release(periph);
  160         }
  161 
  162         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
  163             ("ptopen: dev=%s\n", devtoname(dev)));
  164 
  165         cam_periph_unlock(periph);
  166         return (error);
  167 }
  168 
  169 static int
  170 ptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  171 {
  172         struct  cam_periph *periph;
  173         struct  pt_softc *softc;
  174 
  175         periph = (struct cam_periph *)dev->si_drv1;
  176         softc = (struct pt_softc *)periph->softc;
  177 
  178         cam_periph_lock(periph);
  179 
  180         softc->flags &= ~PT_FLAG_OPEN;
  181         cam_periph_release_locked(periph);
  182         cam_periph_unlock(periph);
  183         return (0);
  184 }
  185 
  186 /*
  187  * Actually translate the requested transfer into one the physical driver
  188  * can understand.  The transfer is described by a buf and will include
  189  * only one physical transfer.
  190  */
  191 static void
  192 ptstrategy(struct bio *bp)
  193 {
  194         struct cam_periph *periph;
  195         struct pt_softc *softc;
  196 
  197         periph = (struct cam_periph *)bp->bio_dev->si_drv1;
  198         bp->bio_resid = bp->bio_bcount;
  199         if (periph == NULL) {
  200                 biofinish(bp, NULL, ENXIO);
  201                 return;
  202         }
  203         cam_periph_lock(periph);
  204         softc = (struct pt_softc *)periph->softc;
  205 
  206         /*
  207          * If the device has been made invalid, error out
  208          */
  209         if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
  210                 cam_periph_unlock(periph);
  211                 biofinish(bp, NULL, ENXIO);
  212                 return;
  213         }
  214 
  215         /*
  216          * Place it in the queue of disk activities for this disk
  217          */
  218         bioq_insert_tail(&softc->bio_queue, bp);
  219 
  220         /*
  221          * Schedule ourselves for performing the work.
  222          */
  223         xpt_schedule(periph, CAM_PRIORITY_NORMAL);
  224         cam_periph_unlock(periph);
  225 
  226         return;
  227 }
  228 
  229 static void
  230 ptinit(void)
  231 {
  232         cam_status status;
  233 
  234         /*
  235          * Install a global async callback.  This callback will
  236          * receive async callbacks like "new device found".
  237          */
  238         status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
  239 
  240         if (status != CAM_REQ_CMP) {
  241                 printf("pt: Failed to attach master async callback "
  242                        "due to status 0x%x!\n", status);
  243         }
  244 }
  245 
  246 static cam_status
  247 ptctor(struct cam_periph *periph, void *arg)
  248 {
  249         struct pt_softc *softc;
  250         struct ccb_getdev *cgd;
  251         struct ccb_pathinq cpi;
  252         struct make_dev_args args;
  253         int error;
  254 
  255         cgd = (struct ccb_getdev *)arg;
  256         if (cgd == NULL) {
  257                 printf("ptregister: no getdev CCB, can't register device\n");
  258                 return(CAM_REQ_CMP_ERR);
  259         }
  260 
  261         softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
  262 
  263         if (softc == NULL) {
  264                 printf("daregister: Unable to probe new device. "
  265                        "Unable to allocate softc\n");                           
  266                 return(CAM_REQ_CMP_ERR);
  267         }
  268 
  269         bzero(softc, sizeof(*softc));
  270         LIST_INIT(&softc->pending_ccbs);
  271         softc->state = PT_STATE_NORMAL;
  272         bioq_init(&softc->bio_queue);
  273 
  274         softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
  275 
  276         periph->softc = softc;
  277 
  278         xpt_path_inq(&cpi, periph->path);
  279 
  280         cam_periph_unlock(periph);
  281 
  282         make_dev_args_init(&args);
  283         args.mda_devsw = &pt_cdevsw;
  284         args.mda_unit = periph->unit_number;
  285         args.mda_uid = UID_ROOT;
  286         args.mda_gid = GID_OPERATOR;
  287         args.mda_mode = 0600;
  288         args.mda_si_drv1 = periph;
  289         error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
  290             periph->unit_number);
  291         if (error != 0) {
  292                 cam_periph_lock(periph);
  293                 return (CAM_REQ_CMP_ERR);
  294         }
  295 
  296         softc->device_stats = devstat_new_entry("pt",
  297                           periph->unit_number, 0,
  298                           DEVSTAT_NO_BLOCKSIZE,
  299                           SID_TYPE(&cgd->inq_data) |
  300                           XPORT_DEVSTAT_TYPE(cpi.transport),
  301                           DEVSTAT_PRIORITY_OTHER);
  302 
  303         cam_periph_lock(periph);
  304 
  305         /*
  306          * Add async callbacks for bus reset and
  307          * bus device reset calls.  I don't bother
  308          * checking if this fails as, in most cases,
  309          * the system will function just fine without
  310          * them and the only alternative would be to
  311          * not attach the device on failure.
  312          */
  313         xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
  314                            ptasync, periph, periph->path);
  315 
  316         /* Tell the user we've attached to the device */
  317         xpt_announce_periph(periph, NULL);
  318 
  319         return(CAM_REQ_CMP);
  320 }
  321 
  322 static void
  323 ptoninvalidate(struct cam_periph *periph)
  324 {
  325         struct pt_softc *softc;
  326 
  327         softc = (struct pt_softc *)periph->softc;
  328 
  329         /*
  330          * De-register any async callbacks.
  331          */
  332         xpt_register_async(0, ptasync, periph, periph->path);
  333 
  334         softc->flags |= PT_FLAG_DEVICE_INVALID;
  335 
  336         /*
  337          * Return all queued I/O with ENXIO.
  338          * XXX Handle any transactions queued to the card
  339          *     with XPT_ABORT_CCB.
  340          */
  341         bioq_flush(&softc->bio_queue, NULL, ENXIO);
  342 }
  343 
  344 static void
  345 ptdtor(struct cam_periph *periph)
  346 {
  347         struct pt_softc *softc;
  348 
  349         softc = (struct pt_softc *)periph->softc;
  350 
  351         devstat_remove_entry(softc->device_stats);
  352         cam_periph_unlock(periph);
  353         destroy_dev(softc->dev);
  354         cam_periph_lock(periph);
  355         free(softc, M_DEVBUF);
  356 }
  357 
  358 static void
  359 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
  360 {
  361         struct cam_periph *periph;
  362 
  363         periph = (struct cam_periph *)callback_arg;
  364         switch (code) {
  365         case AC_FOUND_DEVICE:
  366         {
  367                 struct ccb_getdev *cgd;
  368                 cam_status status;
  369 
  370                 cgd = (struct ccb_getdev *)arg;
  371                 if (cgd == NULL)
  372                         break;
  373 
  374                 if (cgd->protocol != PROTO_SCSI)
  375                         break;
  376                 if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
  377                         break;
  378                 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
  379                         break;
  380 
  381                 /*
  382                  * Allocate a peripheral instance for
  383                  * this device and start the probe
  384                  * process.
  385                  */
  386                 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
  387                                           ptstart, "pt", CAM_PERIPH_BIO,
  388                                           path, ptasync,
  389                                           AC_FOUND_DEVICE, cgd);
  390 
  391                 if (status != CAM_REQ_CMP
  392                  && status != CAM_REQ_INPROG)
  393                         printf("ptasync: Unable to attach to new device "
  394                                 "due to status 0x%x\n", status);
  395                 break;
  396         }
  397         case AC_SENT_BDR:
  398         case AC_BUS_RESET:
  399         {
  400                 struct pt_softc *softc;
  401                 struct ccb_hdr *ccbh;
  402 
  403                 softc = (struct pt_softc *)periph->softc;
  404                 /*
  405                  * Don't fail on the expected unit attention
  406                  * that will occur.
  407                  */
  408                 softc->flags |= PT_FLAG_RETRY_UA;
  409                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
  410                         ccbh->ccb_state |= PT_CCB_RETRY_UA;
  411         }
  412         /* FALLTHROUGH */
  413         default:
  414                 cam_periph_async(periph, code, path, arg);
  415                 break;
  416         }
  417 }
  418 
  419 static void
  420 ptstart(struct cam_periph *periph, union ccb *start_ccb)
  421 {
  422         struct pt_softc *softc;
  423         struct bio *bp;
  424 
  425         softc = (struct pt_softc *)periph->softc;
  426 
  427         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));
  428 
  429         /*
  430          * See if there is a buf with work for us to do..
  431          */
  432         bp = bioq_first(&softc->bio_queue);
  433         if (bp == NULL) {
  434                 xpt_release_ccb(start_ccb);
  435         } else {
  436                 bioq_remove(&softc->bio_queue, bp);
  437 
  438                 devstat_start_transaction_bio(softc->device_stats, bp);
  439 
  440                 scsi_send_receive(&start_ccb->csio,
  441                                   /*retries*/4,
  442                                   ptdone,
  443                                   MSG_SIMPLE_Q_TAG,
  444                                   bp->bio_cmd == BIO_READ,
  445                                   /*byte2*/0,
  446                                   bp->bio_bcount,
  447                                   bp->bio_data,
  448                                   /*sense_len*/SSD_FULL_SIZE,
  449                                   /*timeout*/softc->io_timeout);
  450 
  451                 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
  452 
  453                 /*
  454                  * Block out any asynchronous callbacks
  455                  * while we touch the pending ccb list.
  456                  */
  457                 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
  458                                  periph_links.le);
  459 
  460                 start_ccb->ccb_h.ccb_bp = bp;
  461                 bp = bioq_first(&softc->bio_queue);
  462 
  463                 xpt_action(start_ccb);
  464                 
  465                 if (bp != NULL) {
  466                         /* Have more work to do, so ensure we stay scheduled */
  467                         xpt_schedule(periph, CAM_PRIORITY_NORMAL);
  468                 }
  469         }
  470 }
  471 
  472 static void
  473 ptdone(struct cam_periph *periph, union ccb *done_ccb)
  474 {
  475         struct pt_softc *softc;
  476         struct ccb_scsiio *csio;
  477 
  478         softc = (struct pt_softc *)periph->softc;
  479 
  480         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n"));
  481 
  482         csio = &done_ccb->csio;
  483         switch (csio->ccb_h.ccb_state) {
  484         case PT_CCB_BUFFER_IO:
  485         case PT_CCB_BUFFER_IO_UA:
  486         {
  487                 struct bio *bp;
  488 
  489                 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
  490                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
  491                         int error;
  492                         int sf;
  493                         
  494                         if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
  495                                 sf = SF_RETRY_UA;
  496                         else
  497                                 sf = 0;
  498 
  499                         error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
  500                         if (error == ERESTART) {
  501                                 /*
  502                                  * A retry was scheuled, so
  503                                  * just return.
  504                                  */
  505                                 return;
  506                         }
  507                         if (error != 0) {
  508                                 if (error == ENXIO) {
  509                                         /*
  510                                          * Catastrophic error.  Mark our device
  511                                          * as invalid.
  512                                          */
  513                                         xpt_print(periph->path,
  514                                             "Invalidating device\n");
  515                                         softc->flags |= PT_FLAG_DEVICE_INVALID;
  516                                 }
  517 
  518                                 /*
  519                                  * return all queued I/O with EIO, so that
  520                                  * the client can retry these I/Os in the
  521                                  * proper order should it attempt to recover.
  522                                  */
  523                                 bioq_flush(&softc->bio_queue, NULL, EIO);
  524                                 bp->bio_error = error;
  525                                 bp->bio_resid = bp->bio_bcount;
  526                                 bp->bio_flags |= BIO_ERROR;
  527                         } else {
  528                                 bp->bio_resid = csio->resid;
  529                                 bp->bio_error = 0;
  530                                 if (bp->bio_resid != 0) {
  531                                         /* Short transfer ??? */
  532                                         bp->bio_flags |= BIO_ERROR;
  533                                 }
  534                         }
  535                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
  536                                 cam_release_devq(done_ccb->ccb_h.path,
  537                                                  /*relsim_flags*/0,
  538                                                  /*reduction*/0,
  539                                                  /*timeout*/0,
  540                                                  /*getcount_only*/0);
  541                 } else {
  542                         bp->bio_resid = csio->resid;
  543                         if (bp->bio_resid != 0)
  544                                 bp->bio_flags |= BIO_ERROR;
  545                 }
  546 
  547                 /*
  548                  * Block out any asynchronous callbacks
  549                  * while we touch the pending ccb list.
  550                  */
  551                 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
  552 
  553                 biofinish(bp, softc->device_stats, 0);
  554                 break;
  555         }
  556         }
  557         xpt_release_ccb(done_ccb);
  558 }
  559 
  560 static int
  561 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  562 {
  563 
  564         return(cam_periph_error(ccb, cam_flags, sense_flags));
  565 }
  566 
  567 static int
  568 ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  569 {
  570         struct cam_periph *periph;
  571         struct pt_softc *softc;
  572         int error = 0;
  573 
  574         periph = (struct cam_periph *)dev->si_drv1;
  575         softc = (struct pt_softc *)periph->softc;
  576 
  577         cam_periph_lock(periph);
  578 
  579         switch(cmd) {
  580         case PTIOCGETTIMEOUT:
  581                 if (softc->io_timeout >= 1000)
  582                         *(int *)addr = softc->io_timeout / 1000;
  583                 else
  584                         *(int *)addr = 0;
  585                 break;
  586         case PTIOCSETTIMEOUT:
  587                 if (*(int *)addr < 1) {
  588                         error = EINVAL;
  589                         break;
  590                 }
  591 
  592                 softc->io_timeout = *(int *)addr * 1000;
  593 
  594                 break;
  595         default:
  596                 error = cam_periph_ioctl(periph, cmd, addr, pterror);
  597                 break;
  598         }
  599 
  600         cam_periph_unlock(periph);
  601 
  602         return(error);
  603 }
  604 
  605 void
  606 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
  607                   void (*cbfcnp)(struct cam_periph *, union ccb *),
  608                   u_int tag_action, int readop, u_int byte2,
  609                   u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
  610                   u_int32_t timeout)
  611 {
  612         struct scsi_send_receive *scsi_cmd;
  613 
  614         scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
  615         scsi_cmd->opcode = readop ? RECEIVE : SEND;
  616         scsi_cmd->byte2 = byte2;
  617         scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
  618         scsi_cmd->control = 0;
  619 
  620         cam_fill_csio(csio,
  621                       retries,
  622                       cbfcnp,
  623                       /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
  624                       tag_action,
  625                       data_ptr,
  626                       xfer_len,
  627                       sense_len,
  628                       sizeof(*scsi_cmd),
  629                       timeout);
  630 }

Cache object: 18969315e0720a837c0c3d4740761cc5


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