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  * Implementation of SCSI Processor Target Peripheral driver for CAM.
    3  *
    4  * Copyright (c) 1998 Justin T. Gibbs.
    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 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/5.2/sys/cam/scsi/scsi_pt.c 116162 2003-06-10 18:14:05Z obrien $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/queue.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/types.h>
   37 #include <sys/bio.h>
   38 #include <sys/devicestat.h>
   39 #include <sys/malloc.h>
   40 #include <sys/conf.h>
   41 #include <sys/ptio.h>
   42 
   43 #include <cam/cam.h>
   44 #include <cam/cam_ccb.h>
   45 #include <cam/cam_periph.h>
   46 #include <cam/cam_xpt_periph.h>
   47 #include <cam/cam_debug.h>
   48 
   49 #include <cam/scsi/scsi_all.h>
   50 #include <cam/scsi/scsi_message.h>
   51 #include <cam/scsi/scsi_pt.h>
   52 
   53 #include "opt_pt.h"
   54 
   55 typedef enum {
   56         PT_STATE_PROBE,
   57         PT_STATE_NORMAL
   58 } pt_state;
   59 
   60 typedef enum {
   61         PT_FLAG_NONE            = 0x00,
   62         PT_FLAG_OPEN            = 0x01,
   63         PT_FLAG_DEVICE_INVALID  = 0x02,
   64         PT_FLAG_RETRY_UA        = 0x04
   65 } pt_flags;
   66 
   67 typedef enum {
   68         PT_CCB_BUFFER_IO        = 0x01,
   69         PT_CCB_WAITING          = 0x02,
   70         PT_CCB_RETRY_UA         = 0x04,
   71         PT_CCB_BUFFER_IO_UA     = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
   72 } pt_ccb_state;
   73 
   74 /* Offsets into our private area for storing information */
   75 #define ccb_state       ppriv_field0
   76 #define ccb_bp          ppriv_ptr1
   77 
   78 struct pt_softc {
   79         struct   bio_queue_head bio_queue;
   80         struct   devstat *device_stats;
   81         LIST_HEAD(, ccb_hdr) pending_ccbs;
   82         pt_state state;
   83         pt_flags flags; 
   84         union    ccb saved_ccb;
   85         int      io_timeout;
   86         dev_t    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 #define PT_CDEV_MAJOR 61
  120 
  121 static struct cdevsw pt_cdevsw = {
  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         .d_maj =        PT_CDEV_MAJOR,
  130 };
  131 
  132 #ifndef SCSI_PT_DEFAULT_TIMEOUT
  133 #define SCSI_PT_DEFAULT_TIMEOUT         60
  134 #endif
  135 
  136 static int
  137 ptopen(dev_t dev, int flags, int fmt, struct thread *td)
  138 {
  139         struct cam_periph *periph;
  140         struct pt_softc *softc;
  141         int unit;
  142         int error;
  143         int s;
  144 
  145         unit = minor(dev);
  146         periph = (struct cam_periph *)dev->si_drv1;
  147         if (periph == NULL)
  148                 return (ENXIO); 
  149 
  150         softc = (struct pt_softc *)periph->softc;
  151 
  152         s = splsoftcam();
  153         if (softc->flags & PT_FLAG_DEVICE_INVALID) {
  154                 splx(s);
  155                 return(ENXIO);
  156         }
  157 
  158         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
  159             ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit));
  160 
  161         if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
  162                 splx(s);
  163                 return (error); /* error code from tsleep */
  164         }
  165 
  166         splx(s);
  167 
  168         if ((softc->flags & PT_FLAG_OPEN) == 0) {
  169                 if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  170                         error = ENXIO;
  171                 else
  172                         softc->flags |= PT_FLAG_OPEN;
  173         } else
  174                 error = EBUSY;
  175 
  176         cam_periph_unlock(periph);
  177         return (error);
  178 }
  179 
  180 static int
  181 ptclose(dev_t dev, int flag, int fmt, struct thread *td)
  182 {
  183         struct  cam_periph *periph;
  184         struct  pt_softc *softc;
  185         int     error;
  186 
  187         periph = (struct cam_periph *)dev->si_drv1;
  188         if (periph == NULL)
  189                 return (ENXIO); 
  190 
  191         softc = (struct pt_softc *)periph->softc;
  192 
  193         if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
  194                 return (error); /* error code from tsleep */
  195 
  196         softc->flags &= ~PT_FLAG_OPEN;
  197         cam_periph_unlock(periph);
  198         cam_periph_release(periph);
  199         return (0);
  200 }
  201 
  202 /*
  203  * Actually translate the requested transfer into one the physical driver
  204  * can understand.  The transfer is described by a buf and will include
  205  * only one physical transfer.
  206  */
  207 static void
  208 ptstrategy(struct bio *bp)
  209 {
  210         struct cam_periph *periph;
  211         struct pt_softc *softc;
  212         int    s;
  213         
  214         periph = (struct cam_periph *)bp->bio_dev->si_drv1;
  215         bp->bio_resid = bp->bio_bcount;
  216         if (periph == NULL) {
  217                 biofinish(bp, NULL, ENXIO);
  218                 return;
  219         }
  220         softc = (struct pt_softc *)periph->softc;
  221 
  222         /*
  223          * Mask interrupts so that the pack cannot be invalidated until
  224          * after we are in the queue.  Otherwise, we might not properly
  225          * clean up one of the buffers.
  226          */
  227         s = splbio();
  228         
  229         /*
  230          * If the device has been made invalid, error out
  231          */
  232         if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
  233                 splx(s);
  234                 biofinish(bp, NULL, ENXIO);
  235                 return;
  236         }
  237         
  238         /*
  239          * Place it in the queue of disk activities for this disk
  240          */
  241         bioq_insert_tail(&softc->bio_queue, bp);
  242 
  243         splx(s);
  244         
  245         /*
  246          * Schedule ourselves for performing the work.
  247          */
  248         xpt_schedule(periph, /* XXX priority */1);
  249 
  250         return;
  251 }
  252 
  253 static void
  254 ptinit(void)
  255 {
  256         cam_status status;
  257         struct cam_path *path;
  258 
  259         /*
  260          * Install a global async callback.  This callback will
  261          * receive async callbacks like "new device found".
  262          */
  263         status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
  264                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  265 
  266         if (status == CAM_REQ_CMP) {
  267                 struct ccb_setasync csa;
  268 
  269                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
  270                 csa.ccb_h.func_code = XPT_SASYNC_CB;
  271                 csa.event_enable = AC_FOUND_DEVICE;
  272                 csa.callback = ptasync;
  273                 csa.callback_arg = NULL;
  274                 xpt_action((union ccb *)&csa);
  275                 status = csa.ccb_h.status;
  276                 xpt_free_path(path);
  277         }
  278 
  279         if (status != CAM_REQ_CMP) {
  280                 printf("pt: Failed to attach master async callback "
  281                        "due to status 0x%x!\n", status);
  282         }
  283 }
  284 
  285 static cam_status
  286 ptctor(struct cam_periph *periph, void *arg)
  287 {
  288         struct pt_softc *softc;
  289         struct ccb_setasync csa;
  290         struct ccb_getdev *cgd;
  291 
  292         cgd = (struct ccb_getdev *)arg;
  293         if (periph == NULL) {
  294                 printf("ptregister: periph was NULL!!\n");
  295                 return(CAM_REQ_CMP_ERR);
  296         }
  297 
  298         if (cgd == NULL) {
  299                 printf("ptregister: no getdev CCB, can't register device\n");
  300                 return(CAM_REQ_CMP_ERR);
  301         }
  302 
  303         softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
  304 
  305         if (softc == NULL) {
  306                 printf("daregister: Unable to probe new device. "
  307                        "Unable to allocate softc\n");                           
  308                 return(CAM_REQ_CMP_ERR);
  309         }
  310 
  311         bzero(softc, sizeof(*softc));
  312         LIST_INIT(&softc->pending_ccbs);
  313         softc->state = PT_STATE_NORMAL;
  314         bioq_init(&softc->bio_queue);
  315 
  316         softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
  317 
  318         periph->softc = softc;
  319         
  320         softc->device_stats = devstat_new_entry("pt",
  321                           periph->unit_number, 0,
  322                           DEVSTAT_NO_BLOCKSIZE,
  323                           SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
  324                           DEVSTAT_PRIORITY_OTHER);
  325 
  326         softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
  327                               GID_OPERATOR, 0600, "%s%d", periph->periph_name,
  328                               periph->unit_number);
  329         softc->dev->si_drv1 = periph;
  330 
  331         /*
  332          * Add async callbacks for bus reset and
  333          * bus device reset calls.  I don't bother
  334          * checking if this fails as, in most cases,
  335          * the system will function just fine without
  336          * them and the only alternative would be to
  337          * not attach the device on failure.
  338          */
  339         xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
  340         csa.ccb_h.func_code = XPT_SASYNC_CB;
  341         csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
  342         csa.callback = ptasync;
  343         csa.callback_arg = periph;
  344         xpt_action((union ccb *)&csa);
  345 
  346         /* Tell the user we've attached to the device */
  347         xpt_announce_periph(periph, NULL);
  348 
  349         return(CAM_REQ_CMP);
  350 }
  351 
  352 static void
  353 ptoninvalidate(struct cam_periph *periph)
  354 {
  355         int s;
  356         struct pt_softc *softc;
  357         struct ccb_setasync csa;
  358 
  359         softc = (struct pt_softc *)periph->softc;
  360 
  361         /*
  362          * De-register any async callbacks.
  363          */
  364         xpt_setup_ccb(&csa.ccb_h, periph->path,
  365                       /* priority */ 5);
  366         csa.ccb_h.func_code = XPT_SASYNC_CB;
  367         csa.event_enable = 0;
  368         csa.callback = ptasync;
  369         csa.callback_arg = periph;
  370         xpt_action((union ccb *)&csa);
  371 
  372         softc->flags |= PT_FLAG_DEVICE_INVALID;
  373 
  374         /*
  375          * Although the oninvalidate() routines are always called at
  376          * splsoftcam, we need to be at splbio() here to keep the buffer
  377          * queue from being modified while we traverse it.
  378          */
  379         s = splbio();
  380 
  381         /*
  382          * Return all queued I/O with ENXIO.
  383          * XXX Handle any transactions queued to the card
  384          *     with XPT_ABORT_CCB.
  385          */
  386         bioq_flush(&softc->bio_queue, NULL, ENXIO);
  387 
  388         splx(s);
  389 
  390         xpt_print_path(periph->path);
  391         printf("lost device\n");
  392 }
  393 
  394 static void
  395 ptdtor(struct cam_periph *periph)
  396 {
  397         struct pt_softc *softc;
  398 
  399         softc = (struct pt_softc *)periph->softc;
  400 
  401         devstat_remove_entry(softc->device_stats);
  402 
  403         destroy_dev(softc->dev);
  404 
  405         xpt_print_path(periph->path);
  406         printf("removing device entry\n");
  407         free(softc, M_DEVBUF);
  408 }
  409 
  410 static void
  411 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
  412 {
  413         struct cam_periph *periph;
  414 
  415         periph = (struct cam_periph *)callback_arg;
  416         switch (code) {
  417         case AC_FOUND_DEVICE:
  418         {
  419                 struct ccb_getdev *cgd;
  420                 cam_status status;
  421  
  422                 cgd = (struct ccb_getdev *)arg;
  423                 if (cgd == NULL)
  424                         break;
  425 
  426                 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
  427                         break;
  428 
  429                 /*
  430                  * Allocate a peripheral instance for
  431                  * this device and start the probe
  432                  * process.
  433                  */
  434                 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
  435                                           ptstart, "pt", CAM_PERIPH_BIO,
  436                                           cgd->ccb_h.path, ptasync,
  437                                           AC_FOUND_DEVICE, cgd);
  438 
  439                 if (status != CAM_REQ_CMP
  440                  && status != CAM_REQ_INPROG)
  441                         printf("ptasync: Unable to attach to new device "
  442                                 "due to status 0x%x\n", status);
  443                 break;
  444         }
  445         case AC_SENT_BDR:
  446         case AC_BUS_RESET:
  447         {
  448                 struct pt_softc *softc;
  449                 struct ccb_hdr *ccbh;
  450                 int s;
  451 
  452                 softc = (struct pt_softc *)periph->softc;
  453                 s = splsoftcam();
  454                 /*
  455                  * Don't fail on the expected unit attention
  456                  * that will occur.
  457                  */
  458                 softc->flags |= PT_FLAG_RETRY_UA;
  459                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
  460                         ccbh->ccb_state |= PT_CCB_RETRY_UA;
  461                 splx(s);
  462         }
  463         /* FALLTHROUGH */
  464         default:
  465                 cam_periph_async(periph, code, path, arg);
  466                 break;
  467         }
  468 }
  469 
  470 static void
  471 ptstart(struct cam_periph *periph, union ccb *start_ccb)
  472 {
  473         struct pt_softc *softc;
  474         struct bio *bp;
  475         int s;
  476 
  477         softc = (struct pt_softc *)periph->softc;
  478 
  479         /*
  480          * See if there is a buf with work for us to do..
  481          */
  482         s = splbio();
  483         bp = bioq_first(&softc->bio_queue);
  484         if (periph->immediate_priority <= periph->pinfo.priority) {
  485                 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
  486                                 ("queuing for immediate ccb\n"));
  487                 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
  488                 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
  489                                   periph_links.sle);
  490                 periph->immediate_priority = CAM_PRIORITY_NONE;
  491                 splx(s);
  492                 wakeup(&periph->ccb_list);
  493         } else if (bp == NULL) {
  494                 splx(s);
  495                 xpt_release_ccb(start_ccb);
  496         } else {
  497                 int oldspl;
  498 
  499                 bioq_remove(&softc->bio_queue, bp);
  500 
  501                 devstat_start_transaction_bio(softc->device_stats, bp);
  502 
  503                 scsi_send_receive(&start_ccb->csio,
  504                                   /*retries*/4,
  505                                   ptdone,
  506                                   MSG_SIMPLE_Q_TAG,
  507                                   bp->bio_cmd == BIO_READ,
  508                                   /*byte2*/0,
  509                                   bp->bio_bcount,
  510                                   bp->bio_data,
  511                                   /*sense_len*/SSD_FULL_SIZE,
  512                                   /*timeout*/softc->io_timeout);
  513 
  514                 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
  515 
  516                 /*
  517                  * Block out any asyncronous callbacks
  518                  * while we touch the pending ccb list.
  519                  */
  520                 oldspl = splcam();
  521                 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
  522                                  periph_links.le);
  523                 splx(oldspl);
  524 
  525                 start_ccb->ccb_h.ccb_bp = bp;
  526                 bp = bioq_first(&softc->bio_queue);
  527                 splx(s);
  528 
  529                 xpt_action(start_ccb);
  530                 
  531                 if (bp != NULL) {
  532                         /* Have more work to do, so ensure we stay scheduled */
  533                         xpt_schedule(periph, /* XXX priority */1);
  534                 }
  535         }
  536 }
  537 
  538 static void
  539 ptdone(struct cam_periph *periph, union ccb *done_ccb)
  540 {
  541         struct pt_softc *softc;
  542         struct ccb_scsiio *csio;
  543 
  544         softc = (struct pt_softc *)periph->softc;
  545         csio = &done_ccb->csio;
  546         switch (csio->ccb_h.ccb_state) {
  547         case PT_CCB_BUFFER_IO:
  548         case PT_CCB_BUFFER_IO_UA:
  549         {
  550                 struct bio *bp;
  551                 int    oldspl;
  552 
  553                 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
  554                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
  555                         int error;
  556                         int s;
  557                         int sf;
  558                         
  559                         if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
  560                                 sf = SF_RETRY_UA;
  561                         else
  562                                 sf = 0;
  563 
  564                         error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
  565                         if (error == ERESTART) {
  566                                 /*
  567                                  * A retry was scheuled, so
  568                                  * just return.
  569                                  */
  570                                 return;
  571                         }
  572                         if (error != 0) {
  573                                 s = splbio();
  574 
  575                                 if (error == ENXIO) {
  576                                         /*
  577                                          * Catastrophic error.  Mark our device
  578                                          * as invalid.
  579                                          */
  580                                         xpt_print_path(periph->path);
  581                                         printf("Invalidating device\n");
  582                                         softc->flags |= PT_FLAG_DEVICE_INVALID;
  583                                 }
  584 
  585                                 /*
  586                                  * return all queued I/O with EIO, so that
  587                                  * the client can retry these I/Os in the
  588                                  * proper order should it attempt to recover.
  589                                  */
  590                                 bioq_flush(&softc->bio_queue, NULL, EIO);
  591                                 splx(s);
  592                                 bp->bio_error = error;
  593                                 bp->bio_resid = bp->bio_bcount;
  594                                 bp->bio_flags |= BIO_ERROR;
  595                         } else {
  596                                 bp->bio_resid = csio->resid;
  597                                 bp->bio_error = 0;
  598                                 if (bp->bio_resid != 0) {
  599                                         /* Short transfer ??? */
  600                                         bp->bio_flags |= BIO_ERROR;
  601                                 }
  602                         }
  603                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
  604                                 cam_release_devq(done_ccb->ccb_h.path,
  605                                                  /*relsim_flags*/0,
  606                                                  /*reduction*/0,
  607                                                  /*timeout*/0,
  608                                                  /*getcount_only*/0);
  609                 } else {
  610                         bp->bio_resid = csio->resid;
  611                         if (bp->bio_resid != 0)
  612                                 bp->bio_flags |= BIO_ERROR;
  613                 }
  614 
  615                 /*
  616                  * Block out any asyncronous callbacks
  617                  * while we touch the pending ccb list.
  618                  */
  619                 oldspl = splcam();
  620                 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
  621                 splx(oldspl);
  622 
  623                 biofinish(bp, softc->device_stats, 0);
  624                 break;
  625         }
  626         case PT_CCB_WAITING:
  627                 /* Caller will release the CCB */
  628                 wakeup(&done_ccb->ccb_h.cbfcnp);
  629                 return;
  630         }
  631         xpt_release_ccb(done_ccb);
  632 }
  633 
  634 static int
  635 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  636 {
  637         struct pt_softc   *softc;
  638         struct cam_periph *periph;
  639 
  640         periph = xpt_path_periph(ccb->ccb_h.path);
  641         softc = (struct pt_softc *)periph->softc;
  642 
  643         return(cam_periph_error(ccb, cam_flags, sense_flags,
  644                                 &softc->saved_ccb));
  645 }
  646 
  647 static int
  648 ptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  649 {
  650         struct cam_periph *periph;
  651         struct pt_softc *softc;
  652         int error;
  653 
  654         periph = (struct cam_periph *)dev->si_drv1;
  655         if (periph == NULL)
  656                 return(ENXIO);
  657 
  658         softc = (struct pt_softc *)periph->softc;
  659 
  660         if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
  661                 return (error); /* error code from tsleep */
  662         }       
  663 
  664         switch(cmd) {
  665         case PTIOCGETTIMEOUT:
  666                 if (softc->io_timeout >= 1000)
  667                         *(int *)addr = softc->io_timeout / 1000;
  668                 else
  669                         *(int *)addr = 0;
  670                 break;
  671         case PTIOCSETTIMEOUT:
  672         {
  673                 int s;
  674 
  675                 if (*(int *)addr < 1) {
  676                         error = EINVAL;
  677                         break;
  678                 }
  679 
  680                 s = splsoftcam();
  681                 softc->io_timeout = *(int *)addr * 1000;
  682                 splx(s);
  683 
  684                 break;
  685         }
  686         default:
  687                 error = cam_periph_ioctl(periph, cmd, addr, pterror);
  688                 break;
  689         }
  690 
  691         cam_periph_unlock(periph);
  692 
  693         return(error);
  694 }
  695 
  696 void
  697 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
  698                   void (*cbfcnp)(struct cam_periph *, union ccb *),
  699                   u_int tag_action, int readop, u_int byte2,
  700                   u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
  701                   u_int32_t timeout)
  702 {
  703         struct scsi_send_receive *scsi_cmd;
  704 
  705         scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
  706         scsi_cmd->opcode = readop ? RECEIVE : SEND;
  707         scsi_cmd->byte2 = byte2;
  708         scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
  709         scsi_cmd->control = 0;
  710 
  711         cam_fill_csio(csio,
  712                       retries,
  713                       cbfcnp,
  714                       /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
  715                       tag_action,
  716                       data_ptr,
  717                       xfer_len,
  718                       sense_len,
  719                       sizeof(*scsi_cmd),
  720                       timeout);
  721 }

Cache object: 306cbc6ddd4bcceb2430c076d9e34293


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