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

Cache object: 8dad574f0f6fd3ba8b5bd91ed5f21d53


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