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_sa.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 Sequential Access Peripheral driver for CAM.
    3  *
    4  * Copyright (c) 1999, 2000 Matthew Jacob
    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/6.4/sys/cam/scsi/scsi_sa.c 181127 2008-08-01 18:25:28Z emaste $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/queue.h>
   34 #ifdef _KERNEL
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #endif
   38 #include <sys/types.h>
   39 #include <sys/time.h>
   40 #include <sys/bio.h>
   41 #include <sys/limits.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mtio.h>
   44 #ifdef _KERNEL
   45 #include <sys/conf.h>
   46 #endif
   47 #include <sys/fcntl.h>
   48 #include <sys/devicestat.h>
   49 
   50 #ifndef _KERNEL
   51 #include <stdio.h>
   52 #include <string.h>
   53 #endif
   54 
   55 #include <cam/cam.h>
   56 #include <cam/cam_ccb.h>
   57 #include <cam/cam_periph.h>
   58 #include <cam/cam_xpt_periph.h>
   59 #include <cam/cam_debug.h>
   60 
   61 #include <cam/scsi/scsi_all.h>
   62 #include <cam/scsi/scsi_message.h>
   63 #include <cam/scsi/scsi_sa.h>
   64 
   65 #ifdef _KERNEL
   66 
   67 #include <opt_sa.h>
   68 
   69 #ifndef SA_IO_TIMEOUT
   70 #define SA_IO_TIMEOUT           4
   71 #endif
   72 #ifndef SA_SPACE_TIMEOUT
   73 #define SA_SPACE_TIMEOUT        1 * 60
   74 #endif
   75 #ifndef SA_REWIND_TIMEOUT
   76 #define SA_REWIND_TIMEOUT       2 * 60
   77 #endif
   78 #ifndef SA_ERASE_TIMEOUT
   79 #define SA_ERASE_TIMEOUT        4 * 60
   80 #endif
   81 
   82 #define SCSIOP_TIMEOUT          (60 * 1000)     /* not an option */
   83 
   84 #define IO_TIMEOUT              (SA_IO_TIMEOUT * 60 * 1000)
   85 #define REWIND_TIMEOUT          (SA_REWIND_TIMEOUT * 60 * 1000)
   86 #define ERASE_TIMEOUT           (SA_ERASE_TIMEOUT * 60 * 1000)
   87 #define SPACE_TIMEOUT           (SA_SPACE_TIMEOUT * 60 * 1000)
   88 
   89 /*
   90  * Additional options that can be set for config: SA_1FM_AT_EOT
   91  */
   92 
   93 #ifndef UNUSED_PARAMETER
   94 #define UNUSED_PARAMETER(x)     x = x
   95 #endif
   96 
   97 #define QFRLS(ccb)      \
   98         if (((ccb)->ccb_h.status & CAM_DEV_QFRZN) != 0) \
   99                 cam_release_devq((ccb)->ccb_h.path, 0, 0, 0, FALSE)
  100 
  101 /*
  102  * Driver states
  103  */
  104 
  105 MALLOC_DEFINE(M_SCSISA, "SCSI sa", "SCSI sequential access buffers");
  106 
  107 typedef enum {
  108         SA_STATE_NORMAL, SA_STATE_ABNORMAL
  109 } sa_state;
  110 
  111 #define ccb_pflags      ppriv_field0
  112 #define ccb_bp          ppriv_ptr1
  113 
  114 #define SA_CCB_BUFFER_IO        0x0
  115 #define SA_CCB_WAITING          0x1
  116 #define SA_CCB_TYPEMASK         0x1
  117 #define SA_POSITION_UPDATED     0x2
  118 
  119 #define Set_CCB_Type(x, type)                           \
  120         x->ccb_h.ccb_pflags &= ~SA_CCB_TYPEMASK;        \
  121         x->ccb_h.ccb_pflags |= type
  122 
  123 #define CCB_Type(x)     (x->ccb_h.ccb_pflags & SA_CCB_TYPEMASK)
  124 
  125 
  126 
  127 typedef enum {
  128         SA_FLAG_OPEN            = 0x0001,
  129         SA_FLAG_FIXED           = 0x0002,
  130         SA_FLAG_TAPE_LOCKED     = 0x0004,
  131         SA_FLAG_TAPE_MOUNTED    = 0x0008,
  132         SA_FLAG_TAPE_WP         = 0x0010,
  133         SA_FLAG_TAPE_WRITTEN    = 0x0020,
  134         SA_FLAG_EOM_PENDING     = 0x0040,
  135         SA_FLAG_EIO_PENDING     = 0x0080,
  136         SA_FLAG_EOF_PENDING     = 0x0100,
  137         SA_FLAG_ERR_PENDING     = (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING|
  138                                    SA_FLAG_EOF_PENDING),
  139         SA_FLAG_INVALID         = 0x0200,
  140         SA_FLAG_COMP_ENABLED    = 0x0400,
  141         SA_FLAG_COMP_SUPP       = 0x0800,
  142         SA_FLAG_COMP_UNSUPP     = 0x1000,
  143         SA_FLAG_TAPE_FROZEN     = 0x2000
  144 } sa_flags;
  145 
  146 typedef enum {
  147         SA_MODE_REWIND          = 0x00,
  148         SA_MODE_NOREWIND        = 0x01,
  149         SA_MODE_OFFLINE         = 0x02
  150 } sa_mode;
  151 
  152 typedef enum {
  153         SA_PARAM_NONE           = 0x00,
  154         SA_PARAM_BLOCKSIZE      = 0x01,
  155         SA_PARAM_DENSITY        = 0x02,
  156         SA_PARAM_COMPRESSION    = 0x04,
  157         SA_PARAM_BUFF_MODE      = 0x08,
  158         SA_PARAM_NUMBLOCKS      = 0x10,
  159         SA_PARAM_WP             = 0x20,
  160         SA_PARAM_SPEED          = 0x40,
  161         SA_PARAM_ALL            = 0x7f
  162 } sa_params;
  163 
  164 typedef enum {
  165         SA_QUIRK_NONE           = 0x00,
  166         SA_QUIRK_NOCOMP         = 0x01, /* Can't deal with compression at all */
  167         SA_QUIRK_FIXED          = 0x02, /* Force fixed mode */
  168         SA_QUIRK_VARIABLE       = 0x04, /* Force variable mode */
  169         SA_QUIRK_2FM            = 0x08, /* Needs Two File Marks at EOD */
  170         SA_QUIRK_1FM            = 0x10, /* No more than 1 File Mark at EOD */
  171         SA_QUIRK_NODREAD        = 0x20, /* Don't try and dummy read density */
  172         SA_QUIRK_NO_MODESEL     = 0x40, /* Don't do mode select at all */
  173         SA_QUIRK_NO_CPAGE       = 0x80  /* Don't use DEVICE COMPRESSION page */
  174 } sa_quirks;
  175 
  176 /* units are bits 4-7, 16-21 (1024 units) */
  177 #define SAUNIT(DEV) \
  178         (((minor(DEV) & 0xF0) >> 4) |  ((minor(DEV) & 0x3f0000) >> 16))
  179 
  180 #define SAMODE(z) ((minor(z) & 0x3))
  181 #define SADENSITY(z) (((minor(z) >> 2) & 0x3))
  182 #define SA_IS_CTRL(z) (minor(z) & (1 << 29))
  183 
  184 #define SA_NOT_CTLDEV   0
  185 #define SA_CTLDEV       1
  186 
  187 #define SA_ATYPE_R      0
  188 #define SA_ATYPE_NR     1
  189 #define SA_ATYPE_ER     2
  190 
  191 #define SAMINOR(ctl, unit, mode, access) \
  192         ((ctl << 29) | ((unit & 0x3f0) << 16) | ((unit & 0xf) << 4) | \
  193         (mode << 0x2) | (access & 0x3))
  194 
  195 #define SA_NUM_MODES    4
  196 struct sa_devs {
  197         struct cdev *ctl_dev;
  198         struct sa_mode_devs {
  199                 struct cdev *r_dev;
  200                 struct cdev *nr_dev;
  201                 struct cdev *er_dev;
  202         } mode_devs[SA_NUM_MODES];
  203 };
  204 
  205 struct sa_softc {
  206         sa_state        state;
  207         sa_flags        flags;
  208         sa_quirks       quirks;
  209         struct          bio_queue_head bio_queue;
  210         int             queue_count;
  211         struct          devstat *device_stats;
  212         struct sa_devs  devs;
  213         int             blk_gran;
  214         int             blk_mask;
  215         int             blk_shift;
  216         u_int32_t       max_blk;
  217         u_int32_t       min_blk;
  218         u_int32_t       comp_algorithm;
  219         u_int32_t       saved_comp_algorithm;
  220         u_int32_t       media_blksize;
  221         u_int32_t       last_media_blksize;
  222         u_int32_t       media_numblks;
  223         u_int8_t        media_density;
  224         u_int8_t        speed;
  225         u_int8_t        scsi_rev;
  226         u_int8_t        dsreg;          /* mtio mt_dsreg, redux */
  227         int             buffer_mode;
  228         int             filemarks;
  229         union           ccb saved_ccb;
  230         int             last_resid_was_io;
  231 
  232         /*
  233          * Relative to BOT Location.
  234          */
  235         daddr_t         fileno;
  236         daddr_t         blkno;
  237 
  238         /*
  239          * Latched Error Info
  240          */
  241         struct {
  242                 struct scsi_sense_data _last_io_sense;
  243                 u_int32_t _last_io_resid;
  244                 u_int8_t _last_io_cdb[CAM_MAX_CDBLEN];
  245                 struct scsi_sense_data _last_ctl_sense;
  246                 u_int32_t _last_ctl_resid;
  247                 u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN];
  248 #define last_io_sense   errinfo._last_io_sense
  249 #define last_io_resid   errinfo._last_io_resid
  250 #define last_io_cdb     errinfo._last_io_cdb
  251 #define last_ctl_sense  errinfo._last_ctl_sense
  252 #define last_ctl_resid  errinfo._last_ctl_resid
  253 #define last_ctl_cdb    errinfo._last_ctl_cdb
  254         } errinfo;
  255         /*
  256          * Misc other flags/state
  257          */
  258         u_int32_t
  259                                         : 29,
  260                 open_rdonly             : 1,    /* open read-only */
  261                 open_pending_mount      : 1,    /* open pending mount */
  262                 ctrl_mode               : 1;    /* control device open */
  263 };
  264 
  265 struct sa_quirk_entry {
  266         struct scsi_inquiry_pattern inq_pat;    /* matching pattern */
  267         sa_quirks quirks;       /* specific quirk type */
  268         u_int32_t prefblk;      /* preferred blocksize when in fixed mode */
  269 };
  270 
  271 static struct sa_quirk_entry sa_quirk_table[] =
  272 {
  273         {
  274                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "OnStream",
  275                   "ADR*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_NODREAD |
  276                    SA_QUIRK_1FM|SA_QUIRK_NO_MODESEL, 32768
  277         },
  278         {
  279                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
  280                   "Python 06408*", "*"}, SA_QUIRK_NODREAD, 0
  281         },
  282         {
  283                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
  284                   "Python 25601*", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_NODREAD, 0
  285         },
  286         {
  287                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
  288                   "Python*", "*"}, SA_QUIRK_NODREAD, 0
  289         },
  290         {
  291                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
  292                   "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
  293         },
  294         {
  295                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
  296                   "VIPER 2525 25462", "-011"},
  297                   SA_QUIRK_NOCOMP|SA_QUIRK_1FM|SA_QUIRK_NODREAD, 0
  298         },
  299         {
  300                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
  301                   "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024
  302         },
  303 #if     0
  304         {
  305                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
  306                   "C15*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_NO_CPAGE, 0,
  307         },
  308 #endif
  309         {
  310                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
  311                   "C56*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
  312         },
  313         {
  314                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
  315                   "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
  316         },
  317         {
  318                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
  319                   "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
  320         },
  321         {
  322                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
  323                   "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
  324         },
  325         {
  326                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY",
  327                   "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
  328         },
  329         {
  330                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA",
  331                   "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
  332         },
  333         {       /* jreynold@primenet.com */
  334                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate",
  335                 "STT8000N*", "*"}, SA_QUIRK_1FM, 0
  336         },
  337         {       /* mike@sentex.net */
  338                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate",
  339                 "STT20000*", "*"}, SA_QUIRK_1FM, 0
  340         },
  341         {
  342                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
  343                   " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
  344         },
  345         {
  346                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
  347                   " TDC 3800", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
  348         },
  349         {
  350                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
  351                   " TDC 4100", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
  352         },
  353         {
  354                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
  355                   " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
  356         },
  357         {
  358                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
  359                   " SLR*", "*"}, SA_QUIRK_1FM, 0
  360         },
  361         {
  362                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK",
  363                   "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
  364         },
  365         {
  366                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK",
  367                   "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024
  368         }
  369 };
  370 
  371 static  d_open_t        saopen;
  372 static  d_close_t       saclose;
  373 static  d_strategy_t    sastrategy;
  374 static  d_ioctl_t       saioctl;
  375 static  periph_init_t   sainit;
  376 static  periph_ctor_t   saregister;
  377 static  periph_oninv_t  saoninvalidate;
  378 static  periph_dtor_t   sacleanup;
  379 static  periph_start_t  sastart;
  380 static  void            saasync(void *callback_arg, u_int32_t code,
  381                                 struct cam_path *path, void *arg);
  382 static  void            sadone(struct cam_periph *periph,
  383                                union ccb *start_ccb);
  384 static  int             saerror(union ccb *ccb, u_int32_t cam_flags,
  385                                 u_int32_t sense_flags);
  386 static int              samarkswanted(struct cam_periph *);
  387 static int              sacheckeod(struct cam_periph *periph);
  388 static int              sagetparams(struct cam_periph *periph,
  389                                     sa_params params_to_get,
  390                                     u_int32_t *blocksize, u_int8_t *density,
  391                                     u_int32_t *numblocks, int *buff_mode,
  392                                     u_int8_t *write_protect, u_int8_t *speed,
  393                                     int *comp_supported, int *comp_enabled,
  394                                     u_int32_t *comp_algorithm,
  395                                     sa_comp_t *comp_page);
  396 static int              sasetparams(struct cam_periph *periph,
  397                                     sa_params params_to_set,
  398                                     u_int32_t blocksize, u_int8_t density,
  399                                     u_int32_t comp_algorithm,
  400                                     u_int32_t sense_flags);
  401 static void             saprevent(struct cam_periph *periph, int action);
  402 static int              sarewind(struct cam_periph *periph);
  403 static int              saspace(struct cam_periph *periph, int count,
  404                                 scsi_space_code code);
  405 static int              samount(struct cam_periph *, int, struct cdev *);
  406 static int              saretension(struct cam_periph *periph);
  407 static int              sareservereleaseunit(struct cam_periph *periph,
  408                                              int reserve);
  409 static int              saloadunload(struct cam_periph *periph, int load);
  410 static int              saerase(struct cam_periph *periph, int longerase);
  411 static int              sawritefilemarks(struct cam_periph *periph,
  412                                          int nmarks, int setmarks);
  413 static int              sardpos(struct cam_periph *periph, int, u_int32_t *);
  414 static int              sasetpos(struct cam_periph *periph, int, u_int32_t *);
  415 
  416 
  417 static struct periph_driver sadriver =
  418 {
  419         sainit, "sa",
  420         TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0
  421 };
  422 
  423 PERIPHDRIVER_DECLARE(sa, sadriver);
  424 
  425 /* For 2.2-stable support */
  426 #ifndef D_TAPE
  427 #define D_TAPE 0
  428 #endif
  429 
  430 
  431 static struct cdevsw sa_cdevsw = {
  432         .d_version =    D_VERSION,
  433         .d_open =       saopen,
  434         .d_close =      saclose,
  435         .d_read =       physread,
  436         .d_write =      physwrite,
  437         .d_ioctl =      saioctl,
  438         .d_strategy =   sastrategy,
  439         .d_name =       "sa",
  440         .d_flags =      D_TAPE | D_NEEDGIANT,
  441 };
  442 
  443 static int
  444 saopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  445 {
  446         struct cam_periph *periph;
  447         struct sa_softc *softc;
  448         int unit;
  449         int error;
  450         int s;
  451 
  452         unit = SAUNIT(dev);
  453 
  454         s = splsoftcam();
  455         periph = (struct cam_periph *)dev->si_drv1;
  456         if (periph == NULL) {
  457                 (void) splx(s);
  458                 return (ENXIO); 
  459         }
  460         softc = (struct sa_softc *)periph->softc;
  461         if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
  462                 splx(s);
  463                 return (error);
  464         }
  465         splx(s);
  466 
  467         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
  468             ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
  469 
  470         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
  471                 cam_periph_unlock(periph);
  472                 return (ENXIO);
  473         }
  474 
  475         if (SA_IS_CTRL(dev)) {
  476                 softc->ctrl_mode = 1;
  477                 cam_periph_unlock(periph);
  478                 return (0);
  479         }
  480 
  481         if (softc->flags & SA_FLAG_OPEN) {
  482                 error = EBUSY;
  483         } else if (softc->flags & SA_FLAG_INVALID) {
  484                 error = ENXIO;
  485         } else {
  486                 /*
  487                  * Preserve whether this is a read_only open.
  488                  */
  489                 softc->open_rdonly = (flags & O_RDWR) == O_RDONLY;
  490 
  491                 /*
  492                  * The function samount ensures media is loaded and ready.
  493                  * It also does a device RESERVE if the tape isn't yet mounted.
  494                  *
  495                  * If the mount fails and this was a non-blocking open,
  496                  * make this a 'open_pending_mount' action.
  497                  */
  498                 error = samount(periph, flags, dev);
  499                 if (error && (flags & O_NONBLOCK)) {
  500                         softc->flags |= SA_FLAG_OPEN;
  501                         softc->open_pending_mount = 1;
  502                         cam_periph_unlock(periph);
  503                         return (0);
  504                 }
  505         }
  506 
  507         if (error) {
  508                 cam_periph_release(periph);
  509         } else {
  510                 saprevent(periph, PR_PREVENT);
  511                 softc->flags |= SA_FLAG_OPEN;
  512         }
  513         cam_periph_unlock(periph);
  514         return (error);
  515 }
  516 
  517 static int
  518 saclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  519 {
  520         struct  cam_periph *periph;
  521         struct  sa_softc *softc;
  522         int     unit, mode, error, writing, tmp;
  523         int     closedbits = SA_FLAG_OPEN;
  524 
  525         unit = SAUNIT(dev);
  526         mode = SAMODE(dev);
  527         periph = (struct cam_periph *)dev->si_drv1;
  528         if (periph == NULL)
  529                 return (ENXIO); 
  530 
  531         softc = (struct sa_softc *)periph->softc;
  532 
  533         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
  534             ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
  535 
  536 
  537         if ((error = cam_periph_lock(periph, PRIBIO)) != 0) {
  538                 return (error);
  539         }
  540 
  541         softc->open_rdonly = 0; 
  542         if (SA_IS_CTRL(dev)) {
  543                 softc->ctrl_mode = 0;
  544                 cam_periph_release(periph);
  545                 cam_periph_unlock(periph);
  546                 return (0);
  547         }
  548 
  549         if (softc->open_pending_mount) {
  550                 softc->flags &= ~SA_FLAG_OPEN;
  551                 softc->open_pending_mount = 0; 
  552                 cam_periph_release(periph);
  553                 cam_periph_unlock(periph);
  554                 return (0);
  555         }
  556 
  557         /*
  558          * Were we writing the tape?
  559          */
  560         writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0;
  561 
  562         /*
  563          * See whether or not we need to write filemarks. If this
  564          * fails, we probably have to assume we've lost tape
  565          * position.
  566          */
  567         error = sacheckeod(periph);
  568         if (error) {
  569                 xpt_print_path(periph->path);
  570                 printf("failed to write terminating filemark(s)\n");
  571                 softc->flags |= SA_FLAG_TAPE_FROZEN;
  572         }
  573 
  574         /*
  575          * Whatever we end up doing, allow users to eject tapes from here on.
  576          */
  577         saprevent(periph, PR_ALLOW);
  578 
  579         /*
  580          * Decide how to end...
  581          */
  582         if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) {
  583                 closedbits |= SA_FLAG_TAPE_FROZEN;
  584         } else switch (mode) {
  585         case SA_MODE_OFFLINE:
  586                 /*
  587                  * An 'offline' close is an unconditional release of
  588                  * frozen && mount conditions, irrespective of whether
  589                  * these operations succeeded. The reason for this is
  590                  * to allow at least some kind of programmatic way
  591                  * around our state getting all fouled up. If somebody
  592                  * issues an 'offline' command, that will be allowed
  593                  * to clear state.
  594                  */
  595                 (void) sarewind(periph);
  596                 (void) saloadunload(periph, FALSE);
  597                 closedbits |= SA_FLAG_TAPE_MOUNTED|SA_FLAG_TAPE_FROZEN;
  598                 break;
  599         case SA_MODE_REWIND:
  600                 /*
  601                  * If the rewind fails, return an error- if anyone cares,
  602                  * but not overwriting any previous error.
  603                  *
  604                  * We don't clear the notion of mounted here, but we do
  605                  * clear the notion of frozen if we successfully rewound.
  606                  */
  607                 tmp = sarewind(periph);
  608                 if (tmp) {
  609                         if (error != 0)
  610                                 error = tmp;
  611                 } else {
  612                         closedbits |= SA_FLAG_TAPE_FROZEN;
  613                 }
  614                 break;
  615         case SA_MODE_NOREWIND:
  616                 /*
  617                  * If we're not rewinding/unloading the tape, find out
  618                  * whether we need to back up over one of two filemarks
  619                  * we wrote (if we wrote two filemarks) so that appends
  620                  * from this point on will be sane.
  621                  */
  622                 if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) {
  623                         tmp = saspace(periph, -1, SS_FILEMARKS);
  624                         if (tmp) {
  625                                 xpt_print_path(periph->path);
  626                                 printf("unable to backspace over one of double"
  627                                    " filemarks at end of tape\n");
  628                                 xpt_print_path(periph->path);
  629                                 printf("it is possible that this device"
  630                                    " needs a SA_QUIRK_1FM quirk set for it\n");
  631                                 softc->flags |= SA_FLAG_TAPE_FROZEN;
  632                         }
  633                 }
  634                 break;
  635         default:
  636                 xpt_print_path(periph->path);
  637                 panic("unknown mode 0x%x in saclose", mode);
  638                 /* NOTREACHED */
  639                 break;
  640         }
  641 
  642         /*
  643          * We wish to note here that there are no more filemarks to be written.
  644          */
  645         softc->filemarks = 0;
  646         softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
  647 
  648         /*
  649          * And we are no longer open for business.
  650          */
  651         softc->flags &= ~closedbits;
  652 
  653         /*
  654          * Inform users if tape state if frozen....
  655          */
  656         if (softc->flags & SA_FLAG_TAPE_FROZEN) {
  657                 xpt_print_path(periph->path);
  658                 printf("tape is now frozen- use an OFFLINE, REWIND or MTEOM "
  659                     "command to clear this state.\n");
  660         }
  661         
  662         /* release the device if it is no longer mounted */
  663         if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0)
  664                 sareservereleaseunit(periph, FALSE);
  665 
  666         cam_periph_unlock(periph);
  667         cam_periph_release(periph);
  668 
  669         return (error); 
  670 }
  671 
  672 /*
  673  * Actually translate the requested transfer into one the physical driver
  674  * can understand.  The transfer is described by a buf and will include
  675  * only one physical transfer.
  676  */
  677 static void
  678 sastrategy(struct bio *bp)
  679 {
  680         struct cam_periph *periph;
  681         struct sa_softc *softc;
  682         int    s;
  683         
  684         bp->bio_resid = bp->bio_bcount;
  685         if (SA_IS_CTRL(bp->bio_dev)) {
  686                 biofinish(bp, NULL, EINVAL);
  687                 return;
  688         }
  689         periph = (struct cam_periph *)bp->bio_dev->si_drv1;
  690         if (periph == NULL) {
  691                 biofinish(bp, NULL, ENXIO);
  692                 return;
  693         }
  694         softc = (struct sa_softc *)periph->softc;
  695 
  696         s = splsoftcam();
  697 
  698         if (softc->flags & SA_FLAG_INVALID) {
  699                 splx(s);
  700                 biofinish(bp, NULL, ENXIO);
  701                 return;
  702         }
  703 
  704         if (softc->flags & SA_FLAG_TAPE_FROZEN) {
  705                 splx(s);
  706                 biofinish(bp, NULL, EPERM);
  707                 return;
  708         }
  709 
  710         /*
  711          * This should actually never occur as the write(2)
  712          * system call traps attempts to write to a read-only
  713          * file descriptor.
  714          */
  715         if (bp->bio_cmd == BIO_WRITE && softc->open_rdonly) {
  716                 splx(s);
  717                 biofinish(bp, NULL, EBADF);
  718                 return;
  719         }
  720 
  721         splx(s);
  722 
  723         if (softc->open_pending_mount) {
  724                 int error = samount(periph, 0, bp->bio_dev);
  725                 if (error) {
  726                         biofinish(bp, NULL, ENXIO);
  727                         return;
  728                 }
  729                 saprevent(periph, PR_PREVENT);
  730                 softc->open_pending_mount = 0;
  731         }
  732 
  733 
  734         /*
  735          * If it's a null transfer, return immediately
  736          */
  737         if (bp->bio_bcount == 0) {
  738                 biodone(bp);
  739                 return;
  740         }
  741 
  742         /* valid request?  */
  743         if (softc->flags & SA_FLAG_FIXED) {
  744                 /*
  745                  * Fixed block device.  The byte count must
  746                  * be a multiple of our block size.
  747                  */
  748                 if (((softc->blk_mask != ~0) &&
  749                     ((bp->bio_bcount & softc->blk_mask) != 0)) ||
  750                     ((softc->blk_mask == ~0) &&
  751                     ((bp->bio_bcount % softc->min_blk) != 0))) {
  752                         xpt_print_path(periph->path);
  753                         printf("Invalid request.  Fixed block device "
  754                                "requests must be a multiple "
  755                                "of %d bytes\n", softc->min_blk);
  756                         biofinish(bp, NULL, EINVAL);
  757                         return;
  758                 }
  759         } else if ((bp->bio_bcount > softc->max_blk) ||
  760                    (bp->bio_bcount < softc->min_blk) ||
  761                    (bp->bio_bcount & softc->blk_mask) != 0) {
  762 
  763                 xpt_print_path(periph->path);
  764                 printf("Invalid request.  Variable block device "
  765                     "requests must be ");
  766                 if (softc->blk_mask != 0) {
  767                         printf("a multiple of %d ", (0x1 << softc->blk_gran));
  768                 }
  769                 printf("between %d and %d bytes\n", softc->min_blk,
  770                     softc->max_blk);
  771                 biofinish(bp, NULL, EINVAL);
  772                 return;
  773         }
  774         
  775         /*
  776          * Mask interrupts so that the device cannot be invalidated until
  777          * after we are in the queue.  Otherwise, we might not properly
  778          * clean up one of the buffers.
  779          */
  780         s = splbio();
  781         
  782         /*
  783          * Place it at the end of the queue.
  784          */
  785         bioq_insert_tail(&softc->bio_queue, bp);
  786         softc->queue_count++;
  787 #if     0
  788         CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
  789             ("sastrategy: queuing a %ld %s byte %s\n", bp->bio_bcount,
  790             (softc->flags & SA_FLAG_FIXED)?  "fixed" : "variable",
  791             (bp->bio_cmd == BIO_READ)? "read" : "write"));
  792 #endif
  793         if (softc->queue_count > 1) {
  794                 CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
  795                     ("sastrategy: queue count now %d\n", softc->queue_count));
  796         }
  797         splx(s);
  798         
  799         /*
  800          * Schedule ourselves for performing the work.
  801          */
  802         xpt_schedule(periph, 1);
  803 
  804         return;
  805 }
  806 
  807 
  808 #define PENDING_MOUNT_CHECK(softc, periph, dev)         \
  809         if (softc->open_pending_mount) {                \
  810                 error = samount(periph, 0, dev);        \
  811                 if (error) {                            \
  812                         break;                          \
  813                 }                                       \
  814                 saprevent(periph, PR_PREVENT);          \
  815                 softc->open_pending_mount = 0;          \
  816         }
  817 
  818 static int
  819 saioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
  820 {
  821         struct cam_periph *periph;
  822         struct sa_softc *softc;
  823         scsi_space_code spaceop;
  824         int didlockperiph = 0;
  825         int s;
  826         int mode;
  827         int error = 0;
  828 
  829         mode = SAMODE(dev);
  830         error = 0;              /* shut up gcc */
  831         spaceop = 0;            /* shut up gcc */
  832 
  833         periph = (struct cam_periph *)dev->si_drv1;
  834         if (periph == NULL)
  835                 return (ENXIO); 
  836 
  837         softc = (struct sa_softc *)periph->softc;
  838 
  839         /*
  840          * Check for control mode accesses. We allow MTIOCGET and
  841          * MTIOCERRSTAT (but need to be the only one open in order
  842          * to clear latched status), and MTSETBSIZE, MTSETDNSTY
  843          * and MTCOMP (but need to be the only one accessing this
  844          * device to run those).
  845          */
  846 
  847         if (SA_IS_CTRL(dev)) {
  848                 switch (cmd) {
  849                 case MTIOCGETEOTMODEL:
  850                 case MTIOCGET:
  851                         break;
  852                 case MTIOCERRSTAT:
  853                         /*
  854                          * If the periph isn't already locked, lock it
  855                          * so our MTIOCERRSTAT can reset latched error stats.
  856                          *
  857                          * If the periph is already locked, skip it because
  858                          * we're just getting status and it'll be up to the
  859                          * other thread that has this device open to do
  860                          * an MTIOCERRSTAT that would clear latched status.
  861                          */
  862                         s = splsoftcam();
  863                         if ((periph->flags & CAM_PERIPH_LOCKED) == 0) {
  864                                 error = cam_periph_lock(periph, PRIBIO|PCATCH);
  865                                 if (error != 0) {
  866                                         splx(s);
  867                                         return (error);
  868                                 }
  869                                 didlockperiph = 1;
  870                         }
  871                         break;
  872 
  873                 case MTIOCTOP:
  874                 {
  875                         struct mtop *mt = (struct mtop *) arg;
  876 
  877                         /*
  878                          * Check to make sure it's an OP we can perform
  879                          * with no media inserted.
  880                          */
  881                         switch (mt->mt_op) {
  882                         case MTSETBSIZ:
  883                         case MTSETDNSTY:
  884                         case MTCOMP:
  885                                 mt = NULL;
  886                                 /* FALLTHROUGH */
  887                         default:
  888                                 break;
  889                         }
  890                         if (mt != NULL) {
  891                                 break;
  892                         }
  893                         /* FALLTHROUGH */
  894                 }
  895                 case MTIOCSETEOTMODEL:
  896                         /*
  897                          * We need to acquire the peripheral here rather
  898                          * than at open time because we are sharing writable
  899                          * access to data structures.
  900                          */
  901                         s = splsoftcam();
  902                         error = cam_periph_lock(periph, PRIBIO|PCATCH);
  903                         if (error != 0) {
  904                                 splx(s);
  905                                 return (error);
  906                         }
  907                         didlockperiph = 1;
  908                         break;
  909 
  910                 default:
  911                         return (EINVAL);
  912                 }
  913         }
  914 
  915         /*
  916          * Find the device that the user is talking about
  917          */
  918         switch (cmd) {
  919         case MTIOCGET:
  920         {
  921                 struct mtget *g = (struct mtget *)arg;
  922 
  923                 /*
  924                  * If this isn't the control mode device, actually go out
  925                  * and ask the drive again what it's set to.
  926                  */
  927                 if (!SA_IS_CTRL(dev) && !softc->open_pending_mount) {
  928                         u_int8_t write_protect;
  929                         int comp_enabled, comp_supported;
  930                         error = sagetparams(periph, SA_PARAM_ALL,
  931                             &softc->media_blksize, &softc->media_density,
  932                             &softc->media_numblks, &softc->buffer_mode,
  933                             &write_protect, &softc->speed, &comp_supported,
  934                             &comp_enabled, &softc->comp_algorithm, NULL);
  935                         if (error)
  936                                 break;
  937                         if (write_protect)
  938                                 softc->flags |= SA_FLAG_TAPE_WP;
  939                         else
  940                                 softc->flags &= ~SA_FLAG_TAPE_WP;
  941                         softc->flags &= ~(SA_FLAG_COMP_SUPP|
  942                             SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP);
  943                         if (comp_supported) {
  944                                 if (softc->saved_comp_algorithm == 0)
  945                                         softc->saved_comp_algorithm =
  946                                             softc->comp_algorithm;
  947                                 softc->flags |= SA_FLAG_COMP_SUPP;
  948                                 if (comp_enabled)
  949                                         softc->flags |= SA_FLAG_COMP_ENABLED;
  950                         } else  
  951                                 softc->flags |= SA_FLAG_COMP_UNSUPP;
  952                 }
  953                 bzero(g, sizeof(struct mtget));
  954                 g->mt_type = MT_ISAR;
  955                 if (softc->flags & SA_FLAG_COMP_UNSUPP) {
  956                         g->mt_comp = MT_COMP_UNSUPP;
  957                         g->mt_comp0 = MT_COMP_UNSUPP;
  958                         g->mt_comp1 = MT_COMP_UNSUPP;
  959                         g->mt_comp2 = MT_COMP_UNSUPP;
  960                         g->mt_comp3 = MT_COMP_UNSUPP;
  961                 } else {
  962                         if ((softc->flags & SA_FLAG_COMP_ENABLED) == 0) {
  963                                 g->mt_comp = MT_COMP_DISABLED;
  964                         } else {
  965                                 g->mt_comp = softc->comp_algorithm;
  966                         }
  967                         g->mt_comp0 = softc->comp_algorithm;
  968                         g->mt_comp1 = softc->comp_algorithm;
  969                         g->mt_comp2 = softc->comp_algorithm;
  970                         g->mt_comp3 = softc->comp_algorithm;
  971                 }
  972                 g->mt_density = softc->media_density;
  973                 g->mt_density0 = softc->media_density;
  974                 g->mt_density1 = softc->media_density;
  975                 g->mt_density2 = softc->media_density;
  976                 g->mt_density3 = softc->media_density;
  977                 g->mt_blksiz = softc->media_blksize;
  978                 g->mt_blksiz0 = softc->media_blksize;
  979                 g->mt_blksiz1 = softc->media_blksize;
  980                 g->mt_blksiz2 = softc->media_blksize;
  981                 g->mt_blksiz3 = softc->media_blksize;
  982                 g->mt_fileno = softc->fileno;
  983                 g->mt_blkno = softc->blkno;
  984                 g->mt_dsreg = (short) softc->dsreg;
  985                 /*
  986                  * Yes, we know that this is likely to overflow
  987                  */
  988                 if (softc->last_resid_was_io) {
  989                         if ((g->mt_resid = (short) softc->last_io_resid) != 0) {
  990                                 if (SA_IS_CTRL(dev) == 0 || didlockperiph) {
  991                                         softc->last_io_resid = 0;
  992                                 }
  993                         }
  994                 } else {
  995                         if ((g->mt_resid = (short)softc->last_ctl_resid) != 0) {
  996                                 if (SA_IS_CTRL(dev) == 0 || didlockperiph) {
  997                                         softc->last_ctl_resid = 0;
  998                                 }
  999                         }
 1000                 }
 1001                 error = 0;
 1002                 break;
 1003         }
 1004         case MTIOCERRSTAT:
 1005         {
 1006                 struct scsi_tape_errors *sep =
 1007                     &((union mterrstat *)arg)->scsi_errstat;
 1008 
 1009                 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
 1010                     ("saioctl: MTIOCERRSTAT\n"));
 1011 
 1012                 bzero(sep, sizeof(*sep));
 1013                 sep->io_resid = softc->last_io_resid;
 1014                 bcopy((caddr_t) &softc->last_io_sense, sep->io_sense,
 1015                     sizeof (sep->io_sense));
 1016                 bcopy((caddr_t) &softc->last_io_cdb, sep->io_cdb,
 1017                     sizeof (sep->io_cdb));
 1018                 sep->ctl_resid = softc->last_ctl_resid;
 1019                 bcopy((caddr_t) &softc->last_ctl_sense, sep->ctl_sense,
 1020                     sizeof (sep->ctl_sense));
 1021                 bcopy((caddr_t) &softc->last_ctl_cdb, sep->ctl_cdb,
 1022                     sizeof (sep->ctl_cdb));
 1023 
 1024                 if ((SA_IS_CTRL(dev) == 0 && softc->open_pending_mount) ||
 1025                     didlockperiph)
 1026                         bzero((caddr_t) &softc->errinfo,
 1027                             sizeof (softc->errinfo));
 1028                 error = 0;
 1029                 break;
 1030         }
 1031         case MTIOCTOP:
 1032         {
 1033                 struct mtop *mt;
 1034                 int    count;
 1035 
 1036                 PENDING_MOUNT_CHECK(softc, periph, dev);
 1037 
 1038                 mt = (struct mtop *)arg;
 1039 
 1040 
 1041                 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
 1042                          ("saioctl: op=0x%x count=0x%x\n",
 1043                           mt->mt_op, mt->mt_count));
 1044 
 1045                 count = mt->mt_count;
 1046                 switch (mt->mt_op) {
 1047                 case MTWEOF:    /* write an end-of-file marker */
 1048                         /*
 1049                          * We don't need to clear the SA_FLAG_TAPE_WRITTEN
 1050                          * flag because by keeping track of filemarks
 1051                          * we have last written we know ehether or not
 1052                          * we need to write more when we close the device.
 1053                          */
 1054                         error = sawritefilemarks(periph, count, FALSE);
 1055                         break;
 1056                 case MTWSS:     /* write a setmark */
 1057                         error = sawritefilemarks(periph, count, TRUE);
 1058                         break;
 1059                 case MTBSR:     /* backward space record */
 1060                 case MTFSR:     /* forward space record */
 1061                 case MTBSF:     /* backward space file */
 1062                 case MTFSF:     /* forward space file */
 1063                 case MTBSS:     /* backward space setmark */
 1064                 case MTFSS:     /* forward space setmark */
 1065                 case MTEOD:     /* space to end of recorded medium */
 1066                 {
 1067                         int nmarks;
 1068 
 1069                         spaceop = SS_FILEMARKS;
 1070                         nmarks = softc->filemarks;
 1071                         error = sacheckeod(periph);
 1072                         if (error) {
 1073                                 xpt_print_path(periph->path);
 1074                                 printf("EOD check prior to spacing failed\n");
 1075                                 softc->flags |= SA_FLAG_EIO_PENDING;
 1076                                 break;
 1077                         }
 1078                         nmarks -= softc->filemarks;
 1079                         switch(mt->mt_op) {
 1080                         case MTBSR:
 1081                                 count = -count;
 1082                                 /* FALLTHROUGH */
 1083                         case MTFSR:
 1084                                 spaceop = SS_BLOCKS;
 1085                                 break;
 1086                         case MTBSF:
 1087                                 count = -count;
 1088                                 /* FALLTHROUGH */
 1089                         case MTFSF:
 1090                                 break;
 1091                         case MTBSS:
 1092                                 count = -count;
 1093                                 /* FALLTHROUGH */
 1094                         case MTFSS:
 1095                                 spaceop = SS_SETMARKS;
 1096                                 break;
 1097                         case MTEOD:
 1098                                 spaceop = SS_EOD;
 1099                                 count = 0;
 1100                                 nmarks = 0;
 1101                                 break;
 1102                         default:
 1103                                 error = EINVAL;
 1104                                 break;
 1105                         }
 1106                         if (error)
 1107                                 break;
 1108 
 1109                         nmarks = softc->filemarks;
 1110                         /*
 1111                          * XXX: Why are we checking again?
 1112                          */
 1113                         error = sacheckeod(periph);
 1114                         if (error)
 1115                                 break;
 1116                         nmarks -= softc->filemarks;
 1117                         error = saspace(periph, count - nmarks, spaceop);
 1118                         /*
 1119                          * At this point, clear that we've written the tape
 1120                          * and that we've written any filemarks. We really
 1121                          * don't know what the applications wishes to do next-
 1122                          * the sacheckeod's will make sure we terminated the
 1123                          * tape correctly if we'd been writing, but the next
 1124                          * action the user application takes will set again
 1125                          * whether we need to write filemarks.
 1126                          */
 1127                         softc->flags &=
 1128                             ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
 1129                         softc->filemarks = 0;
 1130                         break;
 1131                 }
 1132                 case MTREW:     /* rewind */
 1133                         PENDING_MOUNT_CHECK(softc, periph, dev);
 1134                         (void) sacheckeod(periph);
 1135                         error = sarewind(periph);
 1136                         /* see above */
 1137                         softc->flags &=
 1138                             ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
 1139                         softc->flags &= ~SA_FLAG_ERR_PENDING;
 1140                         softc->filemarks = 0;
 1141                         break;
 1142                 case MTERASE:   /* erase */
 1143                         PENDING_MOUNT_CHECK(softc, periph, dev);
 1144                         error = saerase(periph, count);
 1145                         softc->flags &=
 1146                             ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
 1147                         softc->flags &= ~SA_FLAG_ERR_PENDING;
 1148                         break;
 1149                 case MTRETENS:  /* re-tension tape */
 1150                         PENDING_MOUNT_CHECK(softc, periph, dev);
 1151                         error = saretension(periph);            
 1152                         softc->flags &=
 1153                             ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
 1154                         softc->flags &= ~SA_FLAG_ERR_PENDING;
 1155                         break;
 1156                 case MTOFFL:    /* rewind and put the drive offline */
 1157 
 1158                         PENDING_MOUNT_CHECK(softc, periph, dev);
 1159 
 1160                         (void) sacheckeod(periph);
 1161                         /* see above */
 1162                         softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
 1163                         softc->filemarks = 0;
 1164 
 1165                         error = sarewind(periph);
 1166                         /* clear the frozen flag anyway */
 1167                         softc->flags &= ~SA_FLAG_TAPE_FROZEN;
 1168 
 1169                         /*
 1170                          * Be sure to allow media removal before ejecting.
 1171                          */
 1172 
 1173                         saprevent(periph, PR_ALLOW);
 1174                         if (error == 0) {
 1175                                 error = saloadunload(periph, FALSE);
 1176                                 if (error == 0) {
 1177                                         softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
 1178                                 }
 1179                         }
 1180                         break;
 1181 
 1182                 case MTNOP:     /* no operation, sets status only */
 1183                 case MTCACHE:   /* enable controller cache */
 1184                 case MTNOCACHE: /* disable controller cache */
 1185                         error = 0;
 1186                         break;
 1187 
 1188                 case MTSETBSIZ: /* Set block size for device */
 1189 
 1190                         PENDING_MOUNT_CHECK(softc, periph, dev);
 1191 
 1192                         error = sasetparams(periph, SA_PARAM_BLOCKSIZE, count,
 1193                                             0, 0, 0);
 1194                         if (error == 0) {
 1195                                 softc->last_media_blksize =
 1196                                     softc->media_blksize;
 1197                                 softc->media_blksize = count;
 1198                                 if (count) {
 1199                                         softc->flags |= SA_FLAG_FIXED;
 1200                                         if (powerof2(count)) {
 1201                                                 softc->blk_shift =
 1202                                                     ffs(count) - 1;
 1203                                                 softc->blk_mask = count - 1;
 1204                                         } else {
 1205                                                 softc->blk_mask = ~0;
 1206                                                 softc->blk_shift = 0;
 1207                                         }
 1208                                         /*
 1209                                          * Make the user's desire 'persistent'.
 1210                                          */
 1211                                         softc->quirks &= ~SA_QUIRK_VARIABLE;
 1212                                         softc->quirks |= SA_QUIRK_FIXED;
 1213                                 } else {
 1214                                         softc->flags &= ~SA_FLAG_FIXED;
 1215                                         if (softc->max_blk == 0) {
 1216                                                 softc->max_blk = ~0;
 1217                                         }
 1218                                         softc->blk_shift = 0;
 1219                                         if (softc->blk_gran != 0) {
 1220                                                 softc->blk_mask =
 1221                                                     softc->blk_gran - 1;
 1222                                         } else {
 1223                                                 softc->blk_mask = 0;
 1224                                         }
 1225                                         /*
 1226                                          * Make the user's desire 'persistent'.
 1227                                          */
 1228                                         softc->quirks |= SA_QUIRK_VARIABLE;
 1229                                         softc->quirks &= ~SA_QUIRK_FIXED;
 1230                                 }
 1231                         }
 1232                         break;
 1233                 case MTSETDNSTY:        /* Set density for device and mode */
 1234                         PENDING_MOUNT_CHECK(softc, periph, dev);
 1235 
 1236                         if (count > UCHAR_MAX) {
 1237                                 error = EINVAL; 
 1238                                 break;
 1239                         } else {
 1240                                 error = sasetparams(periph, SA_PARAM_DENSITY,
 1241                                                     0, count, 0, 0);
 1242                         }
 1243                         break;
 1244                 case MTCOMP:    /* enable compression */
 1245                         PENDING_MOUNT_CHECK(softc, periph, dev);
 1246                         /*
 1247                          * Some devices don't support compression, and
 1248                          * don't like it if you ask them for the
 1249                          * compression page.
 1250                          */
 1251                         if ((softc->quirks & SA_QUIRK_NOCOMP) ||
 1252                             (softc->flags & SA_FLAG_COMP_UNSUPP)) {
 1253                                 error = ENODEV;
 1254                                 break;
 1255                         }
 1256                         error = sasetparams(periph, SA_PARAM_COMPRESSION,
 1257                             0, 0, count, SF_NO_PRINT);
 1258                         break;
 1259                 default:
 1260                         error = EINVAL;
 1261                 }
 1262                 break;
 1263         }
 1264         case MTIOCIEOT:
 1265         case MTIOCEEOT:
 1266                 error = 0;
 1267                 break;
 1268         case MTIOCRDSPOS:
 1269                 PENDING_MOUNT_CHECK(softc, periph, dev);
 1270                 error = sardpos(periph, 0, (u_int32_t *) arg);
 1271                 break;
 1272         case MTIOCRDHPOS:
 1273                 PENDING_MOUNT_CHECK(softc, periph, dev);
 1274                 error = sardpos(periph, 1, (u_int32_t *) arg);
 1275                 break;
 1276         case MTIOCSLOCATE:
 1277                 PENDING_MOUNT_CHECK(softc, periph, dev);
 1278                 error = sasetpos(periph, 0, (u_int32_t *) arg);
 1279                 break;
 1280         case MTIOCHLOCATE:
 1281                 PENDING_MOUNT_CHECK(softc, periph, dev);
 1282                 error = sasetpos(periph, 1, (u_int32_t *) arg);
 1283                 break;
 1284         case MTIOCGETEOTMODEL:
 1285                 error = 0;
 1286                 if (softc->quirks & SA_QUIRK_1FM)
 1287                         mode = 1;
 1288                 else
 1289                         mode = 2;
 1290                 *((u_int32_t *) arg) = mode;
 1291                 break;
 1292         case MTIOCSETEOTMODEL:
 1293                 error = 0;
 1294                 switch (*((u_int32_t *) arg)) {
 1295                 case 1:
 1296                         softc->quirks &= ~SA_QUIRK_2FM;
 1297                         softc->quirks |= SA_QUIRK_1FM;
 1298                         break;
 1299                 case 2:
 1300                         softc->quirks &= ~SA_QUIRK_1FM;
 1301                         softc->quirks |= SA_QUIRK_2FM;
 1302                         break;
 1303                 default:
 1304                         error = EINVAL;
 1305                         break;
 1306                 }
 1307                 break;
 1308         default:
 1309                 error = cam_periph_ioctl(periph, cmd, arg, saerror);
 1310                 break;
 1311         }
 1312 
 1313         /*
 1314          * Check to see if we cleared a frozen state
 1315          */
 1316         if (error == 0 && (softc->flags & SA_FLAG_TAPE_FROZEN)) {
 1317                 switch(cmd) {
 1318                 case MTIOCRDSPOS:
 1319                 case MTIOCRDHPOS:
 1320                 case MTIOCSLOCATE:
 1321                 case MTIOCHLOCATE:
 1322                         softc->fileno = (daddr_t) -1;
 1323                         softc->blkno = (daddr_t) -1;
 1324                         softc->flags &= ~SA_FLAG_TAPE_FROZEN;
 1325                         xpt_print_path(periph->path);
 1326                         printf("tape state now unfrozen.\n");
 1327                         break;
 1328                 default:
 1329                         break;
 1330                 }
 1331         }
 1332         if (didlockperiph) {
 1333                 cam_periph_unlock(periph);
 1334         }
 1335         return (error);
 1336 }
 1337 
 1338 static void
 1339 sainit(void)
 1340 {
 1341         cam_status status;
 1342         struct cam_path *path;
 1343 
 1344         /*
 1345          * Install a global async callback.
 1346          */
 1347         status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID,
 1348                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
 1349 
 1350         if (status == CAM_REQ_CMP) {
 1351                 /* Register the async callbacks of interrest */
 1352                 struct ccb_setasync csa; /*
 1353                                           * This is an immediate CCB,
 1354                                           * so using the stack is OK
 1355                                           */
 1356                 xpt_setup_ccb(&csa.ccb_h, path, 5);
 1357                 csa.ccb_h.func_code = XPT_SASYNC_CB;
 1358                 csa.event_enable = AC_FOUND_DEVICE;
 1359                 csa.callback = saasync;
 1360                 csa.callback_arg = NULL;
 1361                 xpt_action((union ccb *)&csa);
 1362                 status = csa.ccb_h.status;
 1363                 xpt_free_path(path);
 1364         }
 1365 
 1366         if (status != CAM_REQ_CMP) {
 1367                 printf("sa: Failed to attach master async callback "
 1368                        "due to status 0x%x!\n", status);
 1369         }
 1370 }
 1371 
 1372 static void
 1373 saoninvalidate(struct cam_periph *periph)
 1374 {
 1375         struct sa_softc *softc;
 1376         struct ccb_setasync csa;
 1377         int s;
 1378 
 1379         softc = (struct sa_softc *)periph->softc;
 1380 
 1381         /*
 1382          * De-register any async callbacks.
 1383          */
 1384         xpt_setup_ccb(&csa.ccb_h, periph->path,
 1385                       /* priority */ 5);
 1386         csa.ccb_h.func_code = XPT_SASYNC_CB;
 1387         csa.event_enable = 0;
 1388         csa.callback = saasync;
 1389         csa.callback_arg = periph;
 1390         xpt_action((union ccb *)&csa);
 1391 
 1392         softc->flags |= SA_FLAG_INVALID;
 1393 
 1394         /*
 1395          * Although the oninvalidate() routines are always called at
 1396          * splsoftcam, we need to be at splbio() here to keep the buffer
 1397          * queue from being modified while we traverse it.
 1398          */
 1399         s = splbio();
 1400 
 1401         /*
 1402          * Return all queued I/O with ENXIO.
 1403          * XXX Handle any transactions queued to the card
 1404          *     with XPT_ABORT_CCB.
 1405          */
 1406         bioq_flush(&softc->bio_queue, NULL, ENXIO);
 1407         softc->queue_count = 0;
 1408         splx(s);
 1409 
 1410         xpt_print_path(periph->path);
 1411         printf("lost device\n");
 1412 
 1413 }
 1414 
 1415 static void
 1416 sacleanup(struct cam_periph *periph)
 1417 {
 1418         struct sa_softc *softc;
 1419         int i;
 1420 
 1421         softc = (struct sa_softc *)periph->softc;
 1422 
 1423         devstat_remove_entry(softc->device_stats);
 1424 
 1425         destroy_dev(softc->devs.ctl_dev);
 1426 
 1427         for (i = 0; i < SA_NUM_MODES; i++) {
 1428                 destroy_dev(softc->devs.mode_devs[i].r_dev);
 1429                 destroy_dev(softc->devs.mode_devs[i].nr_dev);
 1430                 destroy_dev(softc->devs.mode_devs[i].er_dev);
 1431         }
 1432 
 1433         xpt_print_path(periph->path);
 1434         printf("removing device entry\n");
 1435         free(softc, M_SCSISA);
 1436 }
 1437 
 1438 static void
 1439 saasync(void *callback_arg, u_int32_t code,
 1440         struct cam_path *path, void *arg)
 1441 {
 1442         struct cam_periph *periph;
 1443 
 1444         periph = (struct cam_periph *)callback_arg;
 1445         switch (code) {
 1446         case AC_FOUND_DEVICE:
 1447         {
 1448                 struct ccb_getdev *cgd;
 1449                 cam_status status;
 1450 
 1451                 cgd = (struct ccb_getdev *)arg;
 1452                 if (cgd == NULL)
 1453                         break;
 1454 
 1455                 if (SID_TYPE(&cgd->inq_data) != T_SEQUENTIAL)
 1456                         break;
 1457 
 1458                 /*
 1459                  * Allocate a peripheral instance for
 1460                  * this device and start the probe
 1461                  * process.
 1462                  */
 1463                 status = cam_periph_alloc(saregister, saoninvalidate,
 1464                                           sacleanup, sastart,
 1465                                           "sa", CAM_PERIPH_BIO, cgd->ccb_h.path,
 1466                                           saasync, AC_FOUND_DEVICE, cgd);
 1467 
 1468                 if (status != CAM_REQ_CMP
 1469                  && status != CAM_REQ_INPROG)
 1470                         printf("saasync: Unable to probe new device "
 1471                                 "due to status 0x%x\n", status);
 1472                 break;
 1473         }
 1474         default:
 1475                 cam_periph_async(periph, code, path, arg);
 1476                 break;
 1477         }
 1478 }
 1479 
 1480 static cam_status
 1481 saregister(struct cam_periph *periph, void *arg)
 1482 {
 1483         struct sa_softc *softc;
 1484         struct ccb_setasync csa;
 1485         struct ccb_getdev *cgd;
 1486         caddr_t match;
 1487         int i;
 1488         
 1489         cgd = (struct ccb_getdev *)arg;
 1490         if (periph == NULL) {
 1491                 printf("saregister: periph was NULL!!\n");
 1492                 return (CAM_REQ_CMP_ERR);
 1493         }
 1494 
 1495         if (cgd == NULL) {
 1496                 printf("saregister: no getdev CCB, can't register device\n");
 1497                 return (CAM_REQ_CMP_ERR);
 1498         }
 1499 
 1500         softc = (struct sa_softc *)
 1501             malloc(sizeof (*softc), M_SCSISA, M_NOWAIT | M_ZERO);
 1502         if (softc == NULL) {
 1503                 printf("saregister: Unable to probe new device. "
 1504                        "Unable to allocate softc\n");                           
 1505                 return (CAM_REQ_CMP_ERR);
 1506         }
 1507         softc->scsi_rev = SID_ANSI_REV(&cgd->inq_data);
 1508         softc->state = SA_STATE_NORMAL;
 1509         softc->fileno = (daddr_t) -1;
 1510         softc->blkno = (daddr_t) -1;
 1511 
 1512         bioq_init(&softc->bio_queue);
 1513         periph->softc = softc;
 1514 
 1515         /*
 1516          * See if this device has any quirks.
 1517          */
 1518         match = cam_quirkmatch((caddr_t)&cgd->inq_data,
 1519                                (caddr_t)sa_quirk_table,
 1520                                sizeof(sa_quirk_table)/sizeof(*sa_quirk_table),
 1521                                sizeof(*sa_quirk_table), scsi_inquiry_match);
 1522 
 1523         if (match != NULL) {
 1524                 softc->quirks = ((struct sa_quirk_entry *)match)->quirks;
 1525                 softc->last_media_blksize =
 1526                     ((struct sa_quirk_entry *)match)->prefblk;
 1527 #ifdef  CAMDEBUG
 1528                 xpt_print_path(periph->path);
 1529                 printf("found quirk entry %d\n", (int)
 1530                     (((struct sa_quirk_entry *) match) - sa_quirk_table));
 1531 #endif
 1532         } else
 1533                 softc->quirks = SA_QUIRK_NONE;
 1534 
 1535         /*
 1536          * The SA driver supports a blocksize, but we don't know the
 1537          * blocksize until we media is inserted.  So, set a flag to
 1538          * indicate that the blocksize is unavailable right now.
 1539          */
 1540         softc->device_stats = devstat_new_entry("sa", periph->unit_number, 0,
 1541             DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) |
 1542             DEVSTAT_TYPE_IF_SCSI, DEVSTAT_PRIORITY_TAPE);
 1543 
 1544         softc->devs.ctl_dev = make_dev(&sa_cdevsw, SAMINOR(SA_CTLDEV,
 1545             periph->unit_number, 0, SA_ATYPE_R), UID_ROOT, GID_OPERATOR,
 1546             0660, "%s%d.ctl", periph->periph_name, periph->unit_number);
 1547         softc->devs.ctl_dev->si_drv1 = periph;
 1548 
 1549         for (i = 0; i < SA_NUM_MODES; i++) {
 1550 
 1551                 softc->devs.mode_devs[i].r_dev = make_dev(&sa_cdevsw,
 1552                     SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_R),
 1553                     UID_ROOT, GID_OPERATOR, 0660, "%s%d.%d",
 1554                     periph->periph_name, periph->unit_number, i);
 1555                 softc->devs.mode_devs[i].r_dev->si_drv1 = periph;
 1556 
 1557                 softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw,
 1558                     SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_NR),
 1559                     UID_ROOT, GID_OPERATOR, 0660, "n%s%d.%d",
 1560                     periph->periph_name, periph->unit_number, i);
 1561                 softc->devs.mode_devs[i].nr_dev->si_drv1 = periph;
 1562 
 1563                 softc->devs.mode_devs[i].er_dev = make_dev(&sa_cdevsw,
 1564                     SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_ER),
 1565                     UID_ROOT, GID_OPERATOR, 0660, "e%s%d.%d",
 1566                     periph->periph_name, periph->unit_number, i);
 1567                 softc->devs.mode_devs[i].er_dev->si_drv1 = periph;
 1568 
 1569                 /*
 1570                  * Make the (well known) aliases for the first mode.
 1571                  */
 1572                 if (i == 0) {
 1573                         struct cdev *alias;
 1574 
 1575                         alias = make_dev_alias(softc->devs.mode_devs[i].r_dev,
 1576                            "%s%d", periph->periph_name, periph->unit_number);
 1577                         alias->si_drv1 = periph;
 1578                         alias = make_dev_alias(softc->devs.mode_devs[i].nr_dev,
 1579                             "n%s%d", periph->periph_name, periph->unit_number);
 1580                         alias->si_drv1 = periph;
 1581                         alias = make_dev_alias(softc->devs.mode_devs[i].er_dev,
 1582                             "e%s%d", periph->periph_name, periph->unit_number);
 1583                         alias->si_drv1 = periph;
 1584                 }
 1585         }
 1586 
 1587         /*
 1588          * Add an async callback so that we get
 1589          * notified if this device goes away.
 1590          */
 1591         xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
 1592         csa.ccb_h.func_code = XPT_SASYNC_CB;
 1593         csa.event_enable = AC_LOST_DEVICE;
 1594         csa.callback = saasync;
 1595         csa.callback_arg = periph;
 1596         xpt_action((union ccb *)&csa);
 1597 
 1598         xpt_announce_periph(periph, NULL);
 1599 
 1600         return (CAM_REQ_CMP);
 1601 }
 1602 
 1603 static void
 1604 sastart(struct cam_periph *periph, union ccb *start_ccb)
 1605 {
 1606         struct sa_softc *softc;
 1607 
 1608         softc = (struct sa_softc *)periph->softc;
 1609 
 1610         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sastart\n"));
 1611 
 1612         
 1613         switch (softc->state) {
 1614         case SA_STATE_NORMAL:
 1615         {
 1616                 /* Pull a buffer from the queue and get going on it */          
 1617                 struct bio *bp;
 1618                 int s;
 1619 
 1620                 /*
 1621                  * See if there is a buf with work for us to do..
 1622                  */
 1623                 s = splbio();
 1624                 bp = bioq_first(&softc->bio_queue);
 1625                 if (periph->immediate_priority <= periph->pinfo.priority) {
 1626                         CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
 1627                                         ("queuing for immediate ccb\n"));
 1628                         Set_CCB_Type(start_ccb, SA_CCB_WAITING);
 1629                         SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 1630                                           periph_links.sle);
 1631                         periph->immediate_priority = CAM_PRIORITY_NONE;
 1632                         splx(s);
 1633                         wakeup(&periph->ccb_list);
 1634                 } else if (bp == NULL) {
 1635                         splx(s);
 1636                         xpt_release_ccb(start_ccb);
 1637                 } else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) {
 1638                         struct bio *done_bp;
 1639 again:
 1640                         softc->queue_count--;
 1641                         bioq_remove(&softc->bio_queue, bp);
 1642                         bp->bio_resid = bp->bio_bcount;
 1643                         done_bp = bp;
 1644                         if ((softc->flags & SA_FLAG_EOM_PENDING) != 0) {
 1645                                 /*
 1646                                  * We now just clear errors in this case
 1647                                  * and let the residual be the notifier.
 1648                                  */
 1649                                 bp->bio_error = 0;
 1650                         } else if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) {
 1651                                 /*
 1652                                  * This can only happen if we're reading
 1653                                  * in fixed length mode. In this case,
 1654                                  * we dump the rest of the list the
 1655                                  * same way.
 1656                                  */
 1657                                 bp->bio_error = 0;
 1658                                 if (bioq_first(&softc->bio_queue) != NULL) {
 1659                                         biodone(done_bp);
 1660                                         goto again;
 1661                                 }
 1662                         } else if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) {
 1663                                 bp->bio_error = EIO;
 1664                                 bp->bio_flags |= BIO_ERROR;
 1665                         }
 1666                         bp = bioq_first(&softc->bio_queue);
 1667                         /*
 1668                          * Only if we have no other buffers queued up
 1669                          * do we clear the pending error flag.
 1670                          */
 1671                         if (bp == NULL)
 1672                                 softc->flags &= ~SA_FLAG_ERR_PENDING;
 1673                         CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
 1674                             ("sastart- ERR_PENDING now 0x%x, bp is %sNULL, "
 1675                             "%d more buffers queued up\n",
 1676                             (softc->flags & SA_FLAG_ERR_PENDING),
 1677                             (bp != NULL)? "not " : " ", softc->queue_count));
 1678                         splx(s);
 1679                         xpt_release_ccb(start_ccb);
 1680                         biodone(done_bp);
 1681                 } else {
 1682                         u_int32_t length;
 1683 
 1684                         bioq_remove(&softc->bio_queue, bp);
 1685                         softc->queue_count--;
 1686 
 1687                         if ((softc->flags & SA_FLAG_FIXED) != 0) {
 1688                                 if (softc->blk_shift != 0) {
 1689                                         length =
 1690                                             bp->bio_bcount >> softc->blk_shift;
 1691                                 } else if (softc->media_blksize != 0) {
 1692                                         length = bp->bio_bcount /
 1693                                             softc->media_blksize;
 1694                                 } else {
 1695                                         bp->bio_error = EIO;
 1696                                         xpt_print_path(periph->path);
 1697                                         printf("zero blocksize for "
 1698                                             "FIXED length writes?\n");
 1699                                         splx(s);
 1700                                         biodone(bp);
 1701                                         break;
 1702                                 }
 1703 #if     0
 1704                                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
 1705                                     ("issuing a %d fixed record %s\n",
 1706                                     length,  (bp->bio_cmd == BIO_READ)? "read" :
 1707                                     "write"));
 1708 #endif
 1709                         } else {
 1710                                 length = bp->bio_bcount;
 1711 #if     0
 1712                                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
 1713                                     ("issuing a %d variable byte %s\n",
 1714                                     length,  (bp->bio_cmd == BIO_READ)? "read" :
 1715                                     "write"));
 1716 #endif
 1717                         }
 1718                         devstat_start_transaction_bio(softc->device_stats, bp);
 1719                         /*
 1720                          * Some people have theorized that we should
 1721                          * suppress illegal length indication if we are
 1722                          * running in variable block mode so that we don't
 1723                          * have to request sense every time our requested
 1724                          * block size is larger than the written block.
 1725                          * The residual information from the ccb allows
 1726                          * us to identify this situation anyway.  The only
 1727                          * problem with this is that we will not get
 1728                          * information about blocks that are larger than
 1729                          * our read buffer unless we set the block size
 1730                          * in the mode page to something other than 0.
 1731                          *
 1732                          * I believe that this is a non-issue. If user apps
 1733                          * don't adjust their read size to match our record
 1734                          * size, that's just life. Anyway, the typical usage
 1735                          * would be to issue, e.g., 64KB reads and occasionally
 1736                          * have to do deal with 512 byte or 1KB intermediate
 1737                          * records.
 1738                          */
 1739                         softc->dsreg = (bp->bio_cmd == BIO_READ)?
 1740                             MTIO_DSREG_RD : MTIO_DSREG_WR;
 1741                         scsi_sa_read_write(&start_ccb->csio, 0, sadone,
 1742                             MSG_SIMPLE_Q_TAG, (bp->bio_cmd == BIO_READ),
 1743                             FALSE, (softc->flags & SA_FLAG_FIXED) != 0,
 1744                             length, bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE,
 1745                             IO_TIMEOUT);
 1746                         start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED;
 1747                         Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO);
 1748                         start_ccb->ccb_h.ccb_bp = bp;
 1749                         bp = bioq_first(&softc->bio_queue);
 1750                         splx(s);
 1751                         xpt_action(start_ccb);
 1752                 }
 1753                 
 1754                 if (bp != NULL) {
 1755                         /* Have more work to do, so ensure we stay scheduled */
 1756                         xpt_schedule(periph, 1);
 1757                 }
 1758                 break;
 1759         }
 1760         case SA_STATE_ABNORMAL:
 1761         default:
 1762                 panic("state 0x%x in sastart", softc->state);
 1763                 break;
 1764         }
 1765 }
 1766 
 1767 
 1768 static void
 1769 sadone(struct cam_periph *periph, union ccb *done_ccb)
 1770 {
 1771         struct sa_softc *softc;
 1772         struct ccb_scsiio *csio;
 1773 
 1774         softc = (struct sa_softc *)periph->softc;
 1775         csio = &done_ccb->csio;
 1776         switch (CCB_Type(csio)) {
 1777         case SA_CCB_BUFFER_IO:
 1778         {
 1779                 struct bio *bp;
 1780                 int error;
 1781 
 1782                 softc->dsreg = MTIO_DSREG_REST;
 1783                 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
 1784                 error = 0;
 1785                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 1786                         if ((error = saerror(done_ccb, 0, 0)) == ERESTART) {
 1787                                 /*
 1788                                  * A retry was scheduled, so just return.
 1789                                  */
 1790                                 return;
 1791                         }
 1792                 }
 1793 
 1794                 if (error == EIO) {
 1795                         int s;                  
 1796 
 1797                         /*
 1798                          * Catastrophic error. Mark the tape as frozen
 1799                          * (we no longer know tape position).
 1800                          *
 1801                          * Return all queued I/O with EIO, and unfreeze
 1802                          * our queue so that future transactions that
 1803                          * attempt to fix this problem can get to the
 1804                          * device.
 1805                          *
 1806                          */
 1807 
 1808                         s = splbio();
 1809                         softc->flags |= SA_FLAG_TAPE_FROZEN;
 1810                         bioq_flush(&softc->bio_queue, NULL, EIO);
 1811                         splx(s);
 1812                 }
 1813                 if (error != 0) {
 1814                         bp->bio_resid = bp->bio_bcount;
 1815                         bp->bio_error = error;
 1816                         bp->bio_flags |= BIO_ERROR;
 1817                         /*
 1818                          * In the error case, position is updated in saerror.
 1819                          */
 1820                 } else {
 1821                         bp->bio_resid = csio->resid;
 1822                         bp->bio_error = 0;
 1823                         if (csio->resid != 0) {
 1824                                 bp->bio_flags |= BIO_ERROR;
 1825                         }
 1826                         if (bp->bio_cmd == BIO_WRITE) {
 1827                                 softc->flags |= SA_FLAG_TAPE_WRITTEN;
 1828                                 softc->filemarks = 0;
 1829                         }
 1830                         if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) &&
 1831                             (softc->blkno != (daddr_t) -1)) {
 1832                                 if ((softc->flags & SA_FLAG_FIXED) != 0) {
 1833                                         u_int32_t l;
 1834                                         if (softc->blk_shift != 0) {
 1835                                                 l = bp->bio_bcount >>
 1836                                                         softc->blk_shift;
 1837                                         } else {
 1838                                                 l = bp->bio_bcount /
 1839                                                         softc->media_blksize;
 1840                                         }
 1841                                         softc->blkno += (daddr_t) l;
 1842                                 } else {
 1843                                         softc->blkno++;
 1844                                 }
 1845                         }
 1846                 }
 1847                 /*
 1848                  * If we had an error (immediate or pending),
 1849                  * release the device queue now.
 1850                  */
 1851                 if (error || (softc->flags & SA_FLAG_ERR_PENDING))
 1852                         cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
 1853 #ifdef  CAMDEBUG
 1854                 if (error || bp->bio_resid) {
 1855                         CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
 1856                                   ("error %d resid %ld count %ld\n", error,
 1857                                   bp->bio_resid, bp->bio_bcount));
 1858                 }
 1859 #endif
 1860                 biofinish(bp, softc->device_stats, 0);
 1861                 break;
 1862         }
 1863         case SA_CCB_WAITING:
 1864         {
 1865                 /* Caller will release the CCB */
 1866                 wakeup(&done_ccb->ccb_h.cbfcnp);
 1867                 return;
 1868         }
 1869         }
 1870         xpt_release_ccb(done_ccb);
 1871 }
 1872 
 1873 /*
 1874  * Mount the tape (make sure it's ready for I/O).
 1875  */
 1876 static int
 1877 samount(struct cam_periph *periph, int oflags, struct cdev *dev)
 1878 {
 1879         struct  sa_softc *softc;
 1880         union   ccb *ccb;
 1881         int     error;
 1882 
 1883         /*
 1884          * oflags can be checked for 'kind' of open (read-only check) - later
 1885          * dev can be checked for a control-mode or compression open - later
 1886          */
 1887         UNUSED_PARAMETER(oflags);
 1888         UNUSED_PARAMETER(dev);
 1889 
 1890 
 1891         softc = (struct sa_softc *)periph->softc;
 1892 
 1893         /*
 1894          * This should determine if something has happend since the last
 1895          * open/mount that would invalidate the mount. We do *not* want
 1896          * to retry this command- we just want the status. But we only
 1897          * do this if we're mounted already- if we're not mounted,
 1898          * we don't care about the unit read state and can instead use
 1899          * this opportunity to attempt to reserve the tape unit.
 1900          */
 1901         
 1902         if (softc->flags & SA_FLAG_TAPE_MOUNTED) {
 1903                 ccb = cam_periph_getccb(periph, 1);
 1904                 scsi_test_unit_ready(&ccb->csio, 0, sadone,
 1905                     MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
 1906                 error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 1907                     softc->device_stats);
 1908                 QFRLS(ccb);
 1909                 if (error == ENXIO) {
 1910                         softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
 1911                         scsi_test_unit_ready(&ccb->csio, 0, sadone,
 1912                             MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
 1913                         error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 1914                             softc->device_stats);
 1915                         QFRLS(ccb);
 1916                 } else if (error) {
 1917                         /*
 1918                          * We don't need to freeze the tape because we
 1919                          * will now attempt to rewind/load it.
 1920                          */
 1921                         softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
 1922                         if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
 1923                                 xpt_print_path(periph->path);
 1924                                 printf("error %d on TUR in samount\n", error);
 1925                         }
 1926                 }
 1927         } else {
 1928                 error = sareservereleaseunit(periph, TRUE);
 1929                 if (error) {
 1930                         return (error);
 1931                 }
 1932                 ccb = cam_periph_getccb(periph, 1);
 1933                 scsi_test_unit_ready(&ccb->csio, 0, sadone,
 1934                     MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
 1935                 error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 1936                     softc->device_stats);
 1937                 QFRLS(ccb);
 1938         }
 1939 
 1940         if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) {
 1941                 struct scsi_read_block_limits_data *rblim = NULL;
 1942                 int comp_enabled, comp_supported;
 1943                 u_int8_t write_protect, guessing = 0;
 1944 
 1945                 /*
 1946                  * Clear out old state.
 1947                  */
 1948                 softc->flags &= ~(SA_FLAG_TAPE_WP|SA_FLAG_TAPE_WRITTEN|
 1949                                   SA_FLAG_ERR_PENDING|SA_FLAG_COMP_ENABLED|
 1950                                   SA_FLAG_COMP_SUPP|SA_FLAG_COMP_UNSUPP);
 1951                 softc->filemarks = 0;
 1952 
 1953                 /*
 1954                  * *Very* first off, make sure we're loaded to BOT.
 1955                  */
 1956                 scsi_load_unload(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
 1957                     FALSE, FALSE, 1, SSD_FULL_SIZE, REWIND_TIMEOUT);
 1958                 error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 1959                     softc->device_stats);
 1960                 QFRLS(ccb);
 1961 
 1962                 /*
 1963                  * In case this doesn't work, do a REWIND instead
 1964                  */
 1965                 if (error) {
 1966                         scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG,
 1967                             FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
 1968                         error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 1969                                 softc->device_stats);
 1970                         QFRLS(ccb);
 1971                 }
 1972                 if (error) {
 1973                         xpt_release_ccb(ccb);
 1974                         goto exit;
 1975                 }
 1976 
 1977                 /*
 1978                  * Do a dummy test read to force access to the
 1979                  * media so that the drive will really know what's
 1980                  * there. We actually don't really care what the
 1981                  * blocksize on tape is and don't expect to really
 1982                  * read a full record.
 1983                  */
 1984                 rblim = (struct  scsi_read_block_limits_data *)
 1985                     malloc(8192, M_SCSISA, M_WAITOK);
 1986                 if (rblim == NULL) {
 1987                         xpt_print_path(periph->path);
 1988                         printf("no memory for test read\n");
 1989                         xpt_release_ccb(ccb);
 1990                         error = ENOMEM;
 1991                         goto exit;
 1992                 }
 1993 
 1994                 if ((softc->quirks & SA_QUIRK_NODREAD) == 0) {
 1995                         scsi_sa_read_write(&ccb->csio, 0, sadone,
 1996                             MSG_SIMPLE_Q_TAG, 1, FALSE, 0, 8192,
 1997                             (void *) rblim, 8192, SSD_FULL_SIZE,
 1998                             IO_TIMEOUT);
 1999                         (void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 2000                             softc->device_stats);
 2001                         QFRLS(ccb);
 2002                         scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
 2003                             FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
 2004                         error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO,
 2005                             SF_NO_PRINT | SF_RETRY_UA,
 2006                             softc->device_stats);
 2007                         QFRLS(ccb);
 2008                         if (error) {
 2009                                 xpt_print_path(periph->path);
 2010                                 printf("unable to rewind after test read\n");
 2011                                 xpt_release_ccb(ccb);
 2012                                 goto exit;
 2013                         }
 2014                 }
 2015 
 2016                 /*
 2017                  * Next off, determine block limits.
 2018                  */
 2019                 scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
 2020                     rblim, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
 2021 
 2022                 error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO,
 2023                     SF_NO_PRINT | SF_RETRY_UA, softc->device_stats);
 2024 
 2025                 QFRLS(ccb);
 2026                 xpt_release_ccb(ccb);
 2027 
 2028                 if (error != 0) {
 2029                         /*
 2030                          * If it's less than SCSI-2, READ BLOCK LIMITS is not
 2031                          * a MANDATORY command. Anyway- it doesn't matter-
 2032                          * we can proceed anyway.
 2033                          */
 2034                         softc->blk_gran = 0;
 2035                         softc->max_blk = ~0;
 2036                         softc->min_blk = 0;
 2037                 } else {
 2038                         if (softc->scsi_rev >= SCSI_REV_SPC) {
 2039                                 softc->blk_gran = RBL_GRAN(rblim);
 2040                         } else {
 2041                                 softc->blk_gran = 0;
 2042                         }
 2043                         /*
 2044                          * We take max_blk == min_blk to mean a default to
 2045                          * fixed mode- but note that whatever we get out of
 2046                          * sagetparams below will actually determine whether
 2047                          * we are actually *in* fixed mode.
 2048                          */
 2049                         softc->max_blk = scsi_3btoul(rblim->maximum);
 2050                         softc->min_blk = scsi_2btoul(rblim->minimum);
 2051 
 2052 
 2053                 }
 2054                 /*
 2055                  * Next, perform a mode sense to determine
 2056                  * current density, blocksize, compression etc.
 2057                  */
 2058                 error = sagetparams(periph, SA_PARAM_ALL,
 2059                                     &softc->media_blksize,
 2060                                     &softc->media_density,
 2061                                     &softc->media_numblks,
 2062                                     &softc->buffer_mode, &write_protect,
 2063                                     &softc->speed, &comp_supported,
 2064                                     &comp_enabled, &softc->comp_algorithm,
 2065                                     NULL);
 2066 
 2067                 if (error != 0) {
 2068                         /*
 2069                          * We could work a little harder here. We could
 2070                          * adjust our attempts to get information. It
 2071                          * might be an ancient tape drive. If someone
 2072                          * nudges us, we'll do that.
 2073                          */
 2074                         goto exit;
 2075                 }
 2076 
 2077                 /*
 2078                  * If no quirk has determined that this is a device that is
 2079                  * preferred to be in fixed or variable mode, now is the time
 2080                  * to find out.
 2081                  */
 2082                 if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) {
 2083                         guessing = 1;
 2084                         /*
 2085                          * This could be expensive to find out. Luckily we
 2086                          * only need to do this once. If we start out in
 2087                          * 'default' mode, try and set ourselves to one
 2088                          * of the densities that would determine a wad
 2089                          * of other stuff. Go from highest to lowest.
 2090                          */
 2091                         if (softc->media_density == SCSI_DEFAULT_DENSITY) {
 2092                                 int i;
 2093                                 static u_int8_t ctry[] = {
 2094                                         SCSI_DENSITY_HALFINCH_PE,
 2095                                         SCSI_DENSITY_HALFINCH_6250C,
 2096                                         SCSI_DENSITY_HALFINCH_6250,
 2097                                         SCSI_DENSITY_HALFINCH_1600,
 2098                                         SCSI_DENSITY_HALFINCH_800,
 2099                                         SCSI_DENSITY_QIC_4GB,
 2100                                         SCSI_DENSITY_QIC_2GB,
 2101                                         SCSI_DENSITY_QIC_525_320,
 2102                                         SCSI_DENSITY_QIC_150,
 2103                                         SCSI_DENSITY_QIC_120,
 2104                                         SCSI_DENSITY_QIC_24,
 2105                                         SCSI_DENSITY_QIC_11_9TRK,
 2106                                         SCSI_DENSITY_QIC_11_4TRK,
 2107                                         SCSI_DENSITY_QIC_1320,
 2108                                         SCSI_DENSITY_QIC_3080,
 2109                                         0
 2110                                 };
 2111                                 for (i = 0; ctry[i]; i++) {
 2112                                         error = sasetparams(periph,
 2113                                             SA_PARAM_DENSITY, 0, ctry[i],
 2114                                             0, SF_NO_PRINT);
 2115                                         if (error == 0) {
 2116                                                 softc->media_density = ctry[i];
 2117                                                 break;
 2118                                         }
 2119                                 }
 2120                         }
 2121                         switch (softc->media_density) {
 2122                         case SCSI_DENSITY_QIC_11_4TRK:
 2123                         case SCSI_DENSITY_QIC_11_9TRK:
 2124                         case SCSI_DENSITY_QIC_24:
 2125                         case SCSI_DENSITY_QIC_120:
 2126                         case SCSI_DENSITY_QIC_150:
 2127                         case SCSI_DENSITY_QIC_525_320:
 2128                         case SCSI_DENSITY_QIC_1320:
 2129                         case SCSI_DENSITY_QIC_3080:
 2130                                 softc->quirks &= ~SA_QUIRK_2FM;
 2131                                 softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM;
 2132                                 softc->last_media_blksize = 512;
 2133                                 break;
 2134                         case SCSI_DENSITY_QIC_4GB:
 2135                         case SCSI_DENSITY_QIC_2GB:
 2136                                 softc->quirks &= ~SA_QUIRK_2FM;
 2137                                 softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM;
 2138                                 softc->last_media_blksize = 1024;
 2139                                 break;
 2140                         default:
 2141                                 softc->last_media_blksize =
 2142                                     softc->media_blksize;
 2143                                 softc->quirks |= SA_QUIRK_VARIABLE;
 2144                                 break;
 2145                         }
 2146                 }
 2147 
 2148                 /*
 2149                  * If no quirk has determined that this is a device that needs
 2150                  * to have 2 Filemarks at EOD, now is the time to find out.
 2151                  */
 2152 
 2153                 if ((softc->quirks & SA_QUIRK_2FM) == 0) {
 2154                         switch (softc->media_density) {
 2155                         case SCSI_DENSITY_HALFINCH_800:
 2156                         case SCSI_DENSITY_HALFINCH_1600:
 2157                         case SCSI_DENSITY_HALFINCH_6250:
 2158                         case SCSI_DENSITY_HALFINCH_6250C:
 2159                         case SCSI_DENSITY_HALFINCH_PE:
 2160                                 softc->quirks &= ~SA_QUIRK_1FM;
 2161                                 softc->quirks |= SA_QUIRK_2FM;
 2162                                 break;
 2163                         default:
 2164                                 break;
 2165                         }
 2166                 }
 2167 
 2168                 /*
 2169                  * Now validate that some info we got makes sense.
 2170                  */
 2171                 if ((softc->max_blk < softc->media_blksize) ||
 2172                     (softc->min_blk > softc->media_blksize &&
 2173                     softc->media_blksize)) {
 2174                         xpt_print_path(periph->path);
 2175                         printf("BLOCK LIMITS (%d..%d) could not match current "
 2176                             "block settings (%d)- adjusting\n", softc->min_blk,
 2177                             softc->max_blk, softc->media_blksize);
 2178                         softc->max_blk = softc->min_blk =
 2179                             softc->media_blksize;
 2180                 }
 2181 
 2182                 /*
 2183                  * Now put ourselves into the right frame of mind based
 2184                  * upon quirks...
 2185                  */
 2186 tryagain:
 2187                 /*
 2188                  * If we want to be in FIXED mode and our current blocksize
 2189                  * is not equal to our last blocksize (if nonzero), try and
 2190                  * set ourselves to this last blocksize (as the 'preferred'
 2191                  * block size).  The initial quirkmatch at registry sets the
 2192                  * initial 'last' blocksize. If, for whatever reason, this
 2193                  * 'last' blocksize is zero, set the blocksize to 512,
 2194                  * or min_blk if that's larger.
 2195                  */
 2196                 if ((softc->quirks & SA_QUIRK_FIXED) &&
 2197                     (softc->quirks & SA_QUIRK_NO_MODESEL) == 0 &&
 2198                     (softc->media_blksize != softc->last_media_blksize)) {
 2199                         softc->media_blksize = softc->last_media_blksize;
 2200                         if (softc->media_blksize == 0) {
 2201                                 softc->media_blksize = 512;
 2202                                 if (softc->media_blksize < softc->min_blk) {
 2203                                         softc->media_blksize = softc->min_blk;
 2204                                 }
 2205                         }
 2206                         error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
 2207                             softc->media_blksize, 0, 0, SF_NO_PRINT);
 2208                         if (error) {
 2209                                 xpt_print_path(periph->path);
 2210                                 printf("unable to set fixed blocksize to %d\n",
 2211                                      softc->media_blksize);
 2212                                 goto exit;
 2213                         }
 2214                 }
 2215 
 2216                 if ((softc->quirks & SA_QUIRK_VARIABLE) && 
 2217                     (softc->media_blksize != 0)) {
 2218                         softc->last_media_blksize = softc->media_blksize;
 2219                         softc->media_blksize = 0;
 2220                         error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
 2221                             0, 0, 0, SF_NO_PRINT);
 2222                         if (error) {
 2223                                 /*
 2224                                  * If this fails and we were guessing, just
 2225                                  * assume that we got it wrong and go try
 2226                                  * fixed block mode. Don't even check against
 2227                                  * density code at this point.
 2228                                  */
 2229                                 if (guessing) {
 2230                                         softc->quirks &= ~SA_QUIRK_VARIABLE;
 2231                                         softc->quirks |= SA_QUIRK_FIXED;
 2232                                         if (softc->last_media_blksize == 0)
 2233                                                 softc->last_media_blksize = 512;
 2234                                         goto tryagain;
 2235                                 }
 2236                                 xpt_print_path(periph->path);
 2237                                 printf("unable to set variable blocksize\n");
 2238                                 goto exit;
 2239                         }
 2240                 }
 2241 
 2242                 /*
 2243                  * Now that we have the current block size,
 2244                  * set up some parameters for sastart's usage.
 2245                  */
 2246                 if (softc->media_blksize) {
 2247                         softc->flags |= SA_FLAG_FIXED;
 2248                         if (powerof2(softc->media_blksize)) {
 2249                                 softc->blk_shift =
 2250                                     ffs(softc->media_blksize) - 1;
 2251                                 softc->blk_mask = softc->media_blksize - 1;
 2252                         } else {
 2253                                 softc->blk_mask = ~0;
 2254                                 softc->blk_shift = 0;
 2255                         }
 2256                 } else {
 2257                         /*
 2258                          * The SCSI-3 spec allows 0 to mean "unspecified".
 2259                          * The SCSI-1 spec allows 0 to mean 'infinite'.
 2260                          *
 2261                          * Either works here.
 2262                          */
 2263                         if (softc->max_blk == 0) {
 2264                                 softc->max_blk = ~0;
 2265                         }
 2266                         softc->blk_shift = 0;
 2267                         if (softc->blk_gran != 0) {
 2268                                 softc->blk_mask = softc->blk_gran - 1;
 2269                         } else {
 2270                                 softc->blk_mask = 0;
 2271                         }
 2272                 }
 2273 
 2274                 if (write_protect) 
 2275                         softc->flags |= SA_FLAG_TAPE_WP;
 2276 
 2277                 if (comp_supported) {
 2278                         if (softc->saved_comp_algorithm == 0)
 2279                                 softc->saved_comp_algorithm =
 2280                                     softc->comp_algorithm;
 2281                         softc->flags |= SA_FLAG_COMP_SUPP;
 2282                         if (comp_enabled)
 2283                                 softc->flags |= SA_FLAG_COMP_ENABLED;
 2284                 } else
 2285                         softc->flags |= SA_FLAG_COMP_UNSUPP;
 2286 
 2287                 if ((softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) &&
 2288                     (softc->quirks & SA_QUIRK_NO_MODESEL) == 0) {
 2289                         error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0,
 2290                             0, 0, SF_NO_PRINT);
 2291                         if (error == 0) {
 2292                                 softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF;
 2293                         } else {
 2294                                 xpt_print_path(periph->path);
 2295                                 printf("unable to set buffered mode\n");
 2296                         }
 2297                         error = 0;      /* not an error */
 2298                 }
 2299 
 2300 
 2301                 if (error == 0) {
 2302                         softc->flags |= SA_FLAG_TAPE_MOUNTED;
 2303                 }
 2304 exit:
 2305                 if (rblim != NULL)
 2306                         free(rblim, M_SCSISA);
 2307 
 2308                 if (error != 0) {
 2309                         softc->dsreg = MTIO_DSREG_NIL;
 2310                 } else {
 2311                         softc->fileno = softc->blkno = 0;
 2312                         softc->dsreg = MTIO_DSREG_REST;
 2313                 }
 2314 #ifdef  SA_1FM_AT_EOD
 2315                 if ((softc->quirks & SA_QUIRK_2FM) == 0)
 2316                         softc->quirks |= SA_QUIRK_1FM;
 2317 #else
 2318                 if ((softc->quirks & SA_QUIRK_1FM) == 0)
 2319                         softc->quirks |= SA_QUIRK_2FM;
 2320 #endif
 2321         } else
 2322                 xpt_release_ccb(ccb);
 2323 
 2324         /*
 2325          * If we return an error, we're not mounted any more,
 2326          * so release any device reservation.
 2327          */
 2328         if (error != 0) {
 2329                 (void) sareservereleaseunit(periph, FALSE);
 2330         } else {
 2331                 /*
 2332                  * Clear I/O residual.
 2333                  */
 2334                 softc->last_io_resid = 0;
 2335                 softc->last_ctl_resid = 0;
 2336         }
 2337         return (error);
 2338 }
 2339 
 2340 /*
 2341  * How many filemarks do we need to write if we were to terminate the
 2342  * tape session right now? Note that this can be a negative number
 2343  */
 2344 
 2345 static int
 2346 samarkswanted(struct cam_periph *periph)
 2347 {
 2348         int     markswanted;
 2349         struct  sa_softc *softc;
 2350 
 2351         softc = (struct sa_softc *)periph->softc;
 2352         markswanted = 0;
 2353         if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) {
 2354                 markswanted++;
 2355                 if (softc->quirks & SA_QUIRK_2FM)
 2356                         markswanted++;
 2357         }
 2358         markswanted -= softc->filemarks;
 2359         return (markswanted);
 2360 }
 2361 
 2362 static int
 2363 sacheckeod(struct cam_periph *periph)
 2364 {
 2365         int     error;
 2366         int     markswanted;
 2367 
 2368         markswanted = samarkswanted(periph);
 2369 
 2370         if (markswanted > 0) {
 2371                 error = sawritefilemarks(periph, markswanted, FALSE);
 2372         } else {
 2373                 error = 0;
 2374         }
 2375         return (error);
 2376 }
 2377 
 2378 static int
 2379 saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
 2380 {
 2381         static const char *toobig =
 2382             "%d-byte tape record bigger than supplied buffer\n";
 2383         struct  cam_periph *periph;
 2384         struct  sa_softc *softc;
 2385         struct  ccb_scsiio *csio;
 2386         struct  scsi_sense_data *sense;
 2387         u_int32_t resid = 0;
 2388         int32_t info = 0;
 2389         cam_status status;
 2390         int error_code, sense_key, asc, ascq, error, aqvalid;
 2391 
 2392         periph = xpt_path_periph(ccb->ccb_h.path);
 2393         softc = (struct sa_softc *)periph->softc;
 2394         csio = &ccb->csio;
 2395         sense = &csio->sense_data;
 2396         scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
 2397         aqvalid = sense->extra_len >= 6;
 2398         error = 0;
 2399 
 2400         status = csio->ccb_h.status & CAM_STATUS_MASK;
 2401 
 2402         /*
 2403          * Calculate/latch up, any residuals... We do this in a funny 2-step
 2404          * so we can print stuff here if we have CAM_DEBUG enabled for this
 2405          * unit.
 2406          */
 2407         if (status == CAM_SCSI_STATUS_ERROR) {
 2408                 if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
 2409                         info = (int32_t) scsi_4btoul(sense->info);
 2410                         resid = info;
 2411                         if ((softc->flags & SA_FLAG_FIXED) != 0)
 2412                                 resid *= softc->media_blksize;
 2413                 } else {
 2414                         resid = csio->dxfer_len;
 2415                         info = resid;
 2416                         if ((softc->flags & SA_FLAG_FIXED) != 0) {
 2417                                 if (softc->media_blksize)
 2418                                         info /= softc->media_blksize;
 2419                         }
 2420                 }
 2421                 if (CCB_Type(csio) == SA_CCB_BUFFER_IO) {
 2422                         bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense,
 2423                             sizeof (struct scsi_sense_data));
 2424                         bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb,
 2425                             (int) csio->cdb_len);
 2426                         softc->last_io_resid = resid;
 2427                         softc->last_resid_was_io = 1;
 2428                 } else {
 2429                         bcopy((caddr_t) sense, (caddr_t) &softc->last_ctl_sense,
 2430                             sizeof (struct scsi_sense_data));
 2431                         bcopy(csio->cdb_io.cdb_bytes, softc->last_ctl_cdb,
 2432                             (int) csio->cdb_len);
 2433                         softc->last_ctl_resid = resid;
 2434                         softc->last_resid_was_io = 0;
 2435                 }
 2436                 CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x "
 2437                     "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %d "
 2438                     "dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff,
 2439                     sense_key, asc, ascq, status,
 2440                     sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len));
 2441         } else {
 2442                 CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
 2443                     ("Cam Status 0x%x\n", status));
 2444         }
 2445 
 2446         switch (status) {
 2447         case CAM_REQ_CMP:
 2448                 return (0);
 2449         case CAM_SCSI_STATUS_ERROR:
 2450                 /*
 2451                  * If a read/write command, we handle it here.
 2452                  */
 2453                 if (CCB_Type(csio) != SA_CCB_WAITING) {
 2454                         break;
 2455                 }
 2456                 /*
 2457                  * If this was just EOM/EOP, Filemark, Setmark or ILI detected
 2458                  * on a non read/write command, we assume it's not an error
 2459                  * and propagate the residule and return.
 2460                  */
 2461                 if ((aqvalid && asc == 0 && ascq > 0 && ascq <= 5) ||
 2462                     (aqvalid == 0 && sense_key == SSD_KEY_NO_SENSE)) {
 2463                         csio->resid = resid;
 2464                         QFRLS(ccb);
 2465                         return (0);
 2466                 }
 2467                 /*
 2468                  * Otherwise, we let the common code handle this.
 2469                  */
 2470                 return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
 2471 
 2472         /*
 2473          * XXX: To Be Fixed
 2474          * We cannot depend upon CAM honoring retry counts for these.
 2475          */
 2476         case CAM_SCSI_BUS_RESET:
 2477         case CAM_BDR_SENT:
 2478                 if (ccb->ccb_h.retry_count <= 0) {
 2479                         return (EIO);
 2480                 }
 2481                 /* FALLTHROUGH */
 2482         default:
 2483                 return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
 2484         }
 2485 
 2486         /*
 2487          * Handle filemark, end of tape, mismatched record sizes....
 2488          * From this point out, we're only handling read/write cases.
 2489          * Handle writes && reads differently.
 2490          */
 2491 
 2492         if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) {
 2493                 if (sense_key == SSD_KEY_VOLUME_OVERFLOW) {
 2494                         csio->resid = resid;
 2495                         error = ENOSPC;
 2496                 } else if (sense->flags & SSD_EOM) {
 2497                         softc->flags |= SA_FLAG_EOM_PENDING;
 2498                         /*
 2499                          * Grotesque as it seems, the few times
 2500                          * I've actually seen a non-zero resid,
 2501                          * the tape drive actually lied and had
 2502                          * written all the data!.
 2503                          */
 2504                         csio->resid = 0;
 2505                 }
 2506         } else {
 2507                 csio->resid = resid;
 2508                 if (sense_key == SSD_KEY_BLANK_CHECK) {
 2509                         if (softc->quirks & SA_QUIRK_1FM) {
 2510                                 error = 0;
 2511                                 softc->flags |= SA_FLAG_EOM_PENDING;
 2512                         } else {
 2513                                 error = EIO;
 2514                         }
 2515                 } else if (sense->flags & SSD_FILEMARK) {
 2516                         if (softc->flags & SA_FLAG_FIXED) {
 2517                                 error = -1;
 2518                                 softc->flags |= SA_FLAG_EOF_PENDING;
 2519                         }
 2520                         /*
 2521                          * Unconditionally, if we detected a filemark on a read,
 2522                          * mark that we've run moved a file ahead.
 2523                          */
 2524                         if (softc->fileno != (daddr_t) -1) {
 2525                                 softc->fileno++;
 2526                                 softc->blkno = 0;
 2527                                 csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED;
 2528                         }
 2529                 }
 2530         }
 2531 
 2532         /*
 2533          * Incorrect Length usually applies to read, but can apply to writes.
 2534          */
 2535         if (error == 0 && (sense->flags & SSD_ILI)) {
 2536                 if (info < 0) {
 2537                         xpt_print_path(csio->ccb_h.path);
 2538                         printf(toobig, csio->dxfer_len - info);
 2539                         csio->resid = csio->dxfer_len;
 2540                         error = EIO;
 2541                 } else {
 2542                         csio->resid = resid;
 2543                         if (softc->flags & SA_FLAG_FIXED) {
 2544                                 softc->flags |= SA_FLAG_EIO_PENDING;
 2545                         }
 2546                         /*
 2547                          * Bump the block number if we hadn't seen a filemark.
 2548                          * Do this independent of errors (we've moved anyway).
 2549                          */
 2550                         if ((sense->flags & SSD_FILEMARK) == 0) {
 2551                                 if (softc->blkno != (daddr_t) -1) {
 2552                                         softc->blkno++;
 2553                                         csio->ccb_h.ccb_pflags |=
 2554                                            SA_POSITION_UPDATED;
 2555                                 }
 2556                         }
 2557                 }
 2558         }
 2559 
 2560         if (error <= 0) {
 2561                 /*
 2562                  * Unfreeze the queue if frozen as we're not returning anything
 2563                  * to our waiters that would indicate an I/O error has occurred
 2564                  * (yet).
 2565                  */
 2566                 QFRLS(ccb);
 2567                 error = 0;
 2568         }
 2569         return (error);
 2570 }
 2571 
 2572 static int
 2573 sagetparams(struct cam_periph *periph, sa_params params_to_get,
 2574             u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks,
 2575             int *buff_mode, u_int8_t *write_protect, u_int8_t *speed,
 2576             int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm,
 2577             sa_comp_t *tcs)
 2578 {
 2579         union ccb *ccb;
 2580         void *mode_buffer;
 2581         struct scsi_mode_header_6 *mode_hdr;
 2582         struct scsi_mode_blk_desc *mode_blk;
 2583         int mode_buffer_len;
 2584         struct sa_softc *softc;
 2585         u_int8_t cpage;
 2586         int error;
 2587         cam_status status;
 2588 
 2589         softc = (struct sa_softc *)periph->softc;
 2590         ccb = cam_periph_getccb(periph, 1);
 2591         if (softc->quirks & SA_QUIRK_NO_CPAGE)
 2592                 cpage = SA_DEVICE_CONFIGURATION_PAGE;
 2593         else
 2594                 cpage = SA_DATA_COMPRESSION_PAGE;
 2595 
 2596 retry:
 2597         mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk);
 2598 
 2599         if (params_to_get & SA_PARAM_COMPRESSION) {
 2600                 if (softc->quirks & SA_QUIRK_NOCOMP) {
 2601                         *comp_supported = FALSE;
 2602                         params_to_get &= ~SA_PARAM_COMPRESSION;
 2603                 } else
 2604                         mode_buffer_len += sizeof (sa_comp_t);
 2605         }
 2606 
 2607         mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_WAITOK | M_ZERO);
 2608         mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
 2609         mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
 2610 
 2611         /* it is safe to retry this */
 2612         scsi_mode_sense(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
 2613             SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ?
 2614             cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len,
 2615             SSD_FULL_SIZE, SCSIOP_TIMEOUT);
 2616 
 2617         error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 2618             softc->device_stats);
 2619         QFRLS(ccb);
 2620 
 2621         status = ccb->ccb_h.status & CAM_STATUS_MASK;
 2622 
 2623         if (error == EINVAL && (params_to_get & SA_PARAM_COMPRESSION) != 0) {
 2624                 /*
 2625                  * Hmm. Let's see if we can try another page...
 2626                  * If we've already done that, give up on compression
 2627                  * for this device and remember this for the future
 2628                  * and attempt the request without asking for compression
 2629                  * info.
 2630                  */
 2631                 if (cpage == SA_DATA_COMPRESSION_PAGE) {
 2632                         cpage = SA_DEVICE_CONFIGURATION_PAGE;
 2633                         goto retry;
 2634                 }
 2635                 softc->quirks |= SA_QUIRK_NOCOMP;
 2636                 free(mode_buffer, M_SCSISA);
 2637                 goto retry;
 2638         } else if (status == CAM_SCSI_STATUS_ERROR) {
 2639                 /* Tell the user about the fatal error. */
 2640                 scsi_sense_print(&ccb->csio);
 2641                 goto sagetparamsexit;
 2642         }
 2643 
 2644         /*
 2645          * If the user only wants the compression information, and
 2646          * the device doesn't send back the block descriptor, it's
 2647          * no big deal.  If the user wants more than just
 2648          * compression, though, and the device doesn't pass back the
 2649          * block descriptor, we need to send another mode sense to
 2650          * get the block descriptor.
 2651          */
 2652         if ((mode_hdr->blk_desc_len == 0) &&
 2653             (params_to_get & SA_PARAM_COMPRESSION) &&
 2654             (params_to_get & ~(SA_PARAM_COMPRESSION))) {
 2655 
 2656                 /*
 2657                  * Decrease the mode buffer length by the size of
 2658                  * the compression page, to make sure the data
 2659                  * there doesn't get overwritten.
 2660                  */
 2661                 mode_buffer_len -= sizeof (sa_comp_t);
 2662 
 2663                 /*
 2664                  * Now move the compression page that we presumably
 2665                  * got back down the memory chunk a little bit so
 2666                  * it doesn't get spammed.
 2667                  */
 2668                 bcopy(&mode_hdr[0], &mode_hdr[1], sizeof (sa_comp_t));
 2669                 bzero(&mode_hdr[0], sizeof (mode_hdr[0]));
 2670 
 2671                 /*
 2672                  * Now, we issue another mode sense and just ask
 2673                  * for the block descriptor, etc.
 2674                  */
 2675 
 2676                 scsi_mode_sense(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
 2677                     SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE,
 2678                     mode_buffer, mode_buffer_len, SSD_FULL_SIZE,
 2679                     SCSIOP_TIMEOUT);
 2680 
 2681                 error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
 2682                     softc->device_stats);
 2683                 QFRLS(ccb);
 2684 
 2685                 if (error != 0)
 2686                         goto sagetparamsexit;
 2687         }
 2688 
 2689         if (params_to_get & SA_PARAM_BLOCKSIZE)
 2690                 *blocksize = scsi_3btoul(mode_blk->blklen);
 2691 
 2692         if (params_to_get & SA_PARAM_NUMBLOCKS)
 2693                 *numblocks = scsi_3btoul(mode_blk->nblocks);
 2694 
 2695         if (params_to_get & SA_PARAM_BUFF_MODE)
 2696                 *buff_mode = mode_hdr->dev_spec & SMH_SA_BUF_MODE_MASK;
 2697 
 2698         if (params_to_get & SA_PARAM_DENSITY)
 2699                 *density = mode_blk->density;
 2700 
 2701         if (params_to_get & SA_PARAM_WP)
 2702                 *write_protect = (mode_hdr->dev_spec & SMH_SA_WP)? TRUE : FALSE;
 2703 
 2704         if (params_to_get & SA_PARAM_SPEED)
 2705                 *speed = mode_hdr->dev_spec & SMH_SA_SPEED_MASK;
 2706 
 2707         if (params_to_get & SA_PARAM_COMPRESSION) {
 2708                 sa_comp_t *ntcs = (sa_comp_t *) &mode_blk[1];
 2709                 if (cpage == SA_DATA_COMPRESSION_PAGE) {
 2710                         struct scsi_data_compression_page *cp = &ntcs->dcomp;
 2711                         *comp_supported =
 2712                             (cp->dce_and_dcc & SA_DCP_DCC)? TRUE : FALSE;
 2713                         *comp_enabled =
 2714                             (cp->dce_and_dcc & SA_DCP_DCE)? TRUE : FALSE;
 2715                         *comp_algorithm = scsi_4btoul(cp->comp_algorithm);
 2716                 } else {
 2717                         struct scsi_dev_conf_page *cp = &ntcs->dconf;
 2718                         /*
 2719                          * We don't really know whether this device supports
 2720                          * Data Compression if the the algorithm field is
 2721                          * zero. Just say we do.
 2722                          */
 2723                         *comp_supported = TRUE;
 2724                         *comp_enabled =
 2725                             (cp->sel_comp_alg != SA_COMP_NONE)? TRUE : FALSE;
 2726                         *comp_algorithm = cp->sel_comp_alg;
 2727                 }
 2728                 if (tcs != NULL)
 2729                         bcopy(ntcs, tcs, sizeof (sa_comp_t));
 2730         }
 2731 
 2732         if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
 2733                 int idx;
 2734                 char *xyz = mode_buffer;
 2735                 xpt_print_path(periph->path);
 2736                 printf("Mode Sense Data=");
 2737                 for (idx = 0; idx < mode_buffer_len; idx++)
 2738                         printf(" 0x%02x", xyz[idx] & 0xff);
 2739                 printf("\n");
 2740         }
 2741 
 2742 sagetparamsexit:
 2743 
 2744         xpt_release_ccb(ccb);
 2745         free(mode_buffer, M_SCSISA);
 2746         return (error);
 2747 }
 2748 
 2749 /*
 2750  * The purpose of this function is to set one of four different parameters
 2751  * for a tape drive:
 2752  *      - blocksize
 2753  *      - density
 2754  *      - compression / compression algorithm
 2755  *      - buffering mode
 2756  *
 2757  * The assumption is that this will be called from saioctl(), and therefore
 2758  * from a process context.  Thus the waiting malloc calls below.  If that
 2759  * assumption ever changes, the malloc calls should be changed to be
 2760  * NOWAIT mallocs.
 2761  *
 2762  * Any or all of the four parameters may be set when this function is
 2763  * called.  It should handle setting more than one parameter at once.
 2764  */
 2765 static int
 2766 sasetparams(struct cam_periph *periph, sa_params params_to_set,
 2767             u_int32_t blocksize, u_int8_t density, u_int32_t calg,
 2768             u_int32_t sense_flags)
 2769 {
 2770         struct sa_softc *softc;
 2771         u_int32_t current_blocksize;
 2772         u_int32_t current_calg;
 2773         u_int8_t current_density;
 2774         u_int8_t current_speed;
 2775         int comp_enabled, comp_supported;
 2776         void *mode_buffer;
 2777         int mode_buffer_len;
 2778         struct scsi_mode_header_6 *mode_hdr;
 2779         struct scsi_mode_blk_desc *mode_blk;
 2780         sa_comp_t *ccomp, *cpage;
 2781         int buff_mode;
 2782         union ccb *ccb = NULL;
 2783         int error;
 2784 
 2785         softc = (struct sa_softc *)periph->softc;
 2786 
 2787         ccomp = malloc(sizeof (sa_comp_t), M_SCSISA, M_WAITOK);
 2788 
 2789         /*
 2790          * Since it doesn't make sense to set the number of blocks, or
 2791          * write protection, we won't try to get the current value.  We
 2792          * always want to get the blocksize, so we can set it back to the
 2793          * proper value.
 2794          */
 2795         error = sagetparams(periph,
 2796             params_to_set | SA_PARAM_BLOCKSIZE | SA_PARAM_SPEED,
 2797             &current_blocksize, &current_density, NULL, &buff_mode, NULL,
 2798             &current_speed, &comp_supported, &comp_enabled,
 2799             &current_calg, ccomp);
 2800 
 2801         if (error != 0) {
 2802                 free(ccomp, M_SCSISA);
 2803                 return (error);
 2804         }
 2805 
 2806         mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk);
 2807         if (params_to_set & SA_PARAM_COMPRESSION)
 2808                 mode_buffer_len += sizeof (sa_comp_t);
 2809 
 2810         mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_WAITOK | M_ZERO);
 2811 
 2812         mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
 2813         mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
 2814 
 2815         ccb = cam_periph_getccb(periph, 1);
 2816 
 2817 retry:
 2818 
 2819         if (params_to_set & SA_PARAM_COMPRESSION) {
 2820                 if (mode_blk) {
 2821                         cpage = (sa_comp_t *)&mode_blk[1];
 2822                 } else {
 2823                         cpage = (sa_comp_t *)&mode_hdr[1];
 2824                 }
 2825                 bcopy(ccomp, cpage, sizeof (sa_comp_t));
 2826                 cpage->hdr.pagecode &= ~0x80;
 2827         } else
 2828                 cpage = NULL;
 2829 
 2830         /*
 2831          * If the caller wants us to set the blocksize, use the one they
 2832          * pass in.  Otherwise, use the blocksize we got back from the
 2833          * mode select above.
 2834          */
 2835         if (mode_blk) {
 2836                 if (params_to_set & SA_PARAM_BLOCKSIZE)
 2837                         scsi_ulto3b(blocksize, mode_blk->blklen);
 2838                 else
 2839                         scsi_ulto3b(current_blocksize, mode_blk->blklen);
 2840 
 2841                 /*
 2842                  * Set density if requested, else preserve old density.
 2843                  * SCSI_SAME_DENSITY only applies to SCSI-2 or better
 2844                  * devices, else density we've latched up in our softc.
 2845                  */
 2846                 if (params_to_set & SA_PARAM_DENSITY) {
 2847                         mode_blk->density = density;
 2848                 } else if (softc->scsi_rev > SCSI_REV_CCS) {
 2849                         mode_blk->density = SCSI_SAME_DENSITY;
 2850                 } else {
 2851                         mode_blk->density = softc->media_density;
 2852                 }
 2853         }
 2854 
 2855         /*
 2856          * For mode selects, these two fields must be zero.
 2857          */
 2858         mode_hdr->data_length = 0;
 2859         mode_hdr->medium_type = 0;
 2860 
 2861         /* set the speed to the current value */
 2862         mode_hdr->dev_spec = current_speed;
 2863 
 2864         /* if set, set single-initiator buffering mode */
 2865         if (softc->buffer_mode == SMH_SA_BUF_MODE_SIBUF) {
 2866                 mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF;
 2867         }
 2868 
 2869         if (mode_blk)
 2870                 mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc);
 2871         else
 2872                 mode_hdr->blk_desc_len = 0;
 2873 
 2874         /*
 2875          * First, if the user wants us to set the compression algorithm or
 2876          * just turn compression on, check to make sure that this drive
 2877          * supports compression.
 2878          */
 2879         if (params_to_set & SA_PARAM_COMPRESSION) {
 2880                 /*
 2881                  * If the compression algorithm is 0, disable compression.
 2882                  * If the compression algorithm is non-zero, enable
 2883                  * compression and set the compression type to the
 2884                  * specified compression algorithm, unless the algorithm is
 2885                  * MT_COMP_ENABLE.  In that case, we look at the
 2886                  * compression algorithm that is currently set and if it is
 2887                  * non-zero, we leave it as-is.  If it is zero, and we have
 2888                  * saved a compression algorithm from a time when
 2889                  * compression was enabled before, set the compression to
 2890                  * the saved value.
 2891                  */
 2892                 switch (ccomp->hdr.pagecode & ~0x80) {
 2893                 case SA_DEVICE_CONFIGURATION_PAGE:
 2894                 {
 2895                         struct scsi_dev_conf_page *dcp = &cpage->dconf;
 2896                         if (calg == 0) {
 2897                                 dcp->sel_comp_alg = SA_COMP_NONE;
 2898                                 break;
 2899                         }
 2900                         if (calg != MT_COMP_ENABLE) {
 2901                                 dcp->sel_comp_alg = calg;
 2902                         } else if (dcp->sel_comp_alg == SA_COMP_NONE &&
 2903                             softc->saved_comp_algorithm != 0) {
 2904                                 dcp->sel_comp_alg = softc->saved_comp_algorithm;
 2905                         }
 2906                         break;
 2907                 }
 2908                 case SA_DATA_COMPRESSION_PAGE:
 2909                 if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) {
 2910                         struct scsi_data_compression_page *dcp = &cpage->dcomp;
 2911                         if (calg == 0) {
 2912                                 /*
 2913                                  * Disable compression, but leave the
 2914                                  * decompression and the capability bit
 2915                                  * alone.
 2916                                  */
 2917                                 dcp->dce_and_dcc = SA_DCP_DCC;
 2918                                 dcp->dde_and_red |= SA_DCP_DDE;
 2919                                 break;
 2920                         }
 2921                         /* enable compression && decompression */
 2922                         dcp->dce_and_dcc = SA_DCP_DCE | SA_DCP_DCC;
 2923                         dcp->dde_and_red |= SA_DCP_DDE;
 2924                         /*
 2925                          * If there, use compression algorithm from caller.
 2926                          * Otherwise, if there's a saved compression algorithm
 2927                          * and there is no current algorithm, use the saved
 2928                          * algorithm. Else parrot back what we got and hope
 2929                          * for the best.
 2930                          */
 2931                         if (calg != MT_COMP_ENABLE) {
 2932                                 scsi_ulto4b(calg, dcp->comp_algorithm);
 2933                                 scsi_ulto4b(calg, dcp->decomp_algorithm);
 2934                         } else if (scsi_4btoul(dcp->comp_algorithm) == 0 &&
 2935                             softc->saved_comp_algorithm != 0) {
 2936                                 scsi_ulto4b(softc->saved_comp_algorithm,
 2937                                     dcp->comp_algorithm);
 2938                                 scsi_ulto4b(softc->saved_comp_algorithm,
 2939                                     dcp->decomp_algorithm);
 2940                         }
 2941                         break;
 2942                 }
 2943                 /*
 2944                  * Compression does not appear to be supported-
 2945                  * at least via the DATA COMPRESSION page. It
 2946                  * would be too much to ask us to believe that
 2947                  * the page itself is supported, but incorrectly
 2948                  * reports an ability to manipulate data compression,
 2949                  * so we'll assume that this device doesn't support
 2950                  * compression. We can just fall through for that.
 2951                  */
 2952                 /* FALLTHROUGH */
 2953                 default:
 2954                         /*
 2955                          * The drive doesn't seem to support compression,
 2956                          * so turn off the set compression bit.
 2957                          */
 2958                         params_to_set &= ~SA_PARAM_COMPRESSION;
 2959                         xpt_print_path(periph->path);
 2960                         printf("device does not seem to support compression\n");
 2961 
 2962                         /*
 2963                          * If that was the only thing the user wanted us to set,
 2964                          * clean up allocated resources and return with
 2965                          * 'operation not supported'.
 2966                          */
 2967                         if (params_to_set == SA_PARAM_NONE) {
 2968                                 free(mode_buffer, M_SCSISA);
 2969                                 xpt_release_ccb(ccb);
 2970                                 return (ENODEV);
 2971                         }
 2972                 
 2973                         /*
 2974                          * That wasn't the only thing the user wanted us to set.
 2975                          * So, decrease the stated mode buffer length by the
 2976                          * size of the compression mode page.
 2977                          */
 2978                         mode_buffer_len -= sizeof(sa_comp_t);
 2979                 }
 2980         }
 2981 
 2982         /* It is safe to retry this operation */
 2983         scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
 2984             (params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE,
 2985             FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
 2986 
 2987         error = cam_periph_runccb(ccb, saerror, 0,
 2988             sense_flags, softc->device_stats);
 2989         QFRLS(ccb);
 2990 
 2991         if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
 2992                 int idx;
 2993                 char *xyz = mode_buffer;
 2994                 xpt_print_path(periph->path);
 2995                 printf("Err%d, Mode Select Data=", error);
 2996                 for (idx = 0; idx < mode_buffer_len; idx++)
 2997                         printf(" 0x%02x", xyz[idx] & 0xff);
 2998                 printf("\n");
 2999         }
 3000 
 3001 
 3002         if (error) {
 3003                 /*
 3004                  * If we can, try without setting density/blocksize.
 3005                  */
 3006                 if (mode_blk) {
 3007                         if ((params_to_set &
 3008                             (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) {
 3009                                 mode_blk = NULL;
 3010                                 goto retry;
 3011                         }
 3012                 } else {
 3013                         mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
 3014                         cpage = (sa_comp_t *)&mode_blk[1];
 3015                 }
 3016 
 3017                 /*
 3018                  * If we were setting the blocksize, and that failed, we
 3019                  * want to set it to its original value.  If we weren't
 3020                  * setting the blocksize, we don't want to change it.
 3021                  */
 3022                 scsi_ulto3b(current_blocksize, mode_blk->blklen);
 3023 
 3024                 /*
 3025                  * Set density if requested, else preserve old density.
 3026                  * SCSI_SAME_DENSITY only applies to SCSI-2 or better
 3027                  * devices, else density we've latched up in our softc.
 3028                  */
 3029                 if (params_to_set & SA_PARAM_DENSITY) {
 3030                         mode_blk->density = current_density;
 3031                 } else if (softc->scsi_rev > SCSI_REV_CCS) {
 3032                         mode_blk->density = SCSI_SAME_DENSITY;
 3033                 } else {
 3034                         mode_blk->density = softc->media_density;
 3035                 }
 3036 
 3037                 if (params_to_set & SA_PARAM_COMPRESSION)
 3038                         bcopy(ccomp, cpage, sizeof (sa_comp_t));
 3039 
 3040                 /*
 3041                  * The retry count is the only CCB field that might have been
 3042                  * changed that we care about, so reset it back to 1.
 3043                  */
 3044                 ccb->ccb_h.retry_count = 1;
 3045                 cam_periph_runccb(ccb, saerror, 0, sense_flags,
 3046                     softc->device_stats);
 3047                 QFRLS(ccb);
 3048         }
 3049 
 3050         xpt_release_ccb(ccb);
 3051 
 3052         if (ccomp != NULL)
 3053                 free(ccomp, M_SCSISA);
 3054 
 3055         if (params_to_set & SA_PARAM_COMPRESSION) {
 3056                 if (error) {
 3057                         softc->flags &= ~SA_FLAG_COMP_ENABLED;
 3058                         /*
 3059                          * Even if we get an error setting compression,
 3060                          * do not say that we don't support it. We could
 3061                          * have been wrong, or it may be media specific.
 3062                          *      softc->flags &= ~SA_FLAG_COMP_SUPP;
 3063                          */
 3064                         softc->saved_comp_algorithm = softc->comp_algorithm;
 3065                         softc->comp_algorithm = 0;
 3066                 } else {
 3067                         softc->flags |= SA_FLAG_COMP_ENABLED;
 3068                         softc->comp_algorithm = calg;
 3069                 }
 3070         }
 3071 
 3072         free(mode_buffer, M_SCSISA);
 3073         return (error);
 3074 }
 3075 
 3076 static void
 3077 saprevent(struct cam_periph *periph, int action)
 3078 {
 3079         struct  sa_softc *softc;
 3080         union   ccb *ccb;               
 3081         int     error, sf;
 3082                 
 3083         softc = (struct sa_softc *)periph->softc;
 3084 
 3085         if ((action == PR_ALLOW) && (softc->flags & SA_FLAG_TAPE_LOCKED) == 0)
 3086                 return;
 3087         if ((action == PR_PREVENT) && (softc->flags & SA_FLAG_TAPE_LOCKED) != 0)
 3088                 return;
 3089 
 3090         /*
 3091          * We can be quiet about illegal requests.
 3092          */
 3093         if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
 3094                 sf = 0;
 3095         } else
 3096                 sf = SF_QUIET_IR;
 3097 
 3098         ccb = cam_periph_getccb(periph, 1);
 3099 
 3100         /* It is safe to retry this operation */
 3101         scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action,
 3102             SSD_FULL_SIZE, SCSIOP_TIMEOUT);
 3103 
 3104         error = cam_periph_runccb(ccb, saerror, 0, sf, softc->device_stats);
 3105         QFRLS(ccb);
 3106         if (error == 0) {
 3107                 if (action == PR_ALLOW)
 3108                         softc->flags &= ~SA_FLAG_TAPE_LOCKED;
 3109                 else
 3110                         softc->flags |= SA_FLAG_TAPE_LOCKED;
 3111         }
 3112 
 3113         xpt_release_ccb(ccb);
 3114 }
 3115 
 3116 static int
 3117 sarewind(struct cam_periph *periph)
 3118 {
 3119         union   ccb *ccb;
 3120         struct  sa_softc *softc;
 3121         int     error;
 3122                 
 3123         softc = (struct sa_softc *)periph->softc;
 3124 
 3125         ccb = cam_periph_getccb(periph, 1);
 3126 
 3127         /* It is safe to retry this operation */
 3128         scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
 3129             SSD_FULL_SIZE, REWIND_TIMEOUT);
 3130 
 3131         softc->dsreg = MTIO_DSREG_REW;
 3132         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3133         softc->dsreg = MTIO_DSREG_REST;
 3134 
 3135         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 3136                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
 3137 
 3138         xpt_release_ccb(ccb);
 3139         if (error == 0)
 3140                 softc->fileno = softc->blkno = (daddr_t) 0;
 3141         else
 3142                 softc->fileno = softc->blkno = (daddr_t) -1;
 3143         return (error);
 3144 }
 3145 
 3146 static int
 3147 saspace(struct cam_periph *periph, int count, scsi_space_code code)
 3148 {
 3149         union   ccb *ccb;
 3150         struct  sa_softc *softc;
 3151         int     error;
 3152                 
 3153         softc = (struct sa_softc *)periph->softc;
 3154 
 3155         ccb = cam_periph_getccb(periph, 1);
 3156 
 3157         /* This cannot be retried */
 3158 
 3159         scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count,
 3160             SSD_FULL_SIZE, SPACE_TIMEOUT);
 3161 
 3162         /*
 3163          * Clear residual because we will be using it.
 3164          */
 3165         softc->last_ctl_resid = 0;
 3166 
 3167         softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD;
 3168         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3169         softc->dsreg = MTIO_DSREG_REST;
 3170 
 3171         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 3172                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
 3173 
 3174         xpt_release_ccb(ccb);
 3175 
 3176         /*
 3177          * If a spacing operation has failed, we need to invalidate
 3178          * this mount.
 3179          *
 3180          * If the spacing operation was setmarks or to end of recorded data,
 3181          * we no longer know our relative position.
 3182          *
 3183          * If the spacing operations was spacing files in reverse, we
 3184          * take account of the residual, but still check against less
 3185          * than zero- if we've gone negative, we must have hit BOT.
 3186          *
 3187          * If the spacing operations was spacing records in reverse and
 3188          * we have a residual, we've either hit BOT or hit a filemark.
 3189          * In the former case, we know our new record number (0). In
 3190          * the latter case, we have absolutely no idea what the real
 3191          * record number is- we've stopped between the end of the last
 3192          * record in the previous file and the filemark that stopped
 3193          * our spacing backwards.
 3194          */
 3195         if (error) {
 3196                 softc->fileno = softc->blkno = (daddr_t) -1;
 3197         } else if (code == SS_SETMARKS || code == SS_EOD) {
 3198                 softc->fileno = softc->blkno = (daddr_t) -1;
 3199         } else if (code == SS_FILEMARKS && softc->fileno != (daddr_t) -1) {
 3200                 softc->fileno += (count - softc->last_ctl_resid);
 3201                 if (softc->fileno < 0)  /* we must of hit BOT */
 3202                         softc->fileno = 0;
 3203                 softc->blkno = 0;
 3204         } else if (code == SS_BLOCKS && softc->blkno != (daddr_t) -1) {
 3205                 softc->blkno += (count - softc->last_ctl_resid);
 3206                 if (count < 0) {
 3207                         if (softc->last_ctl_resid || softc->blkno < 0) {
 3208                                 if (softc->fileno == 0) {
 3209                                         softc->blkno = 0;
 3210                                 } else {
 3211                                         softc->blkno = (daddr_t) -1;
 3212                                 }
 3213                         }
 3214                 }
 3215         }
 3216         return (error);
 3217 }
 3218 
 3219 static int
 3220 sawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks)
 3221 {
 3222         union   ccb *ccb;
 3223         struct  sa_softc *softc;
 3224         int     error, nwm = 0;
 3225 
 3226         softc = (struct sa_softc *)periph->softc;
 3227         if (softc->open_rdonly)
 3228                 return (EBADF);
 3229 
 3230         ccb = cam_periph_getccb(periph, 1);
 3231         /*
 3232          * Clear residual because we will be using it.
 3233          */
 3234         softc->last_ctl_resid = 0;
 3235 
 3236         softc->dsreg = MTIO_DSREG_FMK;
 3237         /* this *must* not be retried */
 3238         scsi_write_filemarks(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG,
 3239             FALSE, setmarks, nmarks, SSD_FULL_SIZE, IO_TIMEOUT);
 3240         softc->dsreg = MTIO_DSREG_REST;
 3241 
 3242 
 3243         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3244 
 3245         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 3246                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
 3247 
 3248         if (error == 0 && nmarks) {
 3249                 struct sa_softc *softc = (struct sa_softc *)periph->softc;
 3250                 nwm = nmarks - softc->last_ctl_resid;
 3251                 softc->filemarks += nwm;
 3252         }
 3253 
 3254         xpt_release_ccb(ccb);
 3255 
 3256         /*
 3257          * Update relative positions (if we're doing that).
 3258          */
 3259         if (error) {
 3260                 softc->fileno = softc->blkno = (daddr_t) -1;
 3261         } else if (softc->fileno != (daddr_t) -1) {
 3262                 softc->fileno += nwm;
 3263                 softc->blkno = 0;
 3264         }
 3265         return (error);
 3266 }
 3267 
 3268 static int
 3269 sardpos(struct cam_periph *periph, int hard, u_int32_t *blkptr)
 3270 {
 3271         struct scsi_tape_position_data loc;
 3272         union ccb *ccb;
 3273         struct sa_softc *softc = (struct sa_softc *)periph->softc;
 3274         int error;
 3275 
 3276         /*
 3277          * We try and flush any buffered writes here if we were writing
 3278          * and we're trying to get hardware block position. It eats
 3279          * up performance substantially, but I'm wary of drive firmware.
 3280          *
 3281          * I think that *logical* block position is probably okay-
 3282          * but hardware block position might have to wait for data
 3283          * to hit media to be valid. Caveat Emptor.
 3284          */
 3285 
 3286         if (hard && (softc->flags & SA_FLAG_TAPE_WRITTEN)) {
 3287                 error = sawritefilemarks(periph, 0, 0);
 3288                 if (error && error != EACCES)
 3289                         return (error);
 3290         }
 3291 
 3292         ccb = cam_periph_getccb(periph, 1);
 3293         scsi_read_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
 3294             hard, &loc, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
 3295         softc->dsreg = MTIO_DSREG_RBSY;
 3296         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3297         softc->dsreg = MTIO_DSREG_REST;
 3298         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 3299                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
 3300 
 3301         if (error == 0) {
 3302                 if (loc.flags & SA_RPOS_UNCERTAIN) {
 3303                         error = EINVAL;         /* nothing is certain */
 3304                 } else {
 3305                         *blkptr = scsi_4btoul(loc.firstblk);
 3306                 }
 3307         }
 3308 
 3309         xpt_release_ccb(ccb);
 3310         return (error);
 3311 }
 3312 
 3313 static int
 3314 sasetpos(struct cam_periph *periph, int hard, u_int32_t *blkptr)
 3315 {
 3316         union ccb *ccb;
 3317         struct sa_softc *softc;
 3318         int error;
 3319 
 3320         /*
 3321          * We used to try and flush any buffered writes here.
 3322          * Now we push this onto user applications to either
 3323          * flush the pending writes themselves (via a zero count
 3324          * WRITE FILEMARKS command) or they can trust their tape
 3325          * drive to do this correctly for them.
 3326          */
 3327 
 3328         softc = (struct sa_softc *)periph->softc;
 3329         ccb = cam_periph_getccb(periph, 1);
 3330 
 3331         
 3332         scsi_set_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
 3333             hard, *blkptr, SSD_FULL_SIZE, SPACE_TIMEOUT);
 3334 
 3335 
 3336         softc->dsreg = MTIO_DSREG_POS;
 3337         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3338         softc->dsreg = MTIO_DSREG_REST;
 3339         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 3340                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
 3341         xpt_release_ccb(ccb);
 3342         /*
 3343          * Note relative file && block number position as now unknown.
 3344          */
 3345         softc->fileno = softc->blkno = (daddr_t) -1;
 3346         return (error);
 3347 }
 3348 
 3349 static int
 3350 saretension(struct cam_periph *periph)
 3351 {
 3352         union ccb *ccb;
 3353         struct sa_softc *softc;
 3354         int error;
 3355 
 3356         softc = (struct sa_softc *)periph->softc;
 3357 
 3358         ccb = cam_periph_getccb(periph, 1);
 3359 
 3360         /* It is safe to retry this operation */
 3361         scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
 3362             FALSE, TRUE,  TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT);
 3363 
 3364         softc->dsreg = MTIO_DSREG_TEN;
 3365         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3366         softc->dsreg = MTIO_DSREG_REST;
 3367 
 3368         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 3369                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
 3370         xpt_release_ccb(ccb);
 3371         if (error == 0)
 3372                 softc->fileno = softc->blkno = (daddr_t) 0;
 3373         else
 3374                 softc->fileno = softc->blkno = (daddr_t) -1;
 3375         return (error);
 3376 }
 3377 
 3378 static int
 3379 sareservereleaseunit(struct cam_periph *periph, int reserve)
 3380 {
 3381         union ccb *ccb;
 3382         struct sa_softc *softc;
 3383         int error;
 3384 
 3385         softc = (struct sa_softc *)periph->softc;
 3386         ccb = cam_periph_getccb(periph,  1);
 3387 
 3388         /* It is safe to retry this operation */
 3389         scsi_reserve_release_unit(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG,
 3390             FALSE,  0, SSD_FULL_SIZE,  SCSIOP_TIMEOUT, reserve);
 3391         softc->dsreg = MTIO_DSREG_RBSY;
 3392         error = cam_periph_runccb(ccb, saerror, 0,
 3393             SF_RETRY_UA | SF_NO_PRINT, softc->device_stats);
 3394         softc->dsreg = MTIO_DSREG_REST;
 3395         QFRLS(ccb);
 3396         xpt_release_ccb(ccb);
 3397 
 3398         /*
 3399          * If the error was Illegal Request, then the device doesn't support
 3400          * RESERVE/RELEASE. This is not an error.
 3401          */
 3402         if (error == EINVAL) {
 3403                 error = 0;
 3404         }
 3405 
 3406         return (error);
 3407 }
 3408 
 3409 static int
 3410 saloadunload(struct cam_periph *periph, int load)
 3411 {
 3412         union   ccb *ccb;
 3413         struct  sa_softc *softc;
 3414         int     error;
 3415 
 3416         softc = (struct sa_softc *)periph->softc;
 3417 
 3418         ccb = cam_periph_getccb(periph, 1);
 3419 
 3420         /* It is safe to retry this operation */
 3421         scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
 3422             FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT);
 3423 
 3424         softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL;
 3425         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3426         softc->dsreg = MTIO_DSREG_REST;
 3427         QFRLS(ccb);
 3428         xpt_release_ccb(ccb);
 3429 
 3430         if (error || load == 0)
 3431                 softc->fileno = softc->blkno = (daddr_t) -1;
 3432         else if (error == 0)
 3433                 softc->fileno = softc->blkno = (daddr_t) 0;
 3434         return (error);
 3435 }
 3436 
 3437 static int
 3438 saerase(struct cam_periph *periph, int longerase)
 3439 {
 3440 
 3441         union   ccb *ccb;
 3442         struct  sa_softc *softc;
 3443         int error;
 3444 
 3445         softc = (struct sa_softc *)periph->softc;
 3446         if (softc->open_rdonly)
 3447                 return (EBADF);
 3448 
 3449         ccb = cam_periph_getccb(periph, 1);
 3450 
 3451         scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase,
 3452             SSD_FULL_SIZE, ERASE_TIMEOUT);
 3453 
 3454         softc->dsreg = MTIO_DSREG_ZER;
 3455         error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
 3456         softc->dsreg = MTIO_DSREG_REST;
 3457 
 3458         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
 3459                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
 3460         xpt_release_ccb(ccb);
 3461         return (error);
 3462 }
 3463 
 3464 #endif /* _KERNEL */
 3465 
 3466 /*
 3467  * Read tape block limits command.
 3468  */
 3469 void
 3470 scsi_read_block_limits(struct ccb_scsiio *csio, u_int32_t retries,
 3471                    void (*cbfcnp)(struct cam_periph *, union ccb *),
 3472                    u_int8_t tag_action,
 3473                    struct scsi_read_block_limits_data *rlimit_buf,
 3474                    u_int8_t sense_len, u_int32_t timeout)
 3475 {
 3476         struct scsi_read_block_limits *scsi_cmd;
 3477 
 3478         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action,
 3479              (u_int8_t *)rlimit_buf, sizeof(*rlimit_buf), sense_len,
 3480              sizeof(*scsi_cmd), timeout);
 3481 
 3482         scsi_cmd = (struct scsi_read_block_limits *)&csio->cdb_io.cdb_bytes;
 3483         bzero(scsi_cmd, sizeof(*scsi_cmd));
 3484         scsi_cmd->opcode = READ_BLOCK_LIMITS;
 3485 }
 3486 
 3487 void
 3488 scsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries,
 3489                    void (*cbfcnp)(struct cam_periph *, union ccb *),
 3490                    u_int8_t tag_action, int readop, int sli,
 3491                    int fixed, u_int32_t length, u_int8_t *data_ptr,
 3492                    u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout)
 3493 {
 3494         struct scsi_sa_rw *scsi_cmd;
 3495 
 3496         scsi_cmd = (struct scsi_sa_rw *)&csio->cdb_io.cdb_bytes;
 3497         scsi_cmd->opcode = readop ? SA_READ : SA_WRITE;
 3498         scsi_cmd->sli_fixed = 0;
 3499         if (sli && readop)
 3500                 scsi_cmd->sli_fixed |= SAR_SLI;
 3501         if (fixed)
 3502                 scsi_cmd->sli_fixed |= SARW_FIXED;
 3503         scsi_ulto3b(length, scsi_cmd->length);
 3504         scsi_cmd->control = 0;
 3505 
 3506         cam_fill_csio(csio, retries, cbfcnp, readop ? CAM_DIR_IN : CAM_DIR_OUT,
 3507             tag_action, data_ptr, dxfer_len, sense_len,
 3508             sizeof(*scsi_cmd), timeout);
 3509 }
 3510 
 3511 void
 3512 scsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries,         
 3513                  void (*cbfcnp)(struct cam_periph *, union ccb *),   
 3514                  u_int8_t tag_action, int immediate, int eot,
 3515                  int reten, int load, u_int8_t sense_len,
 3516                  u_int32_t timeout)
 3517 {
 3518         struct scsi_load_unload *scsi_cmd;
 3519 
 3520         scsi_cmd = (struct scsi_load_unload *)&csio->cdb_io.cdb_bytes;
 3521         bzero(scsi_cmd, sizeof(*scsi_cmd));
 3522         scsi_cmd->opcode = LOAD_UNLOAD;
 3523         if (immediate)
 3524                 scsi_cmd->immediate = SLU_IMMED;
 3525         if (eot)
 3526                 scsi_cmd->eot_reten_load |= SLU_EOT;
 3527         if (reten)
 3528                 scsi_cmd->eot_reten_load |= SLU_RETEN;
 3529         if (load)
 3530                 scsi_cmd->eot_reten_load |= SLU_LOAD;
 3531 
 3532         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action,
 3533             NULL, 0, sense_len, sizeof(*scsi_cmd), timeout);    
 3534 }
 3535 
 3536 void
 3537 scsi_rewind(struct ccb_scsiio *csio, u_int32_t retries,         
 3538             void (*cbfcnp)(struct cam_periph *, union ccb *),   
 3539             u_int8_t tag_action, int immediate, u_int8_t sense_len,     
 3540             u_int32_t timeout)
 3541 {
 3542         struct scsi_rewind *scsi_cmd;
 3543 
 3544         scsi_cmd = (struct scsi_rewind *)&csio->cdb_io.cdb_bytes;
 3545         bzero(scsi_cmd, sizeof(*scsi_cmd));
 3546         scsi_cmd->opcode = REWIND;
 3547         if (immediate)
 3548                 scsi_cmd->immediate = SREW_IMMED;
 3549         
 3550         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
 3551             0, sense_len, sizeof(*scsi_cmd), timeout);
 3552 }
 3553 
 3554 void
 3555 scsi_space(struct ccb_scsiio *csio, u_int32_t retries,
 3556            void (*cbfcnp)(struct cam_periph *, union ccb *),
 3557            u_int8_t tag_action, scsi_space_code code,
 3558            u_int32_t count, u_int8_t sense_len, u_int32_t timeout)
 3559 {
 3560         struct scsi_space *scsi_cmd;
 3561 
 3562         scsi_cmd = (struct scsi_space *)&csio->cdb_io.cdb_bytes;
 3563         scsi_cmd->opcode = SPACE;
 3564         scsi_cmd->code = code;
 3565         scsi_ulto3b(count, scsi_cmd->count);
 3566         scsi_cmd->control = 0;
 3567 
 3568         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
 3569             0, sense_len, sizeof(*scsi_cmd), timeout);
 3570 }
 3571 
 3572 void
 3573 scsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries,
 3574                      void (*cbfcnp)(struct cam_periph *, union ccb *),
 3575                      u_int8_t tag_action, int immediate, int setmark,
 3576                      u_int32_t num_marks, u_int8_t sense_len,
 3577                      u_int32_t timeout)
 3578 {
 3579         struct scsi_write_filemarks *scsi_cmd;
 3580 
 3581         scsi_cmd = (struct scsi_write_filemarks *)&csio->cdb_io.cdb_bytes;
 3582         bzero(scsi_cmd, sizeof(*scsi_cmd));
 3583         scsi_cmd->opcode = WRITE_FILEMARKS;
 3584         if (immediate)
 3585                 scsi_cmd->byte2 |= SWFMRK_IMMED;
 3586         if (setmark)
 3587                 scsi_cmd->byte2 |= SWFMRK_WSMK;
 3588         
 3589         scsi_ulto3b(num_marks, scsi_cmd->num_marks);
 3590 
 3591         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
 3592             0, sense_len, sizeof(*scsi_cmd), timeout);
 3593 }
 3594 
 3595 /*
 3596  * The reserve and release unit commands differ only by their opcodes.
 3597  */
 3598 void
 3599 scsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries,
 3600                           void (*cbfcnp)(struct cam_periph *, union ccb *),
 3601                           u_int8_t tag_action, int third_party,
 3602                           int third_party_id, u_int8_t sense_len,
 3603                           u_int32_t timeout, int reserve)
 3604 {
 3605         struct scsi_reserve_release_unit *scsi_cmd;
 3606 
 3607         scsi_cmd = (struct scsi_reserve_release_unit *)&csio->cdb_io.cdb_bytes;
 3608         bzero(scsi_cmd, sizeof(*scsi_cmd));
 3609 
 3610         if (reserve)
 3611                 scsi_cmd->opcode = RESERVE_UNIT;
 3612         else
 3613                 scsi_cmd->opcode = RELEASE_UNIT;
 3614 
 3615         if (third_party) {
 3616                 scsi_cmd->lun_thirdparty |= SRRU_3RD_PARTY;
 3617                 scsi_cmd->lun_thirdparty |=
 3618                         ((third_party_id << SRRU_3RD_SHAMT) & SRRU_3RD_MASK);
 3619         }
 3620 
 3621         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
 3622             0, sense_len, sizeof(*scsi_cmd), timeout);
 3623 }
 3624 
 3625 void
 3626 scsi_erase(struct ccb_scsiio *csio, u_int32_t retries,
 3627            void (*cbfcnp)(struct cam_periph *, union ccb *),
 3628            u_int8_t tag_action, int immediate, int long_erase,
 3629            u_int8_t sense_len, u_int32_t timeout)
 3630 {
 3631         struct scsi_erase *scsi_cmd;
 3632 
 3633         scsi_cmd = (struct scsi_erase *)&csio->cdb_io.cdb_bytes;
 3634         bzero(scsi_cmd, sizeof(*scsi_cmd));
 3635 
 3636         scsi_cmd->opcode = ERASE;
 3637 
 3638         if (immediate)
 3639                 scsi_cmd->lun_imm_long |= SE_IMMED;
 3640 
 3641         if (long_erase)
 3642                 scsi_cmd->lun_imm_long |= SE_LONG;
 3643 
 3644         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
 3645             0, sense_len, sizeof(*scsi_cmd), timeout);
 3646 }
 3647 
 3648 /*
 3649  * Read Tape Position command.
 3650  */
 3651 void
 3652 scsi_read_position(struct ccb_scsiio *csio, u_int32_t retries,
 3653                    void (*cbfcnp)(struct cam_periph *, union ccb *),
 3654                    u_int8_t tag_action, int hardsoft,
 3655                    struct scsi_tape_position_data *sbp,
 3656                    u_int8_t sense_len, u_int32_t timeout)
 3657 {
 3658         struct scsi_tape_read_position *scmd;
 3659 
 3660         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action,
 3661             (u_int8_t *)sbp, sizeof (*sbp), sense_len, sizeof(*scmd), timeout);
 3662         scmd = (struct scsi_tape_read_position *)&csio->cdb_io.cdb_bytes;
 3663         bzero(scmd, sizeof(*scmd));
 3664         scmd->opcode = READ_POSITION;
 3665         scmd->byte1 = hardsoft;
 3666 }
 3667 
 3668 /*
 3669  * Set Tape Position command.
 3670  */
 3671 void
 3672 scsi_set_position(struct ccb_scsiio *csio, u_int32_t retries,
 3673                    void (*cbfcnp)(struct cam_periph *, union ccb *),
 3674                    u_int8_t tag_action, int hardsoft, u_int32_t blkno,
 3675                    u_int8_t sense_len, u_int32_t timeout)
 3676 {
 3677         struct scsi_tape_locate *scmd;
 3678 
 3679         cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action,
 3680             (u_int8_t *)NULL, 0, sense_len, sizeof(*scmd), timeout);
 3681         scmd = (struct scsi_tape_locate *)&csio->cdb_io.cdb_bytes;
 3682         bzero(scmd, sizeof(*scmd));
 3683         scmd->opcode = LOCATE;
 3684         if (hardsoft)
 3685                 scmd->byte1 |= SA_SPOS_BT;
 3686         scsi_ulto4b(blkno, scmd->blkaddr);
 3687 }

Cache object: 74c91c700c5e28579ca36d058bc76cfb


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