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

Cache object: f38dabbe6d75d50b0df9801d409c6faf


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