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

Cache object: 0e9039712c9795dd136bd63d7264a0e9


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