scsi_sa.c revision 195534
1139743Simp/*- 239213Sgibbs * Implementation of SCSI Sequential Access Peripheral driver for CAM. 339213Sgibbs * 458251Smjacob * Copyright (c) 1999, 2000 Matthew Jacob 539213Sgibbs * All rights reserved. 639213Sgibbs * 739213Sgibbs * Redistribution and use in source and binary forms, with or without 839213Sgibbs * modification, are permitted provided that the following conditions 939213Sgibbs * are met: 1039213Sgibbs * 1. Redistributions of source code must retain the above copyright 1139213Sgibbs * notice, this list of conditions, and the following disclaimer, 1239213Sgibbs * without modification, immediately at the beginning of the file. 1339213Sgibbs * 2. The name of the author may not be used to endorse or promote products 1439213Sgibbs * derived from this software without specific prior written permission. 1539213Sgibbs * 1639213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2039213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639213Sgibbs * SUCH DAMAGE. 2739213Sgibbs */ 2839213Sgibbs 29116162Sobrien#include <sys/cdefs.h> 30116162Sobrien__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_sa.c 195534 2009-07-10 08:18:08Z scottl $"); 31116162Sobrien 3239213Sgibbs#include <sys/param.h> 3339213Sgibbs#include <sys/queue.h> 3455205Speter#ifdef _KERNEL 3539213Sgibbs#include <sys/systm.h> 3639213Sgibbs#include <sys/kernel.h> 3739213Sgibbs#endif 3839213Sgibbs#include <sys/types.h> 39110517Sphk#include <sys/time.h> 4060041Sphk#include <sys/bio.h> 41114216Skan#include <sys/limits.h> 4239213Sgibbs#include <sys/malloc.h> 4339213Sgibbs#include <sys/mtio.h> 4465061Speter#ifdef _KERNEL 4539213Sgibbs#include <sys/conf.h> 4665061Speter#endif 47154360Smjacob#include <sys/fcntl.h> 4839213Sgibbs#include <sys/devicestat.h> 4939213Sgibbs 5055205Speter#ifndef _KERNEL 5139213Sgibbs#include <stdio.h> 5239213Sgibbs#include <string.h> 5339213Sgibbs#endif 5439213Sgibbs 5539213Sgibbs#include <cam/cam.h> 5639213Sgibbs#include <cam/cam_ccb.h> 5739213Sgibbs#include <cam/cam_periph.h> 5839213Sgibbs#include <cam/cam_xpt_periph.h> 5939213Sgibbs#include <cam/cam_debug.h> 6039213Sgibbs 6139213Sgibbs#include <cam/scsi/scsi_all.h> 6239213Sgibbs#include <cam/scsi/scsi_message.h> 6339213Sgibbs#include <cam/scsi/scsi_sa.h> 6439213Sgibbs 6555205Speter#ifdef _KERNEL 6639213Sgibbs 6739884Sken#include <opt_sa.h> 6839884Sken 6979100Smjacob#ifndef SA_IO_TIMEOUT 7079100Smjacob#define SA_IO_TIMEOUT 4 7179100Smjacob#endif 7239884Sken#ifndef SA_SPACE_TIMEOUT 7339884Sken#define SA_SPACE_TIMEOUT 1 * 60 7439884Sken#endif 7539884Sken#ifndef SA_REWIND_TIMEOUT 7639884Sken#define SA_REWIND_TIMEOUT 2 * 60 7739884Sken#endif 7839884Sken#ifndef SA_ERASE_TIMEOUT 7939884Sken#define SA_ERASE_TIMEOUT 4 * 60 8039884Sken#endif 8153259Smjacob 8279100Smjacob#define SCSIOP_TIMEOUT (60 * 1000) /* not an option */ 8379100Smjacob 8479100Smjacob#define IO_TIMEOUT (SA_IO_TIMEOUT * 60 * 1000) 8554099Smjacob#define REWIND_TIMEOUT (SA_REWIND_TIMEOUT * 60 * 1000) 8654099Smjacob#define ERASE_TIMEOUT (SA_ERASE_TIMEOUT * 60 * 1000) 8754099Smjacob#define SPACE_TIMEOUT (SA_SPACE_TIMEOUT * 60 * 1000) 8853259Smjacob 8943636Smjacob/* 9051875Smjacob * Additional options that can be set for config: SA_1FM_AT_EOT 9143636Smjacob */ 9253259Smjacob 9341906Smjacob#ifndef UNUSED_PARAMETER 9441906Smjacob#define UNUSED_PARAMETER(x) x = x 9541906Smjacob#endif 9641906Smjacob 9753259Smjacob#define QFRLS(ccb) \ 9853259Smjacob if (((ccb)->ccb_h.status & CAM_DEV_QFRZN) != 0) \ 9953259Smjacob cam_release_devq((ccb)->ccb_h.path, 0, 0, 0, FALSE) 10053259Smjacob 10153259Smjacob/* 10253259Smjacob * Driver states 10353259Smjacob */ 10453259Smjacob 105147723SavatarMALLOC_DEFINE(M_SCSISA, "SCSI sa", "SCSI sequential access buffers"); 10653259Smjacob 10739213Sgibbstypedef enum { 10846962Smjacob SA_STATE_NORMAL, SA_STATE_ABNORMAL 10939213Sgibbs} sa_state; 11039213Sgibbs 11171082Smjacob#define ccb_pflags ppriv_field0 11271082Smjacob#define ccb_bp ppriv_ptr1 11339213Sgibbs 11471082Smjacob#define SA_CCB_BUFFER_IO 0x0 11571082Smjacob#define SA_CCB_WAITING 0x1 11671082Smjacob#define SA_CCB_TYPEMASK 0x1 11771082Smjacob#define SA_POSITION_UPDATED 0x2 11839213Sgibbs 11971082Smjacob#define Set_CCB_Type(x, type) \ 12071082Smjacob x->ccb_h.ccb_pflags &= ~SA_CCB_TYPEMASK; \ 12171082Smjacob x->ccb_h.ccb_pflags |= type 12271082Smjacob 12371082Smjacob#define CCB_Type(x) (x->ccb_h.ccb_pflags & SA_CCB_TYPEMASK) 12471082Smjacob 12571082Smjacob 12671082Smjacob 12739213Sgibbstypedef enum { 12839213Sgibbs SA_FLAG_OPEN = 0x0001, 12939213Sgibbs SA_FLAG_FIXED = 0x0002, 13039213Sgibbs SA_FLAG_TAPE_LOCKED = 0x0004, 13139213Sgibbs SA_FLAG_TAPE_MOUNTED = 0x0008, 13239213Sgibbs SA_FLAG_TAPE_WP = 0x0010, 13339213Sgibbs SA_FLAG_TAPE_WRITTEN = 0x0020, 13441906Smjacob SA_FLAG_EOM_PENDING = 0x0040, 13541906Smjacob SA_FLAG_EIO_PENDING = 0x0080, 13641906Smjacob SA_FLAG_EOF_PENDING = 0x0100, 13739213Sgibbs SA_FLAG_ERR_PENDING = (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING| 13839213Sgibbs SA_FLAG_EOF_PENDING), 13941906Smjacob SA_FLAG_INVALID = 0x0200, 14041906Smjacob SA_FLAG_COMP_ENABLED = 0x0400, 14146962Smjacob SA_FLAG_COMP_SUPP = 0x0800, 14246962Smjacob SA_FLAG_COMP_UNSUPP = 0x1000, 14346962Smjacob SA_FLAG_TAPE_FROZEN = 0x2000 14439213Sgibbs} sa_flags; 14539213Sgibbs 14639213Sgibbstypedef enum { 14739213Sgibbs SA_MODE_REWIND = 0x00, 14839213Sgibbs SA_MODE_NOREWIND = 0x01, 14939213Sgibbs SA_MODE_OFFLINE = 0x02 15039213Sgibbs} sa_mode; 15139213Sgibbs 15239213Sgibbstypedef enum { 15339213Sgibbs SA_PARAM_NONE = 0x00, 15439213Sgibbs SA_PARAM_BLOCKSIZE = 0x01, 15539213Sgibbs SA_PARAM_DENSITY = 0x02, 15639213Sgibbs SA_PARAM_COMPRESSION = 0x04, 15739213Sgibbs SA_PARAM_BUFF_MODE = 0x08, 15839213Sgibbs SA_PARAM_NUMBLOCKS = 0x10, 15939213Sgibbs SA_PARAM_WP = 0x20, 16039213Sgibbs SA_PARAM_SPEED = 0x40, 16139213Sgibbs SA_PARAM_ALL = 0x7f 16239213Sgibbs} sa_params; 16339213Sgibbs 16439213Sgibbstypedef enum { 16539213Sgibbs SA_QUIRK_NONE = 0x00, 16660235Smjacob SA_QUIRK_NOCOMP = 0x01, /* Can't deal with compression at all */ 16760235Smjacob SA_QUIRK_FIXED = 0x02, /* Force fixed mode */ 16860235Smjacob SA_QUIRK_VARIABLE = 0x04, /* Force variable mode */ 16943636Smjacob SA_QUIRK_2FM = 0x08, /* Needs Two File Marks at EOD */ 17056981Smjacob SA_QUIRK_1FM = 0x10, /* No more than 1 File Mark at EOD */ 17160235Smjacob SA_QUIRK_NODREAD = 0x20, /* Don't try and dummy read density */ 17271082Smjacob SA_QUIRK_NO_MODESEL = 0x40, /* Don't do mode select at all */ 17371082Smjacob SA_QUIRK_NO_CPAGE = 0x80 /* Don't use DEVICE COMPRESSION page */ 17439213Sgibbs} sa_quirks; 17539213Sgibbs 176191304Sed#define SAMODE(z) (dev2unit(z) & 0x3) 177191304Sed#define SADENSITY(z) ((dev2unit(z) >> 2) & 0x3) 178191304Sed#define SA_IS_CTRL(z) (dev2unit(z) & (1 << 4)) 17953283Smjacob 18053259Smjacob#define SA_NOT_CTLDEV 0 18153259Smjacob#define SA_CTLDEV 1 18253259Smjacob 18353259Smjacob#define SA_ATYPE_R 0 18453259Smjacob#define SA_ATYPE_NR 1 18553259Smjacob#define SA_ATYPE_ER 2 18653259Smjacob 187191304Sed#define SAMINOR(ctl, mode, access) \ 188191304Sed ((ctl << 4) | (mode << 2) | (access & 0x3)) 18953259Smjacob 19053259Smjacob#define SA_NUM_MODES 4 19153259Smjacobstruct sa_devs { 192130585Sphk struct cdev *ctl_dev; 19353259Smjacob struct sa_mode_devs { 194130585Sphk struct cdev *r_dev; 195130585Sphk struct cdev *nr_dev; 196130585Sphk struct cdev *er_dev; 19753259Smjacob } mode_devs[SA_NUM_MODES]; 19853259Smjacob}; 19953259Smjacob 20039213Sgibbsstruct sa_softc { 20139213Sgibbs sa_state state; 20239213Sgibbs sa_flags flags; 20339213Sgibbs sa_quirks quirks; 20459249Sphk struct bio_queue_head bio_queue; 20546962Smjacob int queue_count; 206112006Sphk struct devstat *device_stats; 20753259Smjacob struct sa_devs devs; 20839213Sgibbs int blk_gran; 20939213Sgibbs int blk_mask; 21039213Sgibbs int blk_shift; 21139213Sgibbs u_int32_t max_blk; 21239213Sgibbs u_int32_t min_blk; 21341674Smjacob u_int32_t comp_algorithm; 21441674Smjacob u_int32_t saved_comp_algorithm; 21539213Sgibbs u_int32_t media_blksize; 21641906Smjacob u_int32_t last_media_blksize; 21739213Sgibbs u_int32_t media_numblks; 21841674Smjacob u_int8_t media_density; 21939213Sgibbs u_int8_t speed; 22041674Smjacob u_int8_t scsi_rev; 22143636Smjacob u_int8_t dsreg; /* mtio mt_dsreg, redux */ 22239213Sgibbs int buffer_mode; 22339213Sgibbs int filemarks; 22439213Sgibbs union ccb saved_ccb; 22571268Smjacob int last_resid_was_io; 22646962Smjacob 22741948Smjacob /* 22843636Smjacob * Relative to BOT Location. 22943636Smjacob */ 23043636Smjacob daddr_t fileno; 23143636Smjacob daddr_t blkno; 23243636Smjacob 23343636Smjacob /* 23441948Smjacob * Latched Error Info 23541948Smjacob */ 23642009Smjacob struct { 23742009Smjacob struct scsi_sense_data _last_io_sense; 23842009Smjacob u_int32_t _last_io_resid; 23942009Smjacob u_int8_t _last_io_cdb[CAM_MAX_CDBLEN]; 24042009Smjacob struct scsi_sense_data _last_ctl_sense; 24142009Smjacob u_int32_t _last_ctl_resid; 24242009Smjacob u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN]; 24342009Smjacob#define last_io_sense errinfo._last_io_sense 24442009Smjacob#define last_io_resid errinfo._last_io_resid 24542009Smjacob#define last_io_cdb errinfo._last_io_cdb 24642009Smjacob#define last_ctl_sense errinfo._last_ctl_sense 24742009Smjacob#define last_ctl_resid errinfo._last_ctl_resid 24842009Smjacob#define last_ctl_cdb errinfo._last_ctl_cdb 24942009Smjacob } errinfo; 25043636Smjacob /* 25143636Smjacob * Misc other flags/state 25243636Smjacob */ 25343636Smjacob u_int32_t 254154360Smjacob : 29, 255154360Smjacob open_rdonly : 1, /* open read-only */ 256154360Smjacob open_pending_mount : 1, /* open pending mount */ 257154360Smjacob ctrl_mode : 1; /* control device open */ 25839213Sgibbs}; 25939213Sgibbs 26039213Sgibbsstruct sa_quirk_entry { 26142563Smjacob struct scsi_inquiry_pattern inq_pat; /* matching pattern */ 26242563Smjacob sa_quirks quirks; /* specific quirk type */ 26342563Smjacob u_int32_t prefblk; /* preferred blocksize when in fixed mode */ 26439213Sgibbs}; 26539213Sgibbs 26639213Sgibbsstatic struct sa_quirk_entry sa_quirk_table[] = 26739213Sgibbs{ 26839213Sgibbs { 26960235Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "OnStream", 27060235Smjacob "ADR*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_NODREAD | 27160235Smjacob SA_QUIRK_1FM|SA_QUIRK_NO_MODESEL, 32768 27260235Smjacob }, 27360235Smjacob { 27439213Sgibbs { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 27577810Snon "Python 06408*", "*"}, SA_QUIRK_NODREAD, 0 27677581Snon }, 27777581Snon { 27877581Snon { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 27956981Smjacob "Python 25601*", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_NODREAD, 0 28041351Sjoerg }, 28141351Sjoerg { 28242130Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28356981Smjacob "Python*", "*"}, SA_QUIRK_NODREAD, 0 28456981Smjacob }, 28556981Smjacob { 28656981Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28743636Smjacob "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 28842130Smjacob }, 28942130Smjacob { 29042563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 29168500Smjacob "VIPER 2525 25462", "-011"}, 29268500Smjacob SA_QUIRK_NOCOMP|SA_QUIRK_1FM|SA_QUIRK_NODREAD, 0 29368500Smjacob }, 29468500Smjacob { 29568500Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 29646962Smjacob "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 29742563Smjacob }, 29871082Smjacob#if 0 29942563Smjacob { 30042533Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 30171082Smjacob "C15*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_NO_CPAGE, 0, 30271082Smjacob }, 30371082Smjacob#endif 304107943Strhodes { 305107943Strhodes { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 306107943Strhodes "C56*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 307107943Strhodes }, 30871082Smjacob { 30971082Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 31046962Smjacob "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 31146962Smjacob }, 31246962Smjacob { 31346962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 31444354Smjacob "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 31542533Smjacob }, 31642533Smjacob { 31742716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 31842716Smjacob "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 31942716Smjacob }, 32042716Smjacob { 32142716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", 32242716Smjacob "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 32342716Smjacob }, 32442716Smjacob { 32542716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA", 32642716Smjacob "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 32742716Smjacob }, 32851744Smjacob { /* jreynold@primenet.com */ 32951744Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 33051744Smjacob "STT8000N*", "*"}, SA_QUIRK_1FM, 0 33151744Smjacob }, 33251875Smjacob { /* mike@sentex.net */ 33351875Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 33451875Smjacob "STT20000*", "*"}, SA_QUIRK_1FM, 0 33551875Smjacob }, 33642716Smjacob { 33741351Sjoerg { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 33843636Smjacob " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 33942563Smjacob }, 34042563Smjacob { 34142563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 34247519Smjacob " TDC 3800", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 34347519Smjacob }, 34447519Smjacob { 34547519Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 34648192Smjacob " TDC 4100", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 34748192Smjacob }, 34848192Smjacob { 34948192Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 35043636Smjacob " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 35142563Smjacob }, 35242563Smjacob { 35346962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 35446962Smjacob " SLR*", "*"}, SA_QUIRK_1FM, 0 35546962Smjacob }, 35646962Smjacob { 35742563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 35843636Smjacob "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 35945752Smjacob }, 36045752Smjacob { 36145752Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 36245752Smjacob "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 36339213Sgibbs } 36439213Sgibbs}; 36539213Sgibbs 36639213Sgibbsstatic d_open_t saopen; 36739213Sgibbsstatic d_close_t saclose; 36839213Sgibbsstatic d_strategy_t sastrategy; 36939213Sgibbsstatic d_ioctl_t saioctl; 37039213Sgibbsstatic periph_init_t sainit; 37139213Sgibbsstatic periph_ctor_t saregister; 37240603Skenstatic periph_oninv_t saoninvalidate; 37339213Sgibbsstatic periph_dtor_t sacleanup; 37439213Sgibbsstatic periph_start_t sastart; 37539213Sgibbsstatic void saasync(void *callback_arg, u_int32_t code, 37639213Sgibbs struct cam_path *path, void *arg); 37739213Sgibbsstatic void sadone(struct cam_periph *periph, 37839213Sgibbs union ccb *start_ccb); 37939213Sgibbsstatic int saerror(union ccb *ccb, u_int32_t cam_flags, 38039213Sgibbs u_int32_t sense_flags); 38168114Smjacobstatic int samarkswanted(struct cam_periph *); 38239213Sgibbsstatic int sacheckeod(struct cam_periph *periph); 38339213Sgibbsstatic int sagetparams(struct cam_periph *periph, 38439213Sgibbs sa_params params_to_get, 38539213Sgibbs u_int32_t *blocksize, u_int8_t *density, 38639213Sgibbs u_int32_t *numblocks, int *buff_mode, 38739213Sgibbs u_int8_t *write_protect, u_int8_t *speed, 38839213Sgibbs int *comp_supported, int *comp_enabled, 38939213Sgibbs u_int32_t *comp_algorithm, 39046962Smjacob sa_comp_t *comp_page); 39139213Sgibbsstatic int sasetparams(struct cam_periph *periph, 39239213Sgibbs sa_params params_to_set, 39339213Sgibbs u_int32_t blocksize, u_int8_t density, 39442563Smjacob u_int32_t comp_algorithm, 39542563Smjacob u_int32_t sense_flags); 39639213Sgibbsstatic void saprevent(struct cam_periph *periph, int action); 39739213Sgibbsstatic int sarewind(struct cam_periph *periph); 39839213Sgibbsstatic int saspace(struct cam_periph *periph, int count, 39939213Sgibbs scsi_space_code code); 400130585Sphkstatic int samount(struct cam_periph *, int, struct cdev *); 40139213Sgibbsstatic int saretension(struct cam_periph *periph); 40239213Sgibbsstatic int sareservereleaseunit(struct cam_periph *periph, 40339213Sgibbs int reserve); 40439213Sgibbsstatic int saloadunload(struct cam_periph *periph, int load); 40539213Sgibbsstatic int saerase(struct cam_periph *periph, int longerase); 40639213Sgibbsstatic int sawritefilemarks(struct cam_periph *periph, 40739213Sgibbs int nmarks, int setmarks); 40841918Smjacobstatic int sardpos(struct cam_periph *periph, int, u_int32_t *); 40941918Smjacobstatic int sasetpos(struct cam_periph *periph, int, u_int32_t *); 41039213Sgibbs 41141918Smjacob 41239213Sgibbsstatic struct periph_driver sadriver = 41339213Sgibbs{ 41439213Sgibbs sainit, "sa", 41539213Sgibbs TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0 41639213Sgibbs}; 41739213Sgibbs 41872119SpeterPERIPHDRIVER_DECLARE(sa, sadriver); 41939213Sgibbs 42039213Sgibbs/* For 2.2-stable support */ 42139213Sgibbs#ifndef D_TAPE 42239213Sgibbs#define D_TAPE 0 42339213Sgibbs#endif 42439213Sgibbs 42539213Sgibbs 42647625Sphkstatic struct cdevsw sa_cdevsw = { 427126080Sphk .d_version = D_VERSION, 428111815Sphk .d_open = saopen, 429111815Sphk .d_close = saclose, 430111815Sphk .d_read = physread, 431111815Sphk .d_write = physwrite, 432111815Sphk .d_ioctl = saioctl, 433111815Sphk .d_strategy = sastrategy, 434111815Sphk .d_name = "sa", 435126080Sphk .d_flags = D_TAPE | D_NEEDGIANT, 43639213Sgibbs}; 43739213Sgibbs 43839213Sgibbsstatic int 439130585Sphksaopen(struct cdev *dev, int flags, int fmt, struct thread *td) 44039213Sgibbs{ 44139213Sgibbs struct cam_periph *periph; 44239213Sgibbs struct sa_softc *softc; 44339213Sgibbs int error; 44439213Sgibbs 445101940Snjl periph = (struct cam_periph *)dev->si_drv1; 446168752Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 447168752Sscottl return (ENXIO); 44853259Smjacob } 449168752Sscottl 450168752Sscottl cam_periph_lock(periph); 451168752Sscottl 45239213Sgibbs softc = (struct sa_softc *)periph->softc; 45339213Sgibbs 45446962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 455191304Sed ("saopen(%s): softc=0x%x\n", devtoname(dev), softc->flags)); 45639213Sgibbs 45743636Smjacob if (SA_IS_CTRL(dev)) { 45843636Smjacob softc->ctrl_mode = 1; 45953259Smjacob cam_periph_unlock(periph); 46043636Smjacob return (0); 46143636Smjacob } 46243636Smjacob 463168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 464168752Sscottl cam_periph_unlock(periph); 465168752Sscottl cam_periph_release(periph); 466168752Sscottl return (error); 467168752Sscottl } 468168752Sscottl 46953259Smjacob if (softc->flags & SA_FLAG_OPEN) { 47053259Smjacob error = EBUSY; 47153259Smjacob } else if (softc->flags & SA_FLAG_INVALID) { 47253259Smjacob error = ENXIO; 47353259Smjacob } else { 47453259Smjacob /* 475154360Smjacob * Preserve whether this is a read_only open. 476154360Smjacob */ 477154360Smjacob softc->open_rdonly = (flags & O_RDWR) == O_RDONLY; 478154360Smjacob 479154360Smjacob /* 48053259Smjacob * The function samount ensures media is loaded and ready. 48153259Smjacob * It also does a device RESERVE if the tape isn't yet mounted. 482154360Smjacob * 483154360Smjacob * If the mount fails and this was a non-blocking open, 484154360Smjacob * make this a 'open_pending_mount' action. 48553259Smjacob */ 48653259Smjacob error = samount(periph, flags, dev); 487154360Smjacob if (error && (flags & O_NONBLOCK)) { 488154360Smjacob softc->flags |= SA_FLAG_OPEN; 489154360Smjacob softc->open_pending_mount = 1; 490168752Sscottl cam_periph_unhold(periph); 491154360Smjacob cam_periph_unlock(periph); 492154360Smjacob return (0); 493154360Smjacob } 49439213Sgibbs } 49539213Sgibbs 49653259Smjacob if (error) { 497168752Sscottl cam_periph_unhold(periph); 498168752Sscottl cam_periph_unlock(periph); 49953259Smjacob cam_periph_release(periph); 500168752Sscottl return (error); 50139213Sgibbs } 502168752Sscottl 503168752Sscottl saprevent(periph, PR_PREVENT); 504168752Sscottl softc->flags |= SA_FLAG_OPEN; 505168752Sscottl 506168752Sscottl cam_periph_unhold(periph); 50739213Sgibbs cam_periph_unlock(periph); 50839213Sgibbs return (error); 50939213Sgibbs} 51039213Sgibbs 51139213Sgibbsstatic int 512130585Sphksaclose(struct cdev *dev, int flag, int fmt, struct thread *td) 51339213Sgibbs{ 51439213Sgibbs struct cam_periph *periph; 51539213Sgibbs struct sa_softc *softc; 516191304Sed int mode, error, writing, tmp; 51742009Smjacob int closedbits = SA_FLAG_OPEN; 51839213Sgibbs 51939213Sgibbs mode = SAMODE(dev); 520101940Snjl periph = (struct cam_periph *)dev->si_drv1; 52139213Sgibbs if (periph == NULL) 52239213Sgibbs return (ENXIO); 52339213Sgibbs 524168752Sscottl cam_periph_lock(periph); 525168752Sscottl 52639213Sgibbs softc = (struct sa_softc *)periph->softc; 52739213Sgibbs 52846962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 529191304Sed ("saclose(%s): softc=0x%x\n", devtoname(dev), softc->flags)); 53046962Smjacob 53146962Smjacob 532154360Smjacob softc->open_rdonly = 0; 53343636Smjacob if (SA_IS_CTRL(dev)) { 53443636Smjacob softc->ctrl_mode = 0; 535168752Sscottl cam_periph_unlock(periph); 53653259Smjacob cam_periph_release(periph); 53743636Smjacob return (0); 53843636Smjacob } 53943636Smjacob 540154360Smjacob if (softc->open_pending_mount) { 541154360Smjacob softc->flags &= ~SA_FLAG_OPEN; 542154360Smjacob softc->open_pending_mount = 0; 543168752Sscottl cam_periph_unlock(periph); 544154360Smjacob cam_periph_release(periph); 545154360Smjacob return (0); 546154360Smjacob } 547154360Smjacob 548168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 549168752Sscottl cam_periph_unlock(periph); 550168752Sscottl return (error); 551168752Sscottl } 552168752Sscottl 55341906Smjacob /* 55446962Smjacob * Were we writing the tape? 55541906Smjacob */ 55646962Smjacob writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0; 55746962Smjacob 55846962Smjacob /* 55946962Smjacob * See whether or not we need to write filemarks. If this 56046962Smjacob * fails, we probably have to assume we've lost tape 56146962Smjacob * position. 56246962Smjacob */ 56341906Smjacob error = sacheckeod(periph); 56441906Smjacob if (error) { 565164906Smjacob xpt_print(periph->path, 566164906Smjacob "failed to write terminating filemark(s)\n"); 56746962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 56841906Smjacob } 56939213Sgibbs 57041906Smjacob /* 57141906Smjacob * Whatever we end up doing, allow users to eject tapes from here on. 57241906Smjacob */ 57339213Sgibbs saprevent(periph, PR_ALLOW); 57439213Sgibbs 57541906Smjacob /* 57641906Smjacob * Decide how to end... 57741906Smjacob */ 57853522Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 57953522Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 58053522Smjacob } else switch (mode) { 58139213Sgibbs case SA_MODE_OFFLINE: 58246962Smjacob /* 58346962Smjacob * An 'offline' close is an unconditional release of 58446962Smjacob * frozen && mount conditions, irrespective of whether 58546962Smjacob * these operations succeeded. The reason for this is 58646962Smjacob * to allow at least some kind of programmatic way 58746962Smjacob * around our state getting all fouled up. If somebody 58846962Smjacob * issues an 'offline' command, that will be allowed 58946962Smjacob * to clear state. 59046962Smjacob */ 59146962Smjacob (void) sarewind(periph); 59246962Smjacob (void) saloadunload(periph, FALSE); 59346962Smjacob closedbits |= SA_FLAG_TAPE_MOUNTED|SA_FLAG_TAPE_FROZEN; 59439213Sgibbs break; 59541906Smjacob case SA_MODE_REWIND: 59646962Smjacob /* 59746962Smjacob * If the rewind fails, return an error- if anyone cares, 59846962Smjacob * but not overwriting any previous error. 59946962Smjacob * 60046962Smjacob * We don't clear the notion of mounted here, but we do 60146962Smjacob * clear the notion of frozen if we successfully rewound. 60246962Smjacob */ 60346962Smjacob tmp = sarewind(periph); 60446962Smjacob if (tmp) { 60546962Smjacob if (error != 0) 60646962Smjacob error = tmp; 60746962Smjacob } else { 60846962Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 60946962Smjacob } 61041906Smjacob break; 61139213Sgibbs case SA_MODE_NOREWIND: 61241906Smjacob /* 61341906Smjacob * If we're not rewinding/unloading the tape, find out 61441906Smjacob * whether we need to back up over one of two filemarks 61541906Smjacob * we wrote (if we wrote two filemarks) so that appends 61641906Smjacob * from this point on will be sane. 61741906Smjacob */ 61846962Smjacob if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) { 61946962Smjacob tmp = saspace(periph, -1, SS_FILEMARKS); 62046962Smjacob if (tmp) { 621164906Smjacob xpt_print(periph->path, "unable to backspace " 622164906Smjacob "over one of double filemarks at end of " 623164906Smjacob "tape\n"); 624164906Smjacob xpt_print(periph->path, "it is possible that " 625164906Smjacob "this device needs a SA_QUIRK_1FM quirk set" 626164906Smjacob "for it\n"); 62746962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 62841906Smjacob } 62941906Smjacob } 63039213Sgibbs break; 63146962Smjacob default: 632164906Smjacob xpt_print(periph->path, "unknown mode 0x%x in saclose\n", mode); 63346962Smjacob /* NOTREACHED */ 63446962Smjacob break; 63539213Sgibbs } 63639213Sgibbs 63741906Smjacob /* 63841948Smjacob * We wish to note here that there are no more filemarks to be written. 63941906Smjacob */ 64041906Smjacob softc->filemarks = 0; 64141948Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 64241906Smjacob 64341906Smjacob /* 64441906Smjacob * And we are no longer open for business. 64541906Smjacob */ 64642009Smjacob softc->flags &= ~closedbits; 64746962Smjacob 64846962Smjacob /* 64946962Smjacob * Inform users if tape state if frozen.... 65046962Smjacob */ 65146962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 652164906Smjacob xpt_print(periph->path, "tape is now frozen- use an OFFLINE, " 653164906Smjacob "REWIND or MTEOM command to clear this state.\n"); 65446962Smjacob } 65539213Sgibbs 65653259Smjacob /* release the device if it is no longer mounted */ 65753259Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) 65853259Smjacob sareservereleaseunit(periph, FALSE); 65939213Sgibbs 660168752Sscottl cam_periph_unhold(periph); 66139213Sgibbs cam_periph_unlock(periph); 66239213Sgibbs cam_periph_release(periph); 66339213Sgibbs 66446962Smjacob return (error); 66539213Sgibbs} 66639213Sgibbs 66739213Sgibbs/* 66839213Sgibbs * Actually translate the requested transfer into one the physical driver 66939213Sgibbs * can understand. The transfer is described by a buf and will include 67039213Sgibbs * only one physical transfer. 67139213Sgibbs */ 67239213Sgibbsstatic void 67359249Sphksastrategy(struct bio *bp) 67439213Sgibbs{ 67539213Sgibbs struct cam_periph *periph; 67639213Sgibbs struct sa_softc *softc; 67739213Sgibbs 67876362Sphk bp->bio_resid = bp->bio_bcount; 67959249Sphk if (SA_IS_CTRL(bp->bio_dev)) { 68076362Sphk biofinish(bp, NULL, EINVAL); 68176362Sphk return; 68243636Smjacob } 683101940Snjl periph = (struct cam_periph *)bp->bio_dev->si_drv1; 68439213Sgibbs if (periph == NULL) { 68576362Sphk biofinish(bp, NULL, ENXIO); 68676362Sphk return; 68739213Sgibbs } 688168752Sscottl cam_periph_lock(periph); 689168752Sscottl 69039213Sgibbs softc = (struct sa_softc *)periph->softc; 69139213Sgibbs 69240603Sken if (softc->flags & SA_FLAG_INVALID) { 693168752Sscottl cam_periph_unlock(periph); 69476362Sphk biofinish(bp, NULL, ENXIO); 69576362Sphk return; 69640603Sken } 69740603Sken 69846962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 699168752Sscottl cam_periph_unlock(periph); 70076362Sphk biofinish(bp, NULL, EPERM); 70176362Sphk return; 70246962Smjacob } 70346962Smjacob 704154360Smjacob /* 705154360Smjacob * This should actually never occur as the write(2) 706154360Smjacob * system call traps attempts to write to a read-only 707154360Smjacob * file descriptor. 708154360Smjacob */ 709154360Smjacob if (bp->bio_cmd == BIO_WRITE && softc->open_rdonly) { 710168752Sscottl cam_periph_unlock(periph); 711154360Smjacob biofinish(bp, NULL, EBADF); 712154360Smjacob return; 713154360Smjacob } 714154360Smjacob 715154360Smjacob if (softc->open_pending_mount) { 716154360Smjacob int error = samount(periph, 0, bp->bio_dev); 717154360Smjacob if (error) { 718168752Sscottl cam_periph_unlock(periph); 719154360Smjacob biofinish(bp, NULL, ENXIO); 720154360Smjacob return; 721154360Smjacob } 722154360Smjacob saprevent(periph, PR_PREVENT); 723154360Smjacob softc->open_pending_mount = 0; 724154360Smjacob } 725154360Smjacob 726154360Smjacob 72739213Sgibbs /* 728154360Smjacob * If it's a null transfer, return immediately 72939213Sgibbs */ 73076362Sphk if (bp->bio_bcount == 0) { 731168752Sscottl cam_periph_unlock(periph); 73276362Sphk biodone(bp); 73376362Sphk return; 73476362Sphk } 73539213Sgibbs 73639213Sgibbs /* valid request? */ 73739213Sgibbs if (softc->flags & SA_FLAG_FIXED) { 73839213Sgibbs /* 73939213Sgibbs * Fixed block device. The byte count must 74039213Sgibbs * be a multiple of our block size. 74139213Sgibbs */ 74242716Smjacob if (((softc->blk_mask != ~0) && 74359249Sphk ((bp->bio_bcount & softc->blk_mask) != 0)) || 74442716Smjacob ((softc->blk_mask == ~0) && 74559249Sphk ((bp->bio_bcount % softc->min_blk) != 0))) { 746164906Smjacob xpt_print(periph->path, "Invalid request. Fixed block " 747164906Smjacob "device requests must be a multiple of %d bytes\n", 748164906Smjacob softc->min_blk); 749168752Sscottl cam_periph_unlock(periph); 75076362Sphk biofinish(bp, NULL, EINVAL); 75176362Sphk return; 75239213Sgibbs } 75359249Sphk } else if ((bp->bio_bcount > softc->max_blk) || 75459249Sphk (bp->bio_bcount < softc->min_blk) || 75559249Sphk (bp->bio_bcount & softc->blk_mask) != 0) { 75639213Sgibbs 75739213Sgibbs xpt_print_path(periph->path); 758164906Smjacob printf("Invalid request. Variable block " 759164906Smjacob "device requests must be "); 76039213Sgibbs if (softc->blk_mask != 0) { 76142716Smjacob printf("a multiple of %d ", (0x1 << softc->blk_gran)); 76239213Sgibbs } 76342716Smjacob printf("between %d and %d bytes\n", softc->min_blk, 76442716Smjacob softc->max_blk); 765168752Sscottl cam_periph_unlock(periph); 76676362Sphk biofinish(bp, NULL, EINVAL); 76776362Sphk return; 76839213Sgibbs } 76939213Sgibbs 77039213Sgibbs /* 77142716Smjacob * Place it at the end of the queue. 77239213Sgibbs */ 77359249Sphk bioq_insert_tail(&softc->bio_queue, bp); 77446962Smjacob softc->queue_count++; 775115660Smjacob#if 0 776115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 777115660Smjacob ("sastrategy: queuing a %ld %s byte %s\n", bp->bio_bcount, 778115660Smjacob (softc->flags & SA_FLAG_FIXED)? "fixed" : "variable", 779115660Smjacob (bp->bio_cmd == BIO_READ)? "read" : "write")); 780115660Smjacob#endif 781115660Smjacob if (softc->queue_count > 1) { 782115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 783115660Smjacob ("sastrategy: queue count now %d\n", softc->queue_count)); 784115660Smjacob } 78539213Sgibbs 78639213Sgibbs /* 78739213Sgibbs * Schedule ourselves for performing the work. 78839213Sgibbs */ 78942716Smjacob xpt_schedule(periph, 1); 790168752Sscottl cam_periph_unlock(periph); 79139213Sgibbs 79239213Sgibbs return; 79339213Sgibbs} 79439213Sgibbs 795154360Smjacob 796154360Smjacob#define PENDING_MOUNT_CHECK(softc, periph, dev) \ 797154360Smjacob if (softc->open_pending_mount) { \ 798154360Smjacob error = samount(periph, 0, dev); \ 799154360Smjacob if (error) { \ 800154360Smjacob break; \ 801154360Smjacob } \ 802154360Smjacob saprevent(periph, PR_PREVENT); \ 803154360Smjacob softc->open_pending_mount = 0; \ 804154360Smjacob } 805154360Smjacob 80639213Sgibbsstatic int 807130585Sphksaioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 80839213Sgibbs{ 80939213Sgibbs struct cam_periph *periph; 81039213Sgibbs struct sa_softc *softc; 81148520Speter scsi_space_code spaceop; 81243636Smjacob int didlockperiph = 0; 81339213Sgibbs int mode; 81453259Smjacob int error = 0; 81539213Sgibbs 81639213Sgibbs mode = SAMODE(dev); 81748520Speter error = 0; /* shut up gcc */ 81848520Speter spaceop = 0; /* shut up gcc */ 81939213Sgibbs 820101940Snjl periph = (struct cam_periph *)dev->si_drv1; 82139213Sgibbs if (periph == NULL) 82239213Sgibbs return (ENXIO); 82339213Sgibbs 824168752Sscottl cam_periph_lock(periph); 82539213Sgibbs softc = (struct sa_softc *)periph->softc; 82639213Sgibbs 82739213Sgibbs /* 82843636Smjacob * Check for control mode accesses. We allow MTIOCGET and 82943636Smjacob * MTIOCERRSTAT (but need to be the only one open in order 83043636Smjacob * to clear latched status), and MTSETBSIZE, MTSETDNSTY 83143636Smjacob * and MTCOMP (but need to be the only one accessing this 83243636Smjacob * device to run those). 83343636Smjacob */ 83443636Smjacob 83543636Smjacob if (SA_IS_CTRL(dev)) { 83643636Smjacob switch (cmd) { 83746962Smjacob case MTIOCGETEOTMODEL: 83843636Smjacob case MTIOCGET: 83943636Smjacob break; 84043636Smjacob case MTIOCERRSTAT: 84143636Smjacob /* 84243636Smjacob * If the periph isn't already locked, lock it 84343636Smjacob * so our MTIOCERRSTAT can reset latched error stats. 84443636Smjacob * 84543636Smjacob * If the periph is already locked, skip it because 84643636Smjacob * we're just getting status and it'll be up to the 84743636Smjacob * other thread that has this device open to do 84843636Smjacob * an MTIOCERRSTAT that would clear latched status. 84943636Smjacob */ 85043636Smjacob if ((periph->flags & CAM_PERIPH_LOCKED) == 0) { 851168752Sscottl error = cam_periph_hold(periph, PRIBIO|PCATCH); 852168752Sscottl if (error != 0) 85343636Smjacob return (error); 85443636Smjacob didlockperiph = 1; 85543636Smjacob } 85643636Smjacob break; 85743636Smjacob 858145050Smjacob case MTIOCTOP: 859145050Smjacob { 860145050Smjacob struct mtop *mt = (struct mtop *) arg; 861145050Smjacob 862145050Smjacob /* 863145050Smjacob * Check to make sure it's an OP we can perform 864145050Smjacob * with no media inserted. 865145050Smjacob */ 866145050Smjacob switch (mt->mt_op) { 867145050Smjacob case MTSETBSIZ: 868145050Smjacob case MTSETDNSTY: 869145050Smjacob case MTCOMP: 870145050Smjacob mt = NULL; 871145050Smjacob /* FALLTHROUGH */ 872145050Smjacob default: 873145050Smjacob break; 874145050Smjacob } 875145050Smjacob if (mt != NULL) { 876145050Smjacob break; 877145050Smjacob } 878145050Smjacob /* FALLTHROUGH */ 879145050Smjacob } 88046962Smjacob case MTIOCSETEOTMODEL: 88143636Smjacob /* 88243636Smjacob * We need to acquire the peripheral here rather 88343636Smjacob * than at open time because we are sharing writable 88443636Smjacob * access to data structures. 88543636Smjacob */ 886168752Sscottl error = cam_periph_hold(periph, PRIBIO|PCATCH); 887168752Sscottl if (error != 0) 88843636Smjacob return (error); 88943636Smjacob didlockperiph = 1; 89043636Smjacob break; 89143636Smjacob 89243636Smjacob default: 89343636Smjacob return (EINVAL); 89443636Smjacob } 89543636Smjacob } 89643636Smjacob 89743636Smjacob /* 89839213Sgibbs * Find the device that the user is talking about 89939213Sgibbs */ 90039213Sgibbs switch (cmd) { 90139213Sgibbs case MTIOCGET: 90239213Sgibbs { 90339213Sgibbs struct mtget *g = (struct mtget *)arg; 90439213Sgibbs 90553259Smjacob /* 90653259Smjacob * If this isn't the control mode device, actually go out 90753259Smjacob * and ask the drive again what it's set to. 90853259Smjacob */ 909154360Smjacob if (!SA_IS_CTRL(dev) && !softc->open_pending_mount) { 91053259Smjacob u_int8_t write_protect; 91153259Smjacob int comp_enabled, comp_supported; 91253259Smjacob error = sagetparams(periph, SA_PARAM_ALL, 91353259Smjacob &softc->media_blksize, &softc->media_density, 91453259Smjacob &softc->media_numblks, &softc->buffer_mode, 91553259Smjacob &write_protect, &softc->speed, &comp_supported, 91653259Smjacob &comp_enabled, &softc->comp_algorithm, NULL); 91753259Smjacob if (error) 91853259Smjacob break; 91953259Smjacob if (write_protect) 92053259Smjacob softc->flags |= SA_FLAG_TAPE_WP; 92153259Smjacob else 92253259Smjacob softc->flags &= ~SA_FLAG_TAPE_WP; 92353259Smjacob softc->flags &= ~(SA_FLAG_COMP_SUPP| 92453259Smjacob SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP); 92553259Smjacob if (comp_supported) { 92653259Smjacob if (softc->saved_comp_algorithm == 0) 92753259Smjacob softc->saved_comp_algorithm = 92853259Smjacob softc->comp_algorithm; 92953259Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 93053259Smjacob if (comp_enabled) 93153259Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 93253259Smjacob } else 93353259Smjacob softc->flags |= SA_FLAG_COMP_UNSUPP; 93453259Smjacob } 93539213Sgibbs bzero(g, sizeof(struct mtget)); 93641948Smjacob g->mt_type = MT_ISAR; 93739213Sgibbs if (softc->flags & SA_FLAG_COMP_UNSUPP) { 93839213Sgibbs g->mt_comp = MT_COMP_UNSUPP; 93939213Sgibbs g->mt_comp0 = MT_COMP_UNSUPP; 94039213Sgibbs g->mt_comp1 = MT_COMP_UNSUPP; 94139213Sgibbs g->mt_comp2 = MT_COMP_UNSUPP; 94239213Sgibbs g->mt_comp3 = MT_COMP_UNSUPP; 94339213Sgibbs } else { 94446962Smjacob if ((softc->flags & SA_FLAG_COMP_ENABLED) == 0) { 94546962Smjacob g->mt_comp = MT_COMP_DISABLED; 94646962Smjacob } else { 94746962Smjacob g->mt_comp = softc->comp_algorithm; 94846962Smjacob } 94939213Sgibbs g->mt_comp0 = softc->comp_algorithm; 95039213Sgibbs g->mt_comp1 = softc->comp_algorithm; 95139213Sgibbs g->mt_comp2 = softc->comp_algorithm; 95239213Sgibbs g->mt_comp3 = softc->comp_algorithm; 95339213Sgibbs } 95446962Smjacob g->mt_density = softc->media_density; 95539213Sgibbs g->mt_density0 = softc->media_density; 95639213Sgibbs g->mt_density1 = softc->media_density; 95739213Sgibbs g->mt_density2 = softc->media_density; 95839213Sgibbs g->mt_density3 = softc->media_density; 95946962Smjacob g->mt_blksiz = softc->media_blksize; 96039213Sgibbs g->mt_blksiz0 = softc->media_blksize; 96139213Sgibbs g->mt_blksiz1 = softc->media_blksize; 96239213Sgibbs g->mt_blksiz2 = softc->media_blksize; 96339213Sgibbs g->mt_blksiz3 = softc->media_blksize; 96443636Smjacob g->mt_fileno = softc->fileno; 96543636Smjacob g->mt_blkno = softc->blkno; 96643636Smjacob g->mt_dsreg = (short) softc->dsreg; 96771268Smjacob /* 96871268Smjacob * Yes, we know that this is likely to overflow 96971268Smjacob */ 97071268Smjacob if (softc->last_resid_was_io) { 97171268Smjacob if ((g->mt_resid = (short) softc->last_io_resid) != 0) { 97271268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 97371268Smjacob softc->last_io_resid = 0; 97471268Smjacob } 97571268Smjacob } 97671268Smjacob } else { 97771268Smjacob if ((g->mt_resid = (short)softc->last_ctl_resid) != 0) { 97871268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 97971268Smjacob softc->last_ctl_resid = 0; 98071268Smjacob } 98171268Smjacob } 98271268Smjacob } 98339213Sgibbs error = 0; 98439213Sgibbs break; 98539213Sgibbs } 98641948Smjacob case MTIOCERRSTAT: 98741948Smjacob { 98841948Smjacob struct scsi_tape_errors *sep = 98941948Smjacob &((union mterrstat *)arg)->scsi_errstat; 99041948Smjacob 99141948Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 99241948Smjacob ("saioctl: MTIOCERRSTAT\n")); 99341948Smjacob 99441948Smjacob bzero(sep, sizeof(*sep)); 99541948Smjacob sep->io_resid = softc->last_io_resid; 99641948Smjacob bcopy((caddr_t) &softc->last_io_sense, sep->io_sense, 99741948Smjacob sizeof (sep->io_sense)); 99842009Smjacob bcopy((caddr_t) &softc->last_io_cdb, sep->io_cdb, 99942009Smjacob sizeof (sep->io_cdb)); 100042009Smjacob sep->ctl_resid = softc->last_ctl_resid; 100141948Smjacob bcopy((caddr_t) &softc->last_ctl_sense, sep->ctl_sense, 100241948Smjacob sizeof (sep->ctl_sense)); 100342009Smjacob bcopy((caddr_t) &softc->last_ctl_cdb, sep->ctl_cdb, 100442009Smjacob sizeof (sep->ctl_cdb)); 100543636Smjacob 1006154360Smjacob if ((SA_IS_CTRL(dev) == 0 && softc->open_pending_mount) || 1007154360Smjacob didlockperiph) 100843636Smjacob bzero((caddr_t) &softc->errinfo, 100943636Smjacob sizeof (softc->errinfo)); 101041948Smjacob error = 0; 101141948Smjacob break; 101241948Smjacob } 101339213Sgibbs case MTIOCTOP: 101439213Sgibbs { 101539213Sgibbs struct mtop *mt; 101639213Sgibbs int count; 101739213Sgibbs 1018154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1019154360Smjacob 102039213Sgibbs mt = (struct mtop *)arg; 102139213Sgibbs 1022154360Smjacob 102339213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 102439213Sgibbs ("saioctl: op=0x%x count=0x%x\n", 102539213Sgibbs mt->mt_op, mt->mt_count)); 102639213Sgibbs 102739213Sgibbs count = mt->mt_count; 102839213Sgibbs switch (mt->mt_op) { 102941906Smjacob case MTWEOF: /* write an end-of-file marker */ 103068114Smjacob /* 103168114Smjacob * We don't need to clear the SA_FLAG_TAPE_WRITTEN 103268114Smjacob * flag because by keeping track of filemarks 103368114Smjacob * we have last written we know ehether or not 103468114Smjacob * we need to write more when we close the device. 103568114Smjacob */ 103641906Smjacob error = sawritefilemarks(periph, count, FALSE); 103739213Sgibbs break; 103842009Smjacob case MTWSS: /* write a setmark */ 103942009Smjacob error = sawritefilemarks(periph, count, TRUE); 104042009Smjacob break; 104139213Sgibbs case MTBSR: /* backward space record */ 104239213Sgibbs case MTFSR: /* forward space record */ 104339213Sgibbs case MTBSF: /* backward space file */ 104439213Sgibbs case MTFSF: /* forward space file */ 104542009Smjacob case MTBSS: /* backward space setmark */ 104642009Smjacob case MTFSS: /* forward space setmark */ 104739213Sgibbs case MTEOD: /* space to end of recorded medium */ 104839213Sgibbs { 104939213Sgibbs int nmarks; 105039213Sgibbs 105148520Speter spaceop = SS_FILEMARKS; 105239213Sgibbs nmarks = softc->filemarks; 105339213Sgibbs error = sacheckeod(periph); 105441906Smjacob if (error) { 1055164906Smjacob xpt_print(periph->path, 1056164906Smjacob "EOD check prior to spacing failed\n"); 105741906Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 105841906Smjacob break; 105941906Smjacob } 106039213Sgibbs nmarks -= softc->filemarks; 106142009Smjacob switch(mt->mt_op) { 106242009Smjacob case MTBSR: 106339213Sgibbs count = -count; 106442009Smjacob /* FALLTHROUGH */ 106542009Smjacob case MTFSR: 106639213Sgibbs spaceop = SS_BLOCKS; 106742009Smjacob break; 106842009Smjacob case MTBSF: 106942009Smjacob count = -count; 107042009Smjacob /* FALLTHROUGH */ 107142009Smjacob case MTFSF: 107242009Smjacob break; 107342009Smjacob case MTBSS: 107442009Smjacob count = -count; 107542009Smjacob /* FALLTHROUGH */ 107642009Smjacob case MTFSS: 107742009Smjacob spaceop = SS_SETMARKS; 107842009Smjacob break; 107942009Smjacob case MTEOD: 108039213Sgibbs spaceop = SS_EOD; 108139213Sgibbs count = 0; 108239213Sgibbs nmarks = 0; 108342009Smjacob break; 108442009Smjacob default: 108542009Smjacob error = EINVAL; 108642009Smjacob break; 108739213Sgibbs } 108842009Smjacob if (error) 108942009Smjacob break; 109039213Sgibbs 109139213Sgibbs nmarks = softc->filemarks; 109242009Smjacob /* 109342009Smjacob * XXX: Why are we checking again? 109442009Smjacob */ 109539213Sgibbs error = sacheckeod(periph); 109642009Smjacob if (error) 109742009Smjacob break; 109839213Sgibbs nmarks -= softc->filemarks; 109942009Smjacob error = saspace(periph, count - nmarks, spaceop); 110041906Smjacob /* 110141906Smjacob * At this point, clear that we've written the tape 110241906Smjacob * and that we've written any filemarks. We really 110341906Smjacob * don't know what the applications wishes to do next- 110441906Smjacob * the sacheckeod's will make sure we terminated the 110541906Smjacob * tape correctly if we'd been writing, but the next 110641906Smjacob * action the user application takes will set again 110741906Smjacob * whether we need to write filemarks. 110841906Smjacob */ 110946962Smjacob softc->flags &= 111046962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 111141906Smjacob softc->filemarks = 0; 111239213Sgibbs break; 111339213Sgibbs } 111439213Sgibbs case MTREW: /* rewind */ 1115154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 111641906Smjacob (void) sacheckeod(periph); 111739213Sgibbs error = sarewind(periph); 111841906Smjacob /* see above */ 111942009Smjacob softc->flags &= 112046962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 112182575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 112241906Smjacob softc->filemarks = 0; 112339213Sgibbs break; 112439213Sgibbs case MTERASE: /* erase */ 1125154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 112639213Sgibbs error = saerase(periph, count); 112746962Smjacob softc->flags &= 112846962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 112982575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 113039213Sgibbs break; 113139213Sgibbs case MTRETENS: /* re-tension tape */ 1132154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 113339213Sgibbs error = saretension(periph); 113446962Smjacob softc->flags &= 113546962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 113682575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 113739213Sgibbs break; 113839213Sgibbs case MTOFFL: /* rewind and put the drive offline */ 113941906Smjacob 1140154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1141154360Smjacob 114241906Smjacob (void) sacheckeod(periph); 114341906Smjacob /* see above */ 114441906Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 114541906Smjacob softc->filemarks = 0; 114641906Smjacob 114746962Smjacob error = sarewind(periph); 114853522Smjacob /* clear the frozen flag anyway */ 114953522Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 115046962Smjacob 115139213Sgibbs /* 115253522Smjacob * Be sure to allow media removal before ejecting. 115339213Sgibbs */ 115446962Smjacob 115539213Sgibbs saprevent(periph, PR_ALLOW); 115653522Smjacob if (error == 0) { 115743636Smjacob error = saloadunload(periph, FALSE); 115853522Smjacob if (error == 0) { 115953522Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 116053522Smjacob } 116153522Smjacob } 116246962Smjacob break; 116339213Sgibbs 116439213Sgibbs case MTNOP: /* no operation, sets status only */ 116539213Sgibbs case MTCACHE: /* enable controller cache */ 116639213Sgibbs case MTNOCACHE: /* disable controller cache */ 116739213Sgibbs error = 0; 116839213Sgibbs break; 116946962Smjacob 117039213Sgibbs case MTSETBSIZ: /* Set block size for device */ 117139213Sgibbs 1172154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1173154360Smjacob 117439213Sgibbs error = sasetparams(periph, SA_PARAM_BLOCKSIZE, count, 117542563Smjacob 0, 0, 0); 117641674Smjacob if (error == 0) { 117741906Smjacob softc->last_media_blksize = 117841906Smjacob softc->media_blksize; 117941674Smjacob softc->media_blksize = count; 118041674Smjacob if (count) { 118141674Smjacob softc->flags |= SA_FLAG_FIXED; 118241674Smjacob if (powerof2(count)) { 118341674Smjacob softc->blk_shift = 118441674Smjacob ffs(count) - 1; 118541674Smjacob softc->blk_mask = count - 1; 118641674Smjacob } else { 118741674Smjacob softc->blk_mask = ~0; 118841674Smjacob softc->blk_shift = 0; 118941674Smjacob } 119041906Smjacob /* 119141906Smjacob * Make the user's desire 'persistent'. 119241906Smjacob */ 119341906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 119441906Smjacob softc->quirks |= SA_QUIRK_FIXED; 119541674Smjacob } else { 119641674Smjacob softc->flags &= ~SA_FLAG_FIXED; 119741674Smjacob if (softc->max_blk == 0) { 119841674Smjacob softc->max_blk = ~0; 119941674Smjacob } 120041674Smjacob softc->blk_shift = 0; 120141674Smjacob if (softc->blk_gran != 0) { 120241674Smjacob softc->blk_mask = 120341674Smjacob softc->blk_gran - 1; 120441674Smjacob } else { 120541674Smjacob softc->blk_mask = 0; 120641674Smjacob } 120741906Smjacob /* 120841906Smjacob * Make the user's desire 'persistent'. 120941906Smjacob */ 121041906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 121141906Smjacob softc->quirks &= ~SA_QUIRK_FIXED; 121241674Smjacob } 121341674Smjacob } 121439213Sgibbs break; 121539213Sgibbs case MTSETDNSTY: /* Set density for device and mode */ 1216154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1217154360Smjacob 121839213Sgibbs if (count > UCHAR_MAX) { 121939213Sgibbs error = EINVAL; 122039213Sgibbs break; 122139213Sgibbs } else { 122239213Sgibbs error = sasetparams(periph, SA_PARAM_DENSITY, 122342563Smjacob 0, count, 0, 0); 122439213Sgibbs } 122539213Sgibbs break; 122639213Sgibbs case MTCOMP: /* enable compression */ 1227154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 122839213Sgibbs /* 122939213Sgibbs * Some devices don't support compression, and 123039213Sgibbs * don't like it if you ask them for the 123139213Sgibbs * compression page. 123239213Sgibbs */ 123343636Smjacob if ((softc->quirks & SA_QUIRK_NOCOMP) || 123443636Smjacob (softc->flags & SA_FLAG_COMP_UNSUPP)) { 123539213Sgibbs error = ENODEV; 123639213Sgibbs break; 123739213Sgibbs } 123839213Sgibbs error = sasetparams(periph, SA_PARAM_COMPRESSION, 123954099Smjacob 0, 0, count, SF_NO_PRINT); 124039213Sgibbs break; 124139213Sgibbs default: 124239213Sgibbs error = EINVAL; 124339213Sgibbs } 124439213Sgibbs break; 124539213Sgibbs } 124639213Sgibbs case MTIOCIEOT: 124739213Sgibbs case MTIOCEEOT: 124839213Sgibbs error = 0; 124939213Sgibbs break; 125041918Smjacob case MTIOCRDSPOS: 1251154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 125241918Smjacob error = sardpos(periph, 0, (u_int32_t *) arg); 125341918Smjacob break; 125441918Smjacob case MTIOCRDHPOS: 1255154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 125641918Smjacob error = sardpos(periph, 1, (u_int32_t *) arg); 125741918Smjacob break; 125841918Smjacob case MTIOCSLOCATE: 1259154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 126041918Smjacob error = sasetpos(periph, 0, (u_int32_t *) arg); 126141918Smjacob break; 126241918Smjacob case MTIOCHLOCATE: 1263154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 126441918Smjacob error = sasetpos(periph, 1, (u_int32_t *) arg); 126541918Smjacob break; 126646962Smjacob case MTIOCGETEOTMODEL: 126746962Smjacob error = 0; 126846962Smjacob if (softc->quirks & SA_QUIRK_1FM) 126946962Smjacob mode = 1; 127046962Smjacob else 127146962Smjacob mode = 2; 127246962Smjacob *((u_int32_t *) arg) = mode; 127346962Smjacob break; 127446962Smjacob case MTIOCSETEOTMODEL: 127546962Smjacob error = 0; 127646962Smjacob switch (*((u_int32_t *) arg)) { 127746962Smjacob case 1: 127846962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 127946962Smjacob softc->quirks |= SA_QUIRK_1FM; 128046962Smjacob break; 128146962Smjacob case 2: 128246962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 128346962Smjacob softc->quirks |= SA_QUIRK_2FM; 128446962Smjacob break; 128546962Smjacob default: 128646962Smjacob error = EINVAL; 128746962Smjacob break; 128846962Smjacob } 128946962Smjacob break; 129039213Sgibbs default: 129139213Sgibbs error = cam_periph_ioctl(periph, cmd, arg, saerror); 129239213Sgibbs break; 129339213Sgibbs } 129471268Smjacob 129571268Smjacob /* 129671268Smjacob * Check to see if we cleared a frozen state 129771268Smjacob */ 129871268Smjacob if (error == 0 && (softc->flags & SA_FLAG_TAPE_FROZEN)) { 129971268Smjacob switch(cmd) { 130071268Smjacob case MTIOCRDSPOS: 130171268Smjacob case MTIOCRDHPOS: 130271268Smjacob case MTIOCSLOCATE: 130371268Smjacob case MTIOCHLOCATE: 130471268Smjacob softc->fileno = (daddr_t) -1; 130571268Smjacob softc->blkno = (daddr_t) -1; 130671268Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 1307164906Smjacob xpt_print(periph->path, 1308164906Smjacob "tape state now unfrozen.\n"); 130971268Smjacob break; 131071268Smjacob default: 131171268Smjacob break; 131271268Smjacob } 131371268Smjacob } 131443636Smjacob if (didlockperiph) { 1315168752Sscottl cam_periph_unhold(periph); 131643636Smjacob } 1317168752Sscottl cam_periph_unlock(periph); 131839213Sgibbs return (error); 131939213Sgibbs} 132039213Sgibbs 132139213Sgibbsstatic void 132239213Sgibbssainit(void) 132339213Sgibbs{ 132439213Sgibbs cam_status status; 132539213Sgibbs 132639213Sgibbs /* 132739213Sgibbs * Install a global async callback. 132839213Sgibbs */ 1329169605Sscottl status = xpt_register_async(AC_FOUND_DEVICE, saasync, NULL, NULL); 133039213Sgibbs 133139213Sgibbs if (status != CAM_REQ_CMP) { 133239213Sgibbs printf("sa: Failed to attach master async callback " 133339213Sgibbs "due to status 0x%x!\n", status); 133439213Sgibbs } 133539213Sgibbs} 133639213Sgibbs 133739213Sgibbsstatic void 133840603Skensaoninvalidate(struct cam_periph *periph) 133940603Sken{ 134040603Sken struct sa_softc *softc; 134140603Sken 134240603Sken softc = (struct sa_softc *)periph->softc; 134340603Sken 134440603Sken /* 134540603Sken * De-register any async callbacks. 134640603Sken */ 1347169605Sscottl xpt_register_async(0, saasync, periph, periph->path); 134840603Sken 134940603Sken softc->flags |= SA_FLAG_INVALID; 135040603Sken 135140603Sken /* 135240603Sken * Return all queued I/O with ENXIO. 135340603Sken * XXX Handle any transactions queued to the card 135440603Sken * with XPT_ABORT_CCB. 135540603Sken */ 1356112946Sphk bioq_flush(&softc->bio_queue, NULL, ENXIO); 135746962Smjacob softc->queue_count = 0; 135840603Sken 1359164906Smjacob xpt_print(periph->path, "lost device\n"); 136040603Sken 136140603Sken} 136240603Sken 136340603Skenstatic void 136439213Sgibbssacleanup(struct cam_periph *periph) 136539213Sgibbs{ 136640603Sken struct sa_softc *softc; 136753259Smjacob int i; 136840603Sken 136940603Sken softc = (struct sa_softc *)periph->softc; 137040603Sken 1371187028Strasz xpt_print(periph->path, "removing device entry\n"); 1372112006Sphk devstat_remove_entry(softc->device_stats); 1373187028Strasz cam_periph_unlock(periph); 137453259Smjacob destroy_dev(softc->devs.ctl_dev); 137553259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 137653259Smjacob destroy_dev(softc->devs.mode_devs[i].r_dev); 137753259Smjacob destroy_dev(softc->devs.mode_devs[i].nr_dev); 137853259Smjacob destroy_dev(softc->devs.mode_devs[i].er_dev); 137953259Smjacob } 1380187028Strasz cam_periph_lock(periph); 1381147723Savatar free(softc, M_SCSISA); 138239213Sgibbs} 138339213Sgibbs 138439213Sgibbsstatic void 138539213Sgibbssaasync(void *callback_arg, u_int32_t code, 138639213Sgibbs struct cam_path *path, void *arg) 138739213Sgibbs{ 138839213Sgibbs struct cam_periph *periph; 138939213Sgibbs 139039213Sgibbs periph = (struct cam_periph *)callback_arg; 139139213Sgibbs switch (code) { 139239213Sgibbs case AC_FOUND_DEVICE: 139339213Sgibbs { 139439213Sgibbs struct ccb_getdev *cgd; 139539213Sgibbs cam_status status; 139639213Sgibbs 139739213Sgibbs cgd = (struct ccb_getdev *)arg; 139879177Smjacob if (cgd == NULL) 139979177Smjacob break; 140039213Sgibbs 1401195534Sscottl if (cgd->protocol != PROTO_SCSI) 1402195534Sscottl break; 1403195534Sscottl 140456148Smjacob if (SID_TYPE(&cgd->inq_data) != T_SEQUENTIAL) 140539213Sgibbs break; 140639213Sgibbs 140739213Sgibbs /* 140839213Sgibbs * Allocate a peripheral instance for 140939213Sgibbs * this device and start the probe 141039213Sgibbs * process. 141139213Sgibbs */ 141240603Sken status = cam_periph_alloc(saregister, saoninvalidate, 141340603Sken sacleanup, sastart, 141439213Sgibbs "sa", CAM_PERIPH_BIO, cgd->ccb_h.path, 141539213Sgibbs saasync, AC_FOUND_DEVICE, cgd); 141639213Sgibbs 141739213Sgibbs if (status != CAM_REQ_CMP 141839213Sgibbs && status != CAM_REQ_INPROG) 141939213Sgibbs printf("saasync: Unable to probe new device " 142039213Sgibbs "due to status 0x%x\n", status); 142139213Sgibbs break; 142239213Sgibbs } 142339213Sgibbs default: 142447413Sgibbs cam_periph_async(periph, code, path, arg); 142539213Sgibbs break; 142639213Sgibbs } 142739213Sgibbs} 142839213Sgibbs 142939213Sgibbsstatic cam_status 143039213Sgibbssaregister(struct cam_periph *periph, void *arg) 143139213Sgibbs{ 143239213Sgibbs struct sa_softc *softc; 143339213Sgibbs struct ccb_getdev *cgd; 143439213Sgibbs caddr_t match; 143553259Smjacob int i; 143639213Sgibbs 143739213Sgibbs cgd = (struct ccb_getdev *)arg; 143839213Sgibbs if (periph == NULL) { 143939213Sgibbs printf("saregister: periph was NULL!!\n"); 144054099Smjacob return (CAM_REQ_CMP_ERR); 144139213Sgibbs } 144239213Sgibbs 144339213Sgibbs if (cgd == NULL) { 144439213Sgibbs printf("saregister: no getdev CCB, can't register device\n"); 144554099Smjacob return (CAM_REQ_CMP_ERR); 144639213Sgibbs } 144739213Sgibbs 144867723Smjacob softc = (struct sa_softc *) 1449147723Savatar malloc(sizeof (*softc), M_SCSISA, M_NOWAIT | M_ZERO); 145039213Sgibbs if (softc == NULL) { 145139213Sgibbs printf("saregister: Unable to probe new device. " 145239213Sgibbs "Unable to allocate softc\n"); 145354099Smjacob return (CAM_REQ_CMP_ERR); 145439213Sgibbs } 145541674Smjacob softc->scsi_rev = SID_ANSI_REV(&cgd->inq_data); 145639213Sgibbs softc->state = SA_STATE_NORMAL; 145743636Smjacob softc->fileno = (daddr_t) -1; 145843636Smjacob softc->blkno = (daddr_t) -1; 145943636Smjacob 146059249Sphk bioq_init(&softc->bio_queue); 146139213Sgibbs periph->softc = softc; 146239213Sgibbs 146339213Sgibbs /* 146439213Sgibbs * See if this device has any quirks. 146539213Sgibbs */ 146639213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 146739213Sgibbs (caddr_t)sa_quirk_table, 146839213Sgibbs sizeof(sa_quirk_table)/sizeof(*sa_quirk_table), 146939213Sgibbs sizeof(*sa_quirk_table), scsi_inquiry_match); 147039213Sgibbs 147142563Smjacob if (match != NULL) { 147239213Sgibbs softc->quirks = ((struct sa_quirk_entry *)match)->quirks; 147342563Smjacob softc->last_media_blksize = 147442563Smjacob ((struct sa_quirk_entry *)match)->prefblk; 147542563Smjacob#ifdef CAMDEBUG 1476164906Smjacob xpt_print(periph->path, "found quirk entry %d\n", 1477164906Smjacob (int) (((struct sa_quirk_entry *) match) - sa_quirk_table)); 147842563Smjacob#endif 147942563Smjacob } else 148039213Sgibbs softc->quirks = SA_QUIRK_NONE; 148139213Sgibbs 148239213Sgibbs /* 148339213Sgibbs * The SA driver supports a blocksize, but we don't know the 148446962Smjacob * blocksize until we media is inserted. So, set a flag to 148539213Sgibbs * indicate that the blocksize is unavailable right now. 148639213Sgibbs */ 1487169605Sscottl cam_periph_unlock(periph); 1488112006Sphk softc->device_stats = devstat_new_entry("sa", periph->unit_number, 0, 148956148Smjacob DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) | 149056148Smjacob DEVSTAT_TYPE_IF_SCSI, DEVSTAT_PRIORITY_TAPE); 149153259Smjacob 149253259Smjacob softc->devs.ctl_dev = make_dev(&sa_cdevsw, SAMINOR(SA_CTLDEV, 1493191304Sed 0, SA_ATYPE_R), UID_ROOT, GID_OPERATOR, 149472804Smjacob 0660, "%s%d.ctl", periph->periph_name, periph->unit_number); 1495101940Snjl softc->devs.ctl_dev->si_drv1 = periph; 149653259Smjacob 149753259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 149853283Smjacob 149953259Smjacob softc->devs.mode_devs[i].r_dev = make_dev(&sa_cdevsw, 1500191304Sed SAMINOR(SA_NOT_CTLDEV, i, SA_ATYPE_R), 150172804Smjacob UID_ROOT, GID_OPERATOR, 0660, "%s%d.%d", 150253259Smjacob periph->periph_name, periph->unit_number, i); 1503101940Snjl softc->devs.mode_devs[i].r_dev->si_drv1 = periph; 150453283Smjacob 150553259Smjacob softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw, 1506191304Sed SAMINOR(SA_NOT_CTLDEV, i, SA_ATYPE_NR), 150772804Smjacob UID_ROOT, GID_OPERATOR, 0660, "n%s%d.%d", 150853259Smjacob periph->periph_name, periph->unit_number, i); 1509101940Snjl softc->devs.mode_devs[i].nr_dev->si_drv1 = periph; 151053259Smjacob 151153283Smjacob softc->devs.mode_devs[i].er_dev = make_dev(&sa_cdevsw, 1512191304Sed SAMINOR(SA_NOT_CTLDEV, i, SA_ATYPE_ER), 151372804Smjacob UID_ROOT, GID_OPERATOR, 0660, "e%s%d.%d", 151453259Smjacob periph->periph_name, periph->unit_number, i); 1515101940Snjl softc->devs.mode_devs[i].er_dev->si_drv1 = periph; 151665838Smjacob 151765838Smjacob /* 151865838Smjacob * Make the (well known) aliases for the first mode. 151965838Smjacob */ 152065838Smjacob if (i == 0) { 1521130585Sphk struct cdev *alias; 1522101940Snjl 1523101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].r_dev, 152472804Smjacob "%s%d", periph->periph_name, periph->unit_number); 1525101940Snjl alias->si_drv1 = periph; 1526101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].nr_dev, 152772804Smjacob "n%s%d", periph->periph_name, periph->unit_number); 1528101940Snjl alias->si_drv1 = periph; 1529101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].er_dev, 153072804Smjacob "e%s%d", periph->periph_name, periph->unit_number); 1531101940Snjl alias->si_drv1 = periph; 153265838Smjacob } 153353259Smjacob } 1534168872Sscottl cam_periph_lock(periph); 153553259Smjacob 153639213Sgibbs /* 153739213Sgibbs * Add an async callback so that we get 153839213Sgibbs * notified if this device goes away. 153939213Sgibbs */ 1540169605Sscottl xpt_register_async(AC_LOST_DEVICE, saasync, periph, periph->path); 154139213Sgibbs 154239213Sgibbs xpt_announce_periph(periph, NULL); 154339213Sgibbs 154454099Smjacob return (CAM_REQ_CMP); 154539213Sgibbs} 154639213Sgibbs 154739213Sgibbsstatic void 154839213Sgibbssastart(struct cam_periph *periph, union ccb *start_ccb) 154939213Sgibbs{ 155039213Sgibbs struct sa_softc *softc; 155139213Sgibbs 155239213Sgibbs softc = (struct sa_softc *)periph->softc; 155339213Sgibbs 1554115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sastart\n")); 155571082Smjacob 155639213Sgibbs 155739213Sgibbs switch (softc->state) { 155839213Sgibbs case SA_STATE_NORMAL: 155939213Sgibbs { 156039213Sgibbs /* Pull a buffer from the queue and get going on it */ 156159249Sphk struct bio *bp; 156239213Sgibbs 156339213Sgibbs /* 156439213Sgibbs * See if there is a buf with work for us to do.. 156539213Sgibbs */ 156659249Sphk bp = bioq_first(&softc->bio_queue); 156739213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 156839213Sgibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 156939213Sgibbs ("queuing for immediate ccb\n")); 157071082Smjacob Set_CCB_Type(start_ccb, SA_CCB_WAITING); 157139213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 157239213Sgibbs periph_links.sle); 157339213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 157439213Sgibbs wakeup(&periph->ccb_list); 157539213Sgibbs } else if (bp == NULL) { 157639213Sgibbs xpt_release_ccb(start_ccb); 157739213Sgibbs } else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) { 157859249Sphk struct bio *done_bp; 157982575Smjacobagain: 158046962Smjacob softc->queue_count--; 158159249Sphk bioq_remove(&softc->bio_queue, bp); 158259249Sphk bp->bio_resid = bp->bio_bcount; 158382575Smjacob done_bp = bp; 158439213Sgibbs if ((softc->flags & SA_FLAG_EOM_PENDING) != 0) { 158582575Smjacob /* 158682575Smjacob * We now just clear errors in this case 158782575Smjacob * and let the residual be the notifier. 158882575Smjacob */ 158982575Smjacob bp->bio_error = 0; 159082575Smjacob } else if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) { 159182575Smjacob /* 159282575Smjacob * This can only happen if we're reading 159382575Smjacob * in fixed length mode. In this case, 159482575Smjacob * we dump the rest of the list the 159582575Smjacob * same way. 159682575Smjacob */ 159782575Smjacob bp->bio_error = 0; 159882575Smjacob if (bioq_first(&softc->bio_queue) != NULL) { 159982575Smjacob biodone(done_bp); 160082575Smjacob goto again; 160182575Smjacob } 160282575Smjacob } else if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) { 160359249Sphk bp->bio_error = EIO; 160482575Smjacob bp->bio_flags |= BIO_ERROR; 160541948Smjacob } 160659249Sphk bp = bioq_first(&softc->bio_queue); 160744354Smjacob /* 160844354Smjacob * Only if we have no other buffers queued up 160944354Smjacob * do we clear the pending error flag. 161044354Smjacob */ 161144354Smjacob if (bp == NULL) 161244354Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 161344354Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 161446962Smjacob ("sastart- ERR_PENDING now 0x%x, bp is %sNULL, " 161546962Smjacob "%d more buffers queued up\n", 161644354Smjacob (softc->flags & SA_FLAG_ERR_PENDING), 161746962Smjacob (bp != NULL)? "not " : " ", softc->queue_count)); 161844354Smjacob xpt_release_ccb(start_ccb); 161941948Smjacob biodone(done_bp); 162039213Sgibbs } else { 162139213Sgibbs u_int32_t length; 162239213Sgibbs 162359249Sphk bioq_remove(&softc->bio_queue, bp); 162446962Smjacob softc->queue_count--; 162539213Sgibbs 162639213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) { 162739213Sgibbs if (softc->blk_shift != 0) { 162839213Sgibbs length = 162959249Sphk bp->bio_bcount >> softc->blk_shift; 163043636Smjacob } else if (softc->media_blksize != 0) { 163171082Smjacob length = bp->bio_bcount / 163271082Smjacob softc->media_blksize; 163343636Smjacob } else { 163459249Sphk bp->bio_error = EIO; 1635164906Smjacob xpt_print(periph->path, "zero blocksize" 1636164906Smjacob " for FIXED length writes?\n"); 163743636Smjacob biodone(bp); 163843636Smjacob break; 163939213Sgibbs } 1640115660Smjacob#if 0 1641115660Smjacob CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 1642115660Smjacob ("issuing a %d fixed record %s\n", 1643115660Smjacob length, (bp->bio_cmd == BIO_READ)? "read" : 1644115660Smjacob "write")); 1645115660Smjacob#endif 164639213Sgibbs } else { 164759249Sphk length = bp->bio_bcount; 1648115660Smjacob#if 0 164941906Smjacob CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 1650115660Smjacob ("issuing a %d variable byte %s\n", 1651115660Smjacob length, (bp->bio_cmd == BIO_READ)? "read" : 1652115660Smjacob "write")); 1653115660Smjacob#endif 165439213Sgibbs } 1655112260Sphk devstat_start_transaction_bio(softc->device_stats, bp); 165639213Sgibbs /* 165741906Smjacob * Some people have theorized that we should 165839213Sgibbs * suppress illegal length indication if we are 165939213Sgibbs * running in variable block mode so that we don't 166039213Sgibbs * have to request sense every time our requested 166139213Sgibbs * block size is larger than the written block. 166239213Sgibbs * The residual information from the ccb allows 166339213Sgibbs * us to identify this situation anyway. The only 166439213Sgibbs * problem with this is that we will not get 166539213Sgibbs * information about blocks that are larger than 166639213Sgibbs * our read buffer unless we set the block size 166739213Sgibbs * in the mode page to something other than 0. 166841906Smjacob * 166941906Smjacob * I believe that this is a non-issue. If user apps 167041906Smjacob * don't adjust their read size to match our record 167141906Smjacob * size, that's just life. Anyway, the typical usage 167241906Smjacob * would be to issue, e.g., 64KB reads and occasionally 167341906Smjacob * have to do deal with 512 byte or 1KB intermediate 167441906Smjacob * records. 167539213Sgibbs */ 167659249Sphk softc->dsreg = (bp->bio_cmd == BIO_READ)? 167743636Smjacob MTIO_DSREG_RD : MTIO_DSREG_WR; 167846962Smjacob scsi_sa_read_write(&start_ccb->csio, 0, sadone, 167959249Sphk MSG_SIMPLE_Q_TAG, (bp->bio_cmd == BIO_READ), 168046962Smjacob FALSE, (softc->flags & SA_FLAG_FIXED) != 0, 168159249Sphk length, bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE, 168279100Smjacob IO_TIMEOUT); 168371082Smjacob start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED; 168471082Smjacob Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO); 168539213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 168659249Sphk bp = bioq_first(&softc->bio_queue); 168739213Sgibbs xpt_action(start_ccb); 168839213Sgibbs } 168939213Sgibbs 169039213Sgibbs if (bp != NULL) { 169139213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 169246962Smjacob xpt_schedule(periph, 1); 169339213Sgibbs } 169439213Sgibbs break; 169539213Sgibbs } 169646962Smjacob case SA_STATE_ABNORMAL: 169746962Smjacob default: 169846962Smjacob panic("state 0x%x in sastart", softc->state); 169946962Smjacob break; 170039213Sgibbs } 170139213Sgibbs} 170239213Sgibbs 170339213Sgibbs 170439213Sgibbsstatic void 170539213Sgibbssadone(struct cam_periph *periph, union ccb *done_ccb) 170639213Sgibbs{ 170739213Sgibbs struct sa_softc *softc; 170839213Sgibbs struct ccb_scsiio *csio; 170939213Sgibbs 171039213Sgibbs softc = (struct sa_softc *)periph->softc; 171139213Sgibbs csio = &done_ccb->csio; 171271082Smjacob switch (CCB_Type(csio)) { 171339213Sgibbs case SA_CCB_BUFFER_IO: 171439213Sgibbs { 171559249Sphk struct bio *bp; 171639213Sgibbs int error; 171739213Sgibbs 171843636Smjacob softc->dsreg = MTIO_DSREG_REST; 171959249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 172039213Sgibbs error = 0; 172139213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 172239213Sgibbs if ((error = saerror(done_ccb, 0, 0)) == ERESTART) { 172339213Sgibbs /* 172441948Smjacob * A retry was scheduled, so just return. 172539213Sgibbs */ 172639213Sgibbs return; 172739213Sgibbs } 172839213Sgibbs } 172939213Sgibbs 173039213Sgibbs if (error == EIO) { 173139213Sgibbs 173239213Sgibbs /* 173353522Smjacob * Catastrophic error. Mark the tape as frozen 173453522Smjacob * (we no longer know tape position). 173553522Smjacob * 173644354Smjacob * Return all queued I/O with EIO, and unfreeze 173739213Sgibbs * our queue so that future transactions that 173839213Sgibbs * attempt to fix this problem can get to the 173939213Sgibbs * device. 174039213Sgibbs * 174139213Sgibbs */ 174239213Sgibbs 174353522Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 1744112946Sphk bioq_flush(&softc->bio_queue, NULL, EIO); 174539213Sgibbs } 174639213Sgibbs if (error != 0) { 174759249Sphk bp->bio_resid = bp->bio_bcount; 174859249Sphk bp->bio_error = error; 174959249Sphk bp->bio_flags |= BIO_ERROR; 175043636Smjacob /* 175143636Smjacob * In the error case, position is updated in saerror. 175243636Smjacob */ 175339213Sgibbs } else { 175459249Sphk bp->bio_resid = csio->resid; 175559249Sphk bp->bio_error = 0; 175639213Sgibbs if (csio->resid != 0) { 175759249Sphk bp->bio_flags |= BIO_ERROR; 175839213Sgibbs } 175959249Sphk if (bp->bio_cmd == BIO_WRITE) { 176039213Sgibbs softc->flags |= SA_FLAG_TAPE_WRITTEN; 176139213Sgibbs softc->filemarks = 0; 176239213Sgibbs } 176371082Smjacob if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) && 176471082Smjacob (softc->blkno != (daddr_t) -1)) { 176543636Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 176643636Smjacob u_int32_t l; 176743636Smjacob if (softc->blk_shift != 0) { 176859249Sphk l = bp->bio_bcount >> 176943636Smjacob softc->blk_shift; 177043636Smjacob } else { 177159249Sphk l = bp->bio_bcount / 177243636Smjacob softc->media_blksize; 177343636Smjacob } 177443636Smjacob softc->blkno += (daddr_t) l; 177543636Smjacob } else { 177643636Smjacob softc->blkno++; 177743636Smjacob } 177843636Smjacob } 177939213Sgibbs } 178046962Smjacob /* 178146962Smjacob * If we had an error (immediate or pending), 178246962Smjacob * release the device queue now. 178346962Smjacob */ 178446962Smjacob if (error || (softc->flags & SA_FLAG_ERR_PENDING)) 178546962Smjacob cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0); 178641674Smjacob#ifdef CAMDEBUG 178759249Sphk if (error || bp->bio_resid) { 178841674Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 178941674Smjacob ("error %d resid %ld count %ld\n", error, 179059249Sphk bp->bio_resid, bp->bio_bcount)); 179141674Smjacob } 179241674Smjacob#endif 1793112006Sphk biofinish(bp, softc->device_stats, 0); 179439213Sgibbs break; 179539213Sgibbs } 179639213Sgibbs case SA_CCB_WAITING: 179739213Sgibbs { 179839213Sgibbs /* Caller will release the CCB */ 179939213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 180039213Sgibbs return; 180139213Sgibbs } 180239213Sgibbs } 180339213Sgibbs xpt_release_ccb(done_ccb); 180439213Sgibbs} 180539213Sgibbs 180641906Smjacob/* 180741906Smjacob * Mount the tape (make sure it's ready for I/O). 180841906Smjacob */ 180939213Sgibbsstatic int 1810130585Sphksamount(struct cam_periph *periph, int oflags, struct cdev *dev) 181139213Sgibbs{ 181239213Sgibbs struct sa_softc *softc; 181339213Sgibbs union ccb *ccb; 181439213Sgibbs int error; 181539213Sgibbs 181641906Smjacob /* 181741906Smjacob * oflags can be checked for 'kind' of open (read-only check) - later 181841906Smjacob * dev can be checked for a control-mode or compression open - later 181941906Smjacob */ 182041906Smjacob UNUSED_PARAMETER(oflags); 182141906Smjacob UNUSED_PARAMETER(dev); 182241906Smjacob 182341906Smjacob 182439213Sgibbs softc = (struct sa_softc *)periph->softc; 182539213Sgibbs 182639213Sgibbs /* 182753259Smjacob * This should determine if something has happend since the last 182853259Smjacob * open/mount that would invalidate the mount. We do *not* want 182953259Smjacob * to retry this command- we just want the status. But we only 183053259Smjacob * do this if we're mounted already- if we're not mounted, 183153259Smjacob * we don't care about the unit read state and can instead use 183253259Smjacob * this opportunity to attempt to reserve the tape unit. 183339213Sgibbs */ 183453259Smjacob 183553259Smjacob if (softc->flags & SA_FLAG_TAPE_MOUNTED) { 183653259Smjacob ccb = cam_periph_getccb(periph, 1); 183753259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 183879100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 183954099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1840112006Sphk softc->device_stats); 184153259Smjacob QFRLS(ccb); 184253259Smjacob if (error == ENXIO) { 184353259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 184453259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 184579100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 184654099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1847112006Sphk softc->device_stats); 184853259Smjacob QFRLS(ccb); 184953259Smjacob } else if (error) { 185054099Smjacob /* 185154099Smjacob * We don't need to freeze the tape because we 185254099Smjacob * will now attempt to rewind/load it. 185354099Smjacob */ 185453259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 1855144430Ssam if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 1856164906Smjacob xpt_print(periph->path, 1857164906Smjacob "error %d on TUR in samount\n", error); 185854099Smjacob } 185953259Smjacob } 186053259Smjacob } else { 186153259Smjacob error = sareservereleaseunit(periph, TRUE); 186253259Smjacob if (error) { 186353259Smjacob return (error); 186453259Smjacob } 186553259Smjacob ccb = cam_periph_getccb(periph, 1); 186654105Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 186779100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 186854105Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1869112006Sphk softc->device_stats); 187054105Smjacob QFRLS(ccb); 187153259Smjacob } 187239213Sgibbs 187339213Sgibbs if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 187453259Smjacob struct scsi_read_block_limits_data *rblim = NULL; 187553259Smjacob int comp_enabled, comp_supported; 187641906Smjacob u_int8_t write_protect, guessing = 0; 187739213Sgibbs 187839213Sgibbs /* 187939213Sgibbs * Clear out old state. 188039213Sgibbs */ 188139213Sgibbs softc->flags &= ~(SA_FLAG_TAPE_WP|SA_FLAG_TAPE_WRITTEN| 188239213Sgibbs SA_FLAG_ERR_PENDING|SA_FLAG_COMP_ENABLED| 188346962Smjacob SA_FLAG_COMP_SUPP|SA_FLAG_COMP_UNSUPP); 188439213Sgibbs softc->filemarks = 0; 188539213Sgibbs 188639213Sgibbs /* 188743636Smjacob * *Very* first off, make sure we're loaded to BOT. 188839213Sgibbs */ 188943636Smjacob scsi_load_unload(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 189054099Smjacob FALSE, FALSE, 1, SSD_FULL_SIZE, REWIND_TIMEOUT); 189154099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1892112006Sphk softc->device_stats); 189353259Smjacob QFRLS(ccb); 189453259Smjacob 189543636Smjacob /* 189644354Smjacob * In case this doesn't work, do a REWIND instead 189743636Smjacob */ 189844354Smjacob if (error) { 189953259Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 190053259Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 190154099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1902112006Sphk softc->device_stats); 190353259Smjacob QFRLS(ccb); 190443636Smjacob } 190543636Smjacob if (error) { 190643636Smjacob xpt_release_ccb(ccb); 190743636Smjacob goto exit; 190843636Smjacob } 190943636Smjacob 191043636Smjacob /* 191153259Smjacob * Do a dummy test read to force access to the 191253259Smjacob * media so that the drive will really know what's 191354099Smjacob * there. We actually don't really care what the 191454099Smjacob * blocksize on tape is and don't expect to really 191554099Smjacob * read a full record. 191643636Smjacob */ 191739213Sgibbs rblim = (struct scsi_read_block_limits_data *) 1918170830Sscottl malloc(8192, M_SCSISA, M_NOWAIT); 191953259Smjacob if (rblim == NULL) { 1920164906Smjacob xpt_print(periph->path, "no memory for test read\n"); 192153259Smjacob xpt_release_ccb(ccb); 192253259Smjacob error = ENOMEM; 192353259Smjacob goto exit; 192453259Smjacob } 192556981Smjacob 192656981Smjacob if ((softc->quirks & SA_QUIRK_NODREAD) == 0) { 192756981Smjacob scsi_sa_read_write(&ccb->csio, 0, sadone, 192856981Smjacob MSG_SIMPLE_Q_TAG, 1, FALSE, 0, 8192, 192956981Smjacob (void *) rblim, 8192, SSD_FULL_SIZE, 193079100Smjacob IO_TIMEOUT); 193156981Smjacob (void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1932112006Sphk softc->device_stats); 193356981Smjacob QFRLS(ccb); 193456981Smjacob scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 193556981Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 193674840Sken error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, 193774840Sken SF_NO_PRINT | SF_RETRY_UA, 1938112006Sphk softc->device_stats); 193956981Smjacob QFRLS(ccb); 194056981Smjacob if (error) { 1941164906Smjacob xpt_print(periph->path, 1942164906Smjacob "unable to rewind after test read\n"); 194356981Smjacob xpt_release_ccb(ccb); 194456981Smjacob goto exit; 194556981Smjacob } 194653259Smjacob } 194739213Sgibbs 194853259Smjacob /* 194953259Smjacob * Next off, determine block limits. 195053259Smjacob */ 195153259Smjacob scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 195279100Smjacob rblim, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 195339213Sgibbs 195474840Sken error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, 1955112006Sphk SF_NO_PRINT | SF_RETRY_UA, softc->device_stats); 195674840Sken 195753259Smjacob QFRLS(ccb); 195839213Sgibbs xpt_release_ccb(ccb); 195939213Sgibbs 196041674Smjacob if (error != 0) { 196141674Smjacob /* 196241674Smjacob * If it's less than SCSI-2, READ BLOCK LIMITS is not 196341674Smjacob * a MANDATORY command. Anyway- it doesn't matter- 196441674Smjacob * we can proceed anyway. 196541674Smjacob */ 196641674Smjacob softc->blk_gran = 0; 196741674Smjacob softc->max_blk = ~0; 196841674Smjacob softc->min_blk = 0; 196941674Smjacob } else { 197074840Sken if (softc->scsi_rev >= SCSI_REV_SPC) { 197141674Smjacob softc->blk_gran = RBL_GRAN(rblim); 197241674Smjacob } else { 197341674Smjacob softc->blk_gran = 0; 197441674Smjacob } 197541674Smjacob /* 197641674Smjacob * We take max_blk == min_blk to mean a default to 197741674Smjacob * fixed mode- but note that whatever we get out of 197841674Smjacob * sagetparams below will actually determine whether 197941674Smjacob * we are actually *in* fixed mode. 198041674Smjacob */ 198141674Smjacob softc->max_blk = scsi_3btoul(rblim->maximum); 198241674Smjacob softc->min_blk = scsi_2btoul(rblim->minimum); 198341674Smjacob 198441674Smjacob 198541674Smjacob } 198641674Smjacob /* 198741674Smjacob * Next, perform a mode sense to determine 198841674Smjacob * current density, blocksize, compression etc. 198941674Smjacob */ 199041674Smjacob error = sagetparams(periph, SA_PARAM_ALL, 199141674Smjacob &softc->media_blksize, 199241674Smjacob &softc->media_density, 199341674Smjacob &softc->media_numblks, 199441674Smjacob &softc->buffer_mode, &write_protect, 199541674Smjacob &softc->speed, &comp_supported, 199641674Smjacob &comp_enabled, &softc->comp_algorithm, 199741674Smjacob NULL); 199841674Smjacob 199941674Smjacob if (error != 0) { 200041674Smjacob /* 200141674Smjacob * We could work a little harder here. We could 200241674Smjacob * adjust our attempts to get information. It 200341674Smjacob * might be an ancient tape drive. If someone 200441674Smjacob * nudges us, we'll do that. 200541674Smjacob */ 200639213Sgibbs goto exit; 200741674Smjacob } 200839213Sgibbs 200941906Smjacob /* 201041906Smjacob * If no quirk has determined that this is a device that is 201141906Smjacob * preferred to be in fixed or variable mode, now is the time 201241906Smjacob * to find out. 201341906Smjacob */ 201441906Smjacob if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) { 201541906Smjacob guessing = 1; 201643636Smjacob /* 201743636Smjacob * This could be expensive to find out. Luckily we 201843636Smjacob * only need to do this once. If we start out in 201943636Smjacob * 'default' mode, try and set ourselves to one 202043636Smjacob * of the densities that would determine a wad 202143636Smjacob * of other stuff. Go from highest to lowest. 202243636Smjacob */ 202343636Smjacob if (softc->media_density == SCSI_DEFAULT_DENSITY) { 202443636Smjacob int i; 202543636Smjacob static u_int8_t ctry[] = { 202643636Smjacob SCSI_DENSITY_HALFINCH_PE, 202743636Smjacob SCSI_DENSITY_HALFINCH_6250C, 202843636Smjacob SCSI_DENSITY_HALFINCH_6250, 202943636Smjacob SCSI_DENSITY_HALFINCH_1600, 203043636Smjacob SCSI_DENSITY_HALFINCH_800, 203146962Smjacob SCSI_DENSITY_QIC_4GB, 203246962Smjacob SCSI_DENSITY_QIC_2GB, 203343636Smjacob SCSI_DENSITY_QIC_525_320, 203443636Smjacob SCSI_DENSITY_QIC_150, 203543636Smjacob SCSI_DENSITY_QIC_120, 203643636Smjacob SCSI_DENSITY_QIC_24, 203743636Smjacob SCSI_DENSITY_QIC_11_9TRK, 203843636Smjacob SCSI_DENSITY_QIC_11_4TRK, 203946962Smjacob SCSI_DENSITY_QIC_1320, 204046962Smjacob SCSI_DENSITY_QIC_3080, 204143636Smjacob 0 204243636Smjacob }; 204343636Smjacob for (i = 0; ctry[i]; i++) { 204443636Smjacob error = sasetparams(periph, 204543636Smjacob SA_PARAM_DENSITY, 0, ctry[i], 204643636Smjacob 0, SF_NO_PRINT); 204743636Smjacob if (error == 0) { 204843636Smjacob softc->media_density = ctry[i]; 204943636Smjacob break; 205043636Smjacob } 205143636Smjacob } 205243636Smjacob } 205341906Smjacob switch (softc->media_density) { 205441906Smjacob case SCSI_DENSITY_QIC_11_4TRK: 205541906Smjacob case SCSI_DENSITY_QIC_11_9TRK: 205641906Smjacob case SCSI_DENSITY_QIC_24: 205741906Smjacob case SCSI_DENSITY_QIC_120: 205841906Smjacob case SCSI_DENSITY_QIC_150: 205965861Smjacob case SCSI_DENSITY_QIC_525_320: 206043636Smjacob case SCSI_DENSITY_QIC_1320: 206143636Smjacob case SCSI_DENSITY_QIC_3080: 206246962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 206343636Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 206441906Smjacob softc->last_media_blksize = 512; 206541906Smjacob break; 206646962Smjacob case SCSI_DENSITY_QIC_4GB: 206746962Smjacob case SCSI_DENSITY_QIC_2GB: 206846962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 206946962Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 207046962Smjacob softc->last_media_blksize = 1024; 207146962Smjacob break; 207241906Smjacob default: 207341906Smjacob softc->last_media_blksize = 207441906Smjacob softc->media_blksize; 207541906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 207641906Smjacob break; 207741906Smjacob } 207841906Smjacob } 207942563Smjacob 208041906Smjacob /* 208141906Smjacob * If no quirk has determined that this is a device that needs 208241906Smjacob * to have 2 Filemarks at EOD, now is the time to find out. 208341906Smjacob */ 208442563Smjacob 208542735Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) { 208641906Smjacob switch (softc->media_density) { 208741906Smjacob case SCSI_DENSITY_HALFINCH_800: 208841906Smjacob case SCSI_DENSITY_HALFINCH_1600: 208941906Smjacob case SCSI_DENSITY_HALFINCH_6250: 209041906Smjacob case SCSI_DENSITY_HALFINCH_6250C: 209141906Smjacob case SCSI_DENSITY_HALFINCH_PE: 209246962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 209341906Smjacob softc->quirks |= SA_QUIRK_2FM; 209441906Smjacob break; 209541906Smjacob default: 209641906Smjacob break; 209741906Smjacob } 209841906Smjacob } 209941906Smjacob 210041906Smjacob /* 210141906Smjacob * Now validate that some info we got makes sense. 210241906Smjacob */ 210341674Smjacob if ((softc->max_blk < softc->media_blksize) || 210441674Smjacob (softc->min_blk > softc->media_blksize && 210541674Smjacob softc->media_blksize)) { 2106164906Smjacob xpt_print(periph->path, 2107164906Smjacob "BLOCK LIMITS (%d..%d) could not match current " 210841674Smjacob "block settings (%d)- adjusting\n", softc->min_blk, 210941674Smjacob softc->max_blk, softc->media_blksize); 211041674Smjacob softc->max_blk = softc->min_blk = 211141674Smjacob softc->media_blksize; 211241674Smjacob } 211341906Smjacob 211441674Smjacob /* 211541906Smjacob * Now put ourselves into the right frame of mind based 211641906Smjacob * upon quirks... 211741906Smjacob */ 211841906Smjacobtryagain: 211942563Smjacob /* 212042563Smjacob * If we want to be in FIXED mode and our current blocksize 212142563Smjacob * is not equal to our last blocksize (if nonzero), try and 212242563Smjacob * set ourselves to this last blocksize (as the 'preferred' 212342563Smjacob * block size). The initial quirkmatch at registry sets the 212442563Smjacob * initial 'last' blocksize. If, for whatever reason, this 212542563Smjacob * 'last' blocksize is zero, set the blocksize to 512, 212642563Smjacob * or min_blk if that's larger. 212742563Smjacob */ 212841906Smjacob if ((softc->quirks & SA_QUIRK_FIXED) && 212960235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0 && 213042563Smjacob (softc->media_blksize != softc->last_media_blksize)) { 213141906Smjacob softc->media_blksize = softc->last_media_blksize; 213241906Smjacob if (softc->media_blksize == 0) { 213342563Smjacob softc->media_blksize = 512; 213441906Smjacob if (softc->media_blksize < softc->min_blk) { 213541906Smjacob softc->media_blksize = softc->min_blk; 213641906Smjacob } 213741906Smjacob } 213841906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 213942563Smjacob softc->media_blksize, 0, 0, SF_NO_PRINT); 214041906Smjacob if (error) { 2141164906Smjacob xpt_print(periph->path, 2142164906Smjacob "unable to set fixed blocksize to %d\n", 2143164906Smjacob softc->media_blksize); 214441906Smjacob goto exit; 214541906Smjacob } 214641906Smjacob } 214741906Smjacob 214841906Smjacob if ((softc->quirks & SA_QUIRK_VARIABLE) && 214941906Smjacob (softc->media_blksize != 0)) { 215041906Smjacob softc->last_media_blksize = softc->media_blksize; 215141906Smjacob softc->media_blksize = 0; 215241906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 215342563Smjacob 0, 0, 0, SF_NO_PRINT); 215441906Smjacob if (error) { 215541906Smjacob /* 215641906Smjacob * If this fails and we were guessing, just 215741906Smjacob * assume that we got it wrong and go try 215842563Smjacob * fixed block mode. Don't even check against 215942563Smjacob * density code at this point. 216041906Smjacob */ 216142563Smjacob if (guessing) { 216241906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 216341906Smjacob softc->quirks |= SA_QUIRK_FIXED; 216441906Smjacob if (softc->last_media_blksize == 0) 216541906Smjacob softc->last_media_blksize = 512; 216641906Smjacob goto tryagain; 216741906Smjacob } 2168164906Smjacob xpt_print(periph->path, 2169164906Smjacob "unable to set variable blocksize\n"); 217041906Smjacob goto exit; 217141906Smjacob } 217241906Smjacob } 217341906Smjacob 217441906Smjacob /* 217541674Smjacob * Now that we have the current block size, 217641674Smjacob * set up some parameters for sastart's usage. 217741674Smjacob */ 217841674Smjacob if (softc->media_blksize) { 217939213Sgibbs softc->flags |= SA_FLAG_FIXED; 218041674Smjacob if (powerof2(softc->media_blksize)) { 218141674Smjacob softc->blk_shift = 218241674Smjacob ffs(softc->media_blksize) - 1; 218341674Smjacob softc->blk_mask = softc->media_blksize - 1; 218439213Sgibbs } else { 218539213Sgibbs softc->blk_mask = ~0; 218639213Sgibbs softc->blk_shift = 0; 218739213Sgibbs } 218839213Sgibbs } else { 218939213Sgibbs /* 219041674Smjacob * The SCSI-3 spec allows 0 to mean "unspecified". 219141674Smjacob * The SCSI-1 spec allows 0 to mean 'infinite'. 219241674Smjacob * 219341674Smjacob * Either works here. 219439213Sgibbs */ 219539213Sgibbs if (softc->max_blk == 0) { 219639213Sgibbs softc->max_blk = ~0; 219739213Sgibbs } 219839213Sgibbs softc->blk_shift = 0; 219939213Sgibbs if (softc->blk_gran != 0) { 220039213Sgibbs softc->blk_mask = softc->blk_gran - 1; 220139213Sgibbs } else { 220239213Sgibbs softc->blk_mask = 0; 220339213Sgibbs } 220439213Sgibbs } 220539213Sgibbs 220639213Sgibbs if (write_protect) 220739213Sgibbs softc->flags |= SA_FLAG_TAPE_WP; 220839213Sgibbs 220939213Sgibbs if (comp_supported) { 221043636Smjacob if (softc->saved_comp_algorithm == 0) 221143636Smjacob softc->saved_comp_algorithm = 221243636Smjacob softc->comp_algorithm; 221346962Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 221446962Smjacob if (comp_enabled) 221546962Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 221639213Sgibbs } else 221739213Sgibbs softc->flags |= SA_FLAG_COMP_UNSUPP; 221839213Sgibbs 221960235Smjacob if ((softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) && 222060235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0) { 222141906Smjacob error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0, 222242563Smjacob 0, 0, SF_NO_PRINT); 222383473Smjacob if (error == 0) { 222441906Smjacob softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF; 222583473Smjacob } else { 2226164906Smjacob xpt_print(periph->path, 2227164906Smjacob "unable to set buffered mode\n"); 222883473Smjacob } 222960235Smjacob error = 0; /* not an error */ 223041906Smjacob } 223139213Sgibbs 223239213Sgibbs 223344354Smjacob if (error == 0) { 223441906Smjacob softc->flags |= SA_FLAG_TAPE_MOUNTED; 223544354Smjacob } 223639213Sgibbsexit: 223739213Sgibbs if (rblim != NULL) 2238169562Sscottl free(rblim, M_SCSISA); 223939213Sgibbs 224043636Smjacob if (error != 0) { 224143636Smjacob softc->dsreg = MTIO_DSREG_NIL; 224244354Smjacob } else { 224344354Smjacob softc->fileno = softc->blkno = 0; 224443636Smjacob softc->dsreg = MTIO_DSREG_REST; 224544354Smjacob } 224651875Smjacob#ifdef SA_1FM_AT_EOD 224751875Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) 224851875Smjacob softc->quirks |= SA_QUIRK_1FM; 224951875Smjacob#else 225046962Smjacob if ((softc->quirks & SA_QUIRK_1FM) == 0) 225143636Smjacob softc->quirks |= SA_QUIRK_2FM; 225243636Smjacob#endif 225339213Sgibbs } else 225439213Sgibbs xpt_release_ccb(ccb); 225539213Sgibbs 225653259Smjacob /* 225753259Smjacob * If we return an error, we're not mounted any more, 225853259Smjacob * so release any device reservation. 225953259Smjacob */ 226053259Smjacob if (error != 0) { 226153259Smjacob (void) sareservereleaseunit(periph, FALSE); 226282575Smjacob } else { 226382575Smjacob /* 226482575Smjacob * Clear I/O residual. 226582575Smjacob */ 226682575Smjacob softc->last_io_resid = 0; 226782575Smjacob softc->last_ctl_resid = 0; 226853259Smjacob } 226954099Smjacob return (error); 227039213Sgibbs} 227139213Sgibbs 227268114Smjacob/* 227368114Smjacob * How many filemarks do we need to write if we were to terminate the 227468114Smjacob * tape session right now? Note that this can be a negative number 227568114Smjacob */ 227668114Smjacob 227739213Sgibbsstatic int 227868114Smjacobsamarkswanted(struct cam_periph *periph) 227939213Sgibbs{ 228039213Sgibbs int markswanted; 228139213Sgibbs struct sa_softc *softc; 228239213Sgibbs 228339213Sgibbs softc = (struct sa_softc *)periph->softc; 228439213Sgibbs markswanted = 0; 228539213Sgibbs if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) { 228639213Sgibbs markswanted++; 228746962Smjacob if (softc->quirks & SA_QUIRK_2FM) 228839213Sgibbs markswanted++; 228939213Sgibbs } 229068114Smjacob markswanted -= softc->filemarks; 229168114Smjacob return (markswanted); 229268114Smjacob} 229339213Sgibbs 229468114Smjacobstatic int 229568114Smjacobsacheckeod(struct cam_periph *periph) 229668114Smjacob{ 229768114Smjacob int error; 229868114Smjacob int markswanted; 229968114Smjacob 230068114Smjacob markswanted = samarkswanted(periph); 230168114Smjacob 230268114Smjacob if (markswanted > 0) { 230341906Smjacob error = sawritefilemarks(periph, markswanted, FALSE); 230439213Sgibbs } else { 230539213Sgibbs error = 0; 230639213Sgibbs } 230739213Sgibbs return (error); 230839213Sgibbs} 230939213Sgibbs 231039213Sgibbsstatic int 231146962Smjacobsaerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) 231239213Sgibbs{ 231346962Smjacob static const char *toobig = 231498449Srobert "%d-byte tape record bigger than supplied buffer\n"; 231539213Sgibbs struct cam_periph *periph; 231639213Sgibbs struct sa_softc *softc; 231739213Sgibbs struct ccb_scsiio *csio; 231839213Sgibbs struct scsi_sense_data *sense; 231953259Smjacob u_int32_t resid = 0; 232053259Smjacob int32_t info = 0; 232182575Smjacob cam_status status; 232282575Smjacob int error_code, sense_key, asc, ascq, error, aqvalid; 232339213Sgibbs 232439213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 232539213Sgibbs softc = (struct sa_softc *)periph->softc; 232639213Sgibbs csio = &ccb->csio; 232739213Sgibbs sense = &csio->sense_data; 232839213Sgibbs scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); 232982575Smjacob aqvalid = sense->extra_len >= 6; 233039213Sgibbs error = 0; 233146962Smjacob 233282575Smjacob status = csio->ccb_h.status & CAM_STATUS_MASK; 233382575Smjacob 233446962Smjacob /* 233582575Smjacob * Calculate/latch up, any residuals... We do this in a funny 2-step 233682575Smjacob * so we can print stuff here if we have CAM_DEBUG enabled for this 233782575Smjacob * unit. 233846962Smjacob */ 233982575Smjacob if (status == CAM_SCSI_STATUS_ERROR) { 234039213Sgibbs if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { 234146962Smjacob info = (int32_t) scsi_4btoul(sense->info); 234239213Sgibbs resid = info; 234339213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) 234439213Sgibbs resid *= softc->media_blksize; 234539213Sgibbs } else { 234639213Sgibbs resid = csio->dxfer_len; 234739213Sgibbs info = resid; 234841674Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 234941674Smjacob if (softc->media_blksize) 235041674Smjacob info /= softc->media_blksize; 235141674Smjacob } 235239213Sgibbs } 235371082Smjacob if (CCB_Type(csio) == SA_CCB_BUFFER_IO) { 235441948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense, 235541948Smjacob sizeof (struct scsi_sense_data)); 235642009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb, 235742009Smjacob (int) csio->cdb_len); 235841948Smjacob softc->last_io_resid = resid; 235971268Smjacob softc->last_resid_was_io = 1; 236041948Smjacob } else { 236141948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_ctl_sense, 236241948Smjacob sizeof (struct scsi_sense_data)); 236342009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_ctl_cdb, 236442009Smjacob (int) csio->cdb_len); 236541948Smjacob softc->last_ctl_resid = resid; 236671268Smjacob softc->last_resid_was_io = 0; 236741948Smjacob } 236882575Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x " 236982575Smjacob "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %d " 237082575Smjacob "dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff, 237182575Smjacob sense_key, asc, ascq, status, 237282575Smjacob sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len)); 237353259Smjacob } else { 237482575Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 237582575Smjacob ("Cam Status 0x%x\n", status)); 237641948Smjacob } 237741948Smjacob 237882575Smjacob switch (status) { 237982575Smjacob case CAM_REQ_CMP: 238082575Smjacob return (0); 238182575Smjacob case CAM_SCSI_STATUS_ERROR: 238282575Smjacob /* 238382575Smjacob * If a read/write command, we handle it here. 238482575Smjacob */ 238582575Smjacob if (CCB_Type(csio) != SA_CCB_WAITING) { 238682575Smjacob break; 238782575Smjacob } 238882575Smjacob /* 238982575Smjacob * If this was just EOM/EOP, Filemark, Setmark or ILI detected 239082575Smjacob * on a non read/write command, we assume it's not an error 239182575Smjacob * and propagate the residule and return. 239282575Smjacob */ 239382575Smjacob if ((aqvalid && asc == 0 && ascq > 0 && ascq <= 5) || 239482575Smjacob (aqvalid == 0 && sense_key == SSD_KEY_NO_SENSE)) { 239582575Smjacob csio->resid = resid; 239682575Smjacob QFRLS(ccb); 239782575Smjacob return (0); 239882575Smjacob } 239982575Smjacob /* 240082575Smjacob * Otherwise, we let the common code handle this. 240182575Smjacob */ 240246962Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 240341948Smjacob 240446962Smjacob /* 240582575Smjacob * XXX: To Be Fixed 240682575Smjacob * We cannot depend upon CAM honoring retry counts for these. 240746962Smjacob */ 240882575Smjacob case CAM_SCSI_BUS_RESET: 240982575Smjacob case CAM_BDR_SENT: 241082575Smjacob if (ccb->ccb_h.retry_count <= 0) { 241182575Smjacob return (EIO); 241282575Smjacob } 241382575Smjacob /* FALLTHROUGH */ 241482575Smjacob default: 241582575Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 241646962Smjacob } 241746962Smjacob 241846962Smjacob /* 241946962Smjacob * Handle filemark, end of tape, mismatched record sizes.... 242046962Smjacob * From this point out, we're only handling read/write cases. 242146962Smjacob * Handle writes && reads differently. 242246962Smjacob */ 242382575Smjacob 242446962Smjacob if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) { 242582575Smjacob if (sense_key == SSD_KEY_VOLUME_OVERFLOW) { 242639213Sgibbs csio->resid = resid; 242782575Smjacob error = ENOSPC; 242882575Smjacob } else if (sense->flags & SSD_EOM) { 242982575Smjacob softc->flags |= SA_FLAG_EOM_PENDING; 243082575Smjacob /* 243182575Smjacob * Grotesque as it seems, the few times 243282575Smjacob * I've actually seen a non-zero resid, 243382575Smjacob * the tape drive actually lied and had 2434124645Sjohan * written all the data!. 243582575Smjacob */ 243682575Smjacob csio->resid = 0; 243739213Sgibbs } 243846962Smjacob } else { 243982575Smjacob csio->resid = resid; 244046962Smjacob if (sense_key == SSD_KEY_BLANK_CHECK) { 244182575Smjacob if (softc->quirks & SA_QUIRK_1FM) { 244282575Smjacob error = 0; 244346962Smjacob softc->flags |= SA_FLAG_EOM_PENDING; 244446962Smjacob } else { 244546962Smjacob error = EIO; 244646962Smjacob } 244782575Smjacob } else if (sense->flags & SSD_FILEMARK) { 244882575Smjacob if (softc->flags & SA_FLAG_FIXED) { 244946962Smjacob error = -1; 245039213Sgibbs softc->flags |= SA_FLAG_EOF_PENDING; 245146962Smjacob } 245246962Smjacob /* 245346962Smjacob * Unconditionally, if we detected a filemark on a read, 245446962Smjacob * mark that we've run moved a file ahead. 245546962Smjacob */ 245643636Smjacob if (softc->fileno != (daddr_t) -1) { 245743636Smjacob softc->fileno++; 245843636Smjacob softc->blkno = 0; 245971082Smjacob csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED; 246043636Smjacob } 246139213Sgibbs } 246246962Smjacob } 246382575Smjacob 246446962Smjacob /* 246546962Smjacob * Incorrect Length usually applies to read, but can apply to writes. 246646962Smjacob */ 246746962Smjacob if (error == 0 && (sense->flags & SSD_ILI)) { 246846962Smjacob if (info < 0) { 2469164906Smjacob xpt_print(csio->ccb_h.path, toobig, 2470164906Smjacob csio->dxfer_len - info); 247146962Smjacob csio->resid = csio->dxfer_len; 247246962Smjacob error = EIO; 247346962Smjacob } else { 247446962Smjacob csio->resid = resid; 247582575Smjacob if (softc->flags & SA_FLAG_FIXED) { 247682575Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 247746962Smjacob } 247846962Smjacob /* 247946962Smjacob * Bump the block number if we hadn't seen a filemark. 248046962Smjacob * Do this independent of errors (we've moved anyway). 248146962Smjacob */ 248246962Smjacob if ((sense->flags & SSD_FILEMARK) == 0) { 248346962Smjacob if (softc->blkno != (daddr_t) -1) { 248446962Smjacob softc->blkno++; 248571082Smjacob csio->ccb_h.ccb_pflags |= 248671082Smjacob SA_POSITION_UPDATED; 248739213Sgibbs } 248839213Sgibbs } 248939213Sgibbs } 249039213Sgibbs } 249182575Smjacob 249282575Smjacob if (error <= 0) { 249382575Smjacob /* 249482575Smjacob * Unfreeze the queue if frozen as we're not returning anything 249582575Smjacob * to our waiters that would indicate an I/O error has occurred 249682575Smjacob * (yet). 249782575Smjacob */ 249882575Smjacob QFRLS(ccb); 249982575Smjacob error = 0; 250080575Smjacob } 250182575Smjacob return (error); 250239213Sgibbs} 250339213Sgibbs 250439213Sgibbsstatic int 250539213Sgibbssagetparams(struct cam_periph *periph, sa_params params_to_get, 250639213Sgibbs u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks, 250739213Sgibbs int *buff_mode, u_int8_t *write_protect, u_int8_t *speed, 250839213Sgibbs int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm, 250946962Smjacob sa_comp_t *tcs) 251039213Sgibbs{ 251139213Sgibbs union ccb *ccb; 251239213Sgibbs void *mode_buffer; 251339213Sgibbs struct scsi_mode_header_6 *mode_hdr; 251439213Sgibbs struct scsi_mode_blk_desc *mode_blk; 251539213Sgibbs int mode_buffer_len; 251639213Sgibbs struct sa_softc *softc; 251746962Smjacob u_int8_t cpage; 251839213Sgibbs int error; 251939213Sgibbs cam_status status; 252039213Sgibbs 252139213Sgibbs softc = (struct sa_softc *)periph->softc; 252246962Smjacob ccb = cam_periph_getccb(periph, 1); 252371082Smjacob if (softc->quirks & SA_QUIRK_NO_CPAGE) 252471082Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 252571082Smjacob else 252671082Smjacob cpage = SA_DATA_COMPRESSION_PAGE; 252739213Sgibbs 252839213Sgibbsretry: 252939213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 253039213Sgibbs 253139213Sgibbs if (params_to_get & SA_PARAM_COMPRESSION) { 253239213Sgibbs if (softc->quirks & SA_QUIRK_NOCOMP) { 253339213Sgibbs *comp_supported = FALSE; 253439213Sgibbs params_to_get &= ~SA_PARAM_COMPRESSION; 253539213Sgibbs } else 253646962Smjacob mode_buffer_len += sizeof (sa_comp_t); 253739213Sgibbs } 253854099Smjacob 2539170829Sscottl /* XXX Fix M_NOWAIT */ 2540170829Sscottl mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_NOWAIT | M_ZERO); 2541170829Sscottl if (mode_buffer == NULL) { 2542170829Sscottl xpt_release_ccb(ccb); 2543170829Sscottl return (ENOMEM); 2544170829Sscottl } 254539213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 254639213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 254739213Sgibbs 254842716Smjacob /* it is safe to retry this */ 254942716Smjacob scsi_mode_sense(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 255042716Smjacob SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ? 255146962Smjacob cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len, 255279100Smjacob SSD_FULL_SIZE, SCSIOP_TIMEOUT); 255339213Sgibbs 255454099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 2555112006Sphk softc->device_stats); 255654099Smjacob QFRLS(ccb); 255739213Sgibbs 255839213Sgibbs status = ccb->ccb_h.status & CAM_STATUS_MASK; 255939213Sgibbs 256042716Smjacob if (error == EINVAL && (params_to_get & SA_PARAM_COMPRESSION) != 0) { 256139213Sgibbs /* 256246962Smjacob * Hmm. Let's see if we can try another page... 256346962Smjacob * If we've already done that, give up on compression 256446962Smjacob * for this device and remember this for the future 256546962Smjacob * and attempt the request without asking for compression 256646962Smjacob * info. 256739213Sgibbs */ 256846962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 256946962Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 257046962Smjacob goto retry; 257146962Smjacob } 257239213Sgibbs softc->quirks |= SA_QUIRK_NOCOMP; 2573169562Sscottl free(mode_buffer, M_SCSISA); 257439213Sgibbs goto retry; 257546962Smjacob } else if (status == CAM_SCSI_STATUS_ERROR) { 257646962Smjacob /* Tell the user about the fatal error. */ 257746962Smjacob scsi_sense_print(&ccb->csio); 257846962Smjacob goto sagetparamsexit; 257946962Smjacob } 258039213Sgibbs 258146962Smjacob /* 258246962Smjacob * If the user only wants the compression information, and 258346962Smjacob * the device doesn't send back the block descriptor, it's 258446962Smjacob * no big deal. If the user wants more than just 258546962Smjacob * compression, though, and the device doesn't pass back the 258646962Smjacob * block descriptor, we need to send another mode sense to 258746962Smjacob * get the block descriptor. 258846962Smjacob */ 258946962Smjacob if ((mode_hdr->blk_desc_len == 0) && 259046962Smjacob (params_to_get & SA_PARAM_COMPRESSION) && 259146962Smjacob (params_to_get & ~(SA_PARAM_COMPRESSION))) { 259239213Sgibbs 259339213Sgibbs /* 259446962Smjacob * Decrease the mode buffer length by the size of 259546962Smjacob * the compression page, to make sure the data 259646962Smjacob * there doesn't get overwritten. 259739213Sgibbs */ 259846962Smjacob mode_buffer_len -= sizeof (sa_comp_t); 259939213Sgibbs 260046962Smjacob /* 260146962Smjacob * Now move the compression page that we presumably 260246962Smjacob * got back down the memory chunk a little bit so 260346962Smjacob * it doesn't get spammed. 260446962Smjacob */ 260554099Smjacob bcopy(&mode_hdr[0], &mode_hdr[1], sizeof (sa_comp_t)); 260654099Smjacob bzero(&mode_hdr[0], sizeof (mode_hdr[0])); 260739213Sgibbs 260846962Smjacob /* 260946962Smjacob * Now, we issue another mode sense and just ask 261046962Smjacob * for the block descriptor, etc. 261146962Smjacob */ 261239213Sgibbs 261346962Smjacob scsi_mode_sense(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 261446962Smjacob SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE, 261579100Smjacob mode_buffer, mode_buffer_len, SSD_FULL_SIZE, 261679100Smjacob SCSIOP_TIMEOUT); 261739213Sgibbs 261854099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 2619112006Sphk softc->device_stats); 262054099Smjacob QFRLS(ccb); 262139213Sgibbs 262246962Smjacob if (error != 0) 262346962Smjacob goto sagetparamsexit; 262446962Smjacob } 262539213Sgibbs 262646962Smjacob if (params_to_get & SA_PARAM_BLOCKSIZE) 262746962Smjacob *blocksize = scsi_3btoul(mode_blk->blklen); 262839213Sgibbs 262946962Smjacob if (params_to_get & SA_PARAM_NUMBLOCKS) 263046962Smjacob *numblocks = scsi_3btoul(mode_blk->nblocks); 263139213Sgibbs 263246962Smjacob if (params_to_get & SA_PARAM_BUFF_MODE) 263346962Smjacob *buff_mode = mode_hdr->dev_spec & SMH_SA_BUF_MODE_MASK; 263439213Sgibbs 263546962Smjacob if (params_to_get & SA_PARAM_DENSITY) 263646962Smjacob *density = mode_blk->density; 263739213Sgibbs 263846962Smjacob if (params_to_get & SA_PARAM_WP) 263946962Smjacob *write_protect = (mode_hdr->dev_spec & SMH_SA_WP)? TRUE : FALSE; 264039213Sgibbs 264146962Smjacob if (params_to_get & SA_PARAM_SPEED) 264246962Smjacob *speed = mode_hdr->dev_spec & SMH_SA_SPEED_MASK; 264339213Sgibbs 264446962Smjacob if (params_to_get & SA_PARAM_COMPRESSION) { 264554099Smjacob sa_comp_t *ntcs = (sa_comp_t *) &mode_blk[1]; 264646962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 264746962Smjacob struct scsi_data_compression_page *cp = &ntcs->dcomp; 264846962Smjacob *comp_supported = 264946962Smjacob (cp->dce_and_dcc & SA_DCP_DCC)? TRUE : FALSE; 265046962Smjacob *comp_enabled = 265146962Smjacob (cp->dce_and_dcc & SA_DCP_DCE)? TRUE : FALSE; 265246962Smjacob *comp_algorithm = scsi_4btoul(cp->comp_algorithm); 265346962Smjacob } else { 265446962Smjacob struct scsi_dev_conf_page *cp = &ntcs->dconf; 265546962Smjacob /* 265646962Smjacob * We don't really know whether this device supports 265746962Smjacob * Data Compression if the the algorithm field is 265846962Smjacob * zero. Just say we do. 265946962Smjacob */ 266046962Smjacob *comp_supported = TRUE; 266146962Smjacob *comp_enabled = 266246962Smjacob (cp->sel_comp_alg != SA_COMP_NONE)? TRUE : FALSE; 266346962Smjacob *comp_algorithm = cp->sel_comp_alg; 266441906Smjacob } 266546962Smjacob if (tcs != NULL) 266654099Smjacob bcopy(ntcs, tcs, sizeof (sa_comp_t)); 266739213Sgibbs } 266839213Sgibbs 266946962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 267046962Smjacob int idx; 267146962Smjacob char *xyz = mode_buffer; 267246962Smjacob xpt_print_path(periph->path); 267346962Smjacob printf("Mode Sense Data="); 267446962Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 267546962Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 267646962Smjacob printf("\n"); 267746962Smjacob } 267846962Smjacob 267939213Sgibbssagetparamsexit: 268039213Sgibbs 268139213Sgibbs xpt_release_ccb(ccb); 2682169562Sscottl free(mode_buffer, M_SCSISA); 268354099Smjacob return (error); 268439213Sgibbs} 268539213Sgibbs 268639213Sgibbs/* 268739213Sgibbs * The purpose of this function is to set one of four different parameters 268839213Sgibbs * for a tape drive: 268939213Sgibbs * - blocksize 269039213Sgibbs * - density 269139213Sgibbs * - compression / compression algorithm 269239213Sgibbs * - buffering mode 269339213Sgibbs * 269439213Sgibbs * The assumption is that this will be called from saioctl(), and therefore 269539213Sgibbs * from a process context. Thus the waiting malloc calls below. If that 269639213Sgibbs * assumption ever changes, the malloc calls should be changed to be 269739213Sgibbs * NOWAIT mallocs. 269839213Sgibbs * 269939213Sgibbs * Any or all of the four parameters may be set when this function is 270039213Sgibbs * called. It should handle setting more than one parameter at once. 270139213Sgibbs */ 270239213Sgibbsstatic int 270339213Sgibbssasetparams(struct cam_periph *periph, sa_params params_to_set, 270446962Smjacob u_int32_t blocksize, u_int8_t density, u_int32_t calg, 270542563Smjacob u_int32_t sense_flags) 270639213Sgibbs{ 270739213Sgibbs struct sa_softc *softc; 270839213Sgibbs u_int32_t current_blocksize; 270946962Smjacob u_int32_t current_calg; 271039213Sgibbs u_int8_t current_density; 271139213Sgibbs u_int8_t current_speed; 271239213Sgibbs int comp_enabled, comp_supported; 271339213Sgibbs void *mode_buffer; 271439213Sgibbs int mode_buffer_len; 271539213Sgibbs struct scsi_mode_header_6 *mode_hdr; 271639213Sgibbs struct scsi_mode_blk_desc *mode_blk; 271746962Smjacob sa_comp_t *ccomp, *cpage; 271839213Sgibbs int buff_mode; 271946962Smjacob union ccb *ccb = NULL; 272039213Sgibbs int error; 272139213Sgibbs 272239213Sgibbs softc = (struct sa_softc *)periph->softc; 272339213Sgibbs 2724170830Sscottl ccomp = malloc(sizeof (sa_comp_t), M_SCSISA, M_NOWAIT); 2725170830Sscottl if (ccomp == NULL) 2726170830Sscottl return (ENOMEM); 272739213Sgibbs 272839213Sgibbs /* 272939213Sgibbs * Since it doesn't make sense to set the number of blocks, or 273039213Sgibbs * write protection, we won't try to get the current value. We 273139213Sgibbs * always want to get the blocksize, so we can set it back to the 273239213Sgibbs * proper value. 273339213Sgibbs */ 273446962Smjacob error = sagetparams(periph, 273546962Smjacob params_to_set | SA_PARAM_BLOCKSIZE | SA_PARAM_SPEED, 273646962Smjacob ¤t_blocksize, ¤t_density, NULL, &buff_mode, NULL, 273746962Smjacob ¤t_speed, &comp_supported, &comp_enabled, 273846962Smjacob ¤t_calg, ccomp); 273939213Sgibbs 274039213Sgibbs if (error != 0) { 2741169562Sscottl free(ccomp, M_SCSISA); 274254099Smjacob return (error); 274339213Sgibbs } 274439213Sgibbs 274539213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 274639213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 274746962Smjacob mode_buffer_len += sizeof (sa_comp_t); 274839213Sgibbs 2749170830Sscottl mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_NOWAIT | M_ZERO); 2750170830Sscottl if (mode_buffer == NULL) { 2751170830Sscottl free(ccomp, M_SCSISA); 2752170830Sscottl return (ENOMEM); 2753170830Sscottl } 275439213Sgibbs 275539213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 275639213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 275739213Sgibbs 275853259Smjacob ccb = cam_periph_getccb(periph, 1); 275953259Smjacob 276053259Smjacobretry: 276153259Smjacob 276239213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) { 276353259Smjacob if (mode_blk) { 276453259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 276553259Smjacob } else { 276653259Smjacob cpage = (sa_comp_t *)&mode_hdr[1]; 276753259Smjacob } 276846962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 276954099Smjacob cpage->hdr.pagecode &= ~0x80; 277039213Sgibbs } else 277146962Smjacob cpage = NULL; 277239213Sgibbs 277339213Sgibbs /* 277439213Sgibbs * If the caller wants us to set the blocksize, use the one they 277539213Sgibbs * pass in. Otherwise, use the blocksize we got back from the 277639213Sgibbs * mode select above. 277739213Sgibbs */ 277853259Smjacob if (mode_blk) { 277953259Smjacob if (params_to_set & SA_PARAM_BLOCKSIZE) 278053259Smjacob scsi_ulto3b(blocksize, mode_blk->blklen); 278153259Smjacob else 278253259Smjacob scsi_ulto3b(current_blocksize, mode_blk->blklen); 278339213Sgibbs 278453259Smjacob /* 278553259Smjacob * Set density if requested, else preserve old density. 278653259Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 278753259Smjacob * devices, else density we've latched up in our softc. 278853259Smjacob */ 278953259Smjacob if (params_to_set & SA_PARAM_DENSITY) { 279053259Smjacob mode_blk->density = density; 279153259Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 279253259Smjacob mode_blk->density = SCSI_SAME_DENSITY; 279353259Smjacob } else { 279453259Smjacob mode_blk->density = softc->media_density; 279553259Smjacob } 279641674Smjacob } 279739213Sgibbs 279839213Sgibbs /* 279939213Sgibbs * For mode selects, these two fields must be zero. 280039213Sgibbs */ 280139213Sgibbs mode_hdr->data_length = 0; 280239213Sgibbs mode_hdr->medium_type = 0; 280339213Sgibbs 280439213Sgibbs /* set the speed to the current value */ 280539213Sgibbs mode_hdr->dev_spec = current_speed; 280639213Sgibbs 2807120019Smjacob /* if set, set single-initiator buffering mode */ 2808120019Smjacob if (softc->buffer_mode == SMH_SA_BUF_MODE_SIBUF) { 2809120019Smjacob mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF; 2810120019Smjacob } 281139213Sgibbs 281253259Smjacob if (mode_blk) 281353259Smjacob mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc); 281453259Smjacob else 281553259Smjacob mode_hdr->blk_desc_len = 0; 281639213Sgibbs 281739213Sgibbs /* 281839213Sgibbs * First, if the user wants us to set the compression algorithm or 281939213Sgibbs * just turn compression on, check to make sure that this drive 282039213Sgibbs * supports compression. 282139213Sgibbs */ 282246962Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 282339213Sgibbs /* 282439213Sgibbs * If the compression algorithm is 0, disable compression. 282539213Sgibbs * If the compression algorithm is non-zero, enable 282639213Sgibbs * compression and set the compression type to the 282739213Sgibbs * specified compression algorithm, unless the algorithm is 282839213Sgibbs * MT_COMP_ENABLE. In that case, we look at the 282939213Sgibbs * compression algorithm that is currently set and if it is 283039213Sgibbs * non-zero, we leave it as-is. If it is zero, and we have 283139213Sgibbs * saved a compression algorithm from a time when 283239213Sgibbs * compression was enabled before, set the compression to 283339213Sgibbs * the saved value. 283439213Sgibbs */ 283554099Smjacob switch (ccomp->hdr.pagecode & ~0x80) { 2836115660Smjacob case SA_DEVICE_CONFIGURATION_PAGE: 2837115660Smjacob { 2838115660Smjacob struct scsi_dev_conf_page *dcp = &cpage->dconf; 2839115660Smjacob if (calg == 0) { 2840115660Smjacob dcp->sel_comp_alg = SA_COMP_NONE; 2841115660Smjacob break; 2842115660Smjacob } 2843115660Smjacob if (calg != MT_COMP_ENABLE) { 2844115660Smjacob dcp->sel_comp_alg = calg; 2845115660Smjacob } else if (dcp->sel_comp_alg == SA_COMP_NONE && 2846115660Smjacob softc->saved_comp_algorithm != 0) { 2847115660Smjacob dcp->sel_comp_alg = softc->saved_comp_algorithm; 2848115660Smjacob } 2849115660Smjacob break; 2850115660Smjacob } 285146962Smjacob case SA_DATA_COMPRESSION_PAGE: 285246962Smjacob if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) { 285346962Smjacob struct scsi_data_compression_page *dcp = &cpage->dcomp; 285446962Smjacob if (calg == 0) { 285554099Smjacob /* 285654099Smjacob * Disable compression, but leave the 285754099Smjacob * decompression and the capability bit 285854099Smjacob * alone. 285954099Smjacob */ 286054099Smjacob dcp->dce_and_dcc = SA_DCP_DCC; 286154099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 286246962Smjacob break; 286346962Smjacob } 286453259Smjacob /* enable compression && decompression */ 286554099Smjacob dcp->dce_and_dcc = SA_DCP_DCE | SA_DCP_DCC; 286654099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 286753259Smjacob /* 286853259Smjacob * If there, use compression algorithm from caller. 286953259Smjacob * Otherwise, if there's a saved compression algorithm 287053259Smjacob * and there is no current algorithm, use the saved 287153259Smjacob * algorithm. Else parrot back what we got and hope 287253259Smjacob * for the best. 287353259Smjacob */ 287446962Smjacob if (calg != MT_COMP_ENABLE) { 287546962Smjacob scsi_ulto4b(calg, dcp->comp_algorithm); 287653259Smjacob scsi_ulto4b(calg, dcp->decomp_algorithm); 287746962Smjacob } else if (scsi_4btoul(dcp->comp_algorithm) == 0 && 287846962Smjacob softc->saved_comp_algorithm != 0) { 287939213Sgibbs scsi_ulto4b(softc->saved_comp_algorithm, 288046962Smjacob dcp->comp_algorithm); 288153259Smjacob scsi_ulto4b(softc->saved_comp_algorithm, 288253259Smjacob dcp->decomp_algorithm); 288339213Sgibbs } 288446962Smjacob break; 288539213Sgibbs } 2886115660Smjacob /* 2887115660Smjacob * Compression does not appear to be supported- 2888115660Smjacob * at least via the DATA COMPRESSION page. It 2889115660Smjacob * would be too much to ask us to believe that 2890115660Smjacob * the page itself is supported, but incorrectly 2891115660Smjacob * reports an ability to manipulate data compression, 2892115660Smjacob * so we'll assume that this device doesn't support 2893115660Smjacob * compression. We can just fall through for that. 2894115660Smjacob */ 2895115660Smjacob /* FALLTHROUGH */ 289646962Smjacob default: 289746962Smjacob /* 289854099Smjacob * The drive doesn't seem to support compression, 289946962Smjacob * so turn off the set compression bit. 290046962Smjacob */ 290146962Smjacob params_to_set &= ~SA_PARAM_COMPRESSION; 2902164906Smjacob xpt_print(periph->path, 2903164906Smjacob "device does not seem to support compression\n"); 290454099Smjacob 290546962Smjacob /* 290646962Smjacob * If that was the only thing the user wanted us to set, 290746962Smjacob * clean up allocated resources and return with 290846962Smjacob * 'operation not supported'. 290946962Smjacob */ 291046962Smjacob if (params_to_set == SA_PARAM_NONE) { 2911169562Sscottl free(mode_buffer, M_SCSISA); 291254099Smjacob xpt_release_ccb(ccb); 291354099Smjacob return (ENODEV); 291446962Smjacob } 291546962Smjacob 291646962Smjacob /* 291746962Smjacob * That wasn't the only thing the user wanted us to set. 291846962Smjacob * So, decrease the stated mode buffer length by the 291946962Smjacob * size of the compression mode page. 292046962Smjacob */ 292146962Smjacob mode_buffer_len -= sizeof(sa_comp_t); 292246962Smjacob } 292339213Sgibbs } 292439213Sgibbs 292546962Smjacob /* It is safe to retry this operation */ 292646962Smjacob scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 292746962Smjacob (params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE, 292879100Smjacob FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 292941674Smjacob 293046962Smjacob error = cam_periph_runccb(ccb, saerror, 0, 2931112006Sphk sense_flags, softc->device_stats); 293254099Smjacob QFRLS(ccb); 293339213Sgibbs 293446962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 293541906Smjacob int idx; 293641674Smjacob char *xyz = mode_buffer; 293741674Smjacob xpt_print_path(periph->path); 293842009Smjacob printf("Err%d, Mode Select Data=", error); 293941906Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 294042009Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 294141674Smjacob printf("\n"); 294241674Smjacob } 294341674Smjacob 294439213Sgibbs 294553259Smjacob if (error) { 294639213Sgibbs /* 294753259Smjacob * If we can, try without setting density/blocksize. 294853259Smjacob */ 294953259Smjacob if (mode_blk) { 295053259Smjacob if ((params_to_set & 295153259Smjacob (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) { 295253259Smjacob mode_blk = NULL; 295353259Smjacob goto retry; 295453259Smjacob } 295553259Smjacob } else { 295653259Smjacob mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 295753259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 295853259Smjacob } 295953259Smjacob 296053259Smjacob /* 296139213Sgibbs * If we were setting the blocksize, and that failed, we 296239213Sgibbs * want to set it to its original value. If we weren't 296339213Sgibbs * setting the blocksize, we don't want to change it. 296439213Sgibbs */ 296539213Sgibbs scsi_ulto3b(current_blocksize, mode_blk->blklen); 296639213Sgibbs 296739213Sgibbs /* 296841674Smjacob * Set density if requested, else preserve old density. 296941674Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 297041674Smjacob * devices, else density we've latched up in our softc. 297139213Sgibbs */ 297241674Smjacob if (params_to_set & SA_PARAM_DENSITY) { 297339213Sgibbs mode_blk->density = current_density; 297441674Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 297541674Smjacob mode_blk->density = SCSI_SAME_DENSITY; 297641674Smjacob } else { 297741674Smjacob mode_blk->density = softc->media_density; 297841674Smjacob } 297939213Sgibbs 298039213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 298146962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 298239213Sgibbs 298339213Sgibbs /* 298439213Sgibbs * The retry count is the only CCB field that might have been 298539213Sgibbs * changed that we care about, so reset it back to 1. 298639213Sgibbs */ 298739213Sgibbs ccb->ccb_h.retry_count = 1; 298854099Smjacob cam_periph_runccb(ccb, saerror, 0, sense_flags, 2989112006Sphk softc->device_stats); 299054099Smjacob QFRLS(ccb); 299139213Sgibbs } 299239213Sgibbs 299353259Smjacob xpt_release_ccb(ccb); 299453259Smjacob 299546962Smjacob if (ccomp != NULL) 2996169562Sscottl free(ccomp, M_SCSISA); 299739213Sgibbs 299841948Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 299941948Smjacob if (error) { 300041948Smjacob softc->flags &= ~SA_FLAG_COMP_ENABLED; 300146962Smjacob /* 300246962Smjacob * Even if we get an error setting compression, 300346962Smjacob * do not say that we don't support it. We could 300446962Smjacob * have been wrong, or it may be media specific. 300546962Smjacob * softc->flags &= ~SA_FLAG_COMP_SUPP; 300646962Smjacob */ 300741948Smjacob softc->saved_comp_algorithm = softc->comp_algorithm; 300841948Smjacob softc->comp_algorithm = 0; 300941948Smjacob } else { 301041948Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 301146962Smjacob softc->comp_algorithm = calg; 301241948Smjacob } 301341948Smjacob } 301441948Smjacob 3015169562Sscottl free(mode_buffer, M_SCSISA); 301654099Smjacob return (error); 301739213Sgibbs} 301839213Sgibbs 301939213Sgibbsstatic void 302039213Sgibbssaprevent(struct cam_periph *periph, int action) 302139213Sgibbs{ 302239213Sgibbs struct sa_softc *softc; 302339213Sgibbs union ccb *ccb; 302442735Smjacob int error, sf; 302539213Sgibbs 302639213Sgibbs softc = (struct sa_softc *)periph->softc; 302739213Sgibbs 302842735Smjacob if ((action == PR_ALLOW) && (softc->flags & SA_FLAG_TAPE_LOCKED) == 0) 302939213Sgibbs return; 303042735Smjacob if ((action == PR_PREVENT) && (softc->flags & SA_FLAG_TAPE_LOCKED) != 0) 303142735Smjacob return; 303239213Sgibbs 303356981Smjacob /* 303456981Smjacob * We can be quiet about illegal requests. 303556981Smjacob */ 303656981Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 303742735Smjacob sf = 0; 303856981Smjacob } else 303942735Smjacob sf = SF_QUIET_IR; 304042735Smjacob 304142716Smjacob ccb = cam_periph_getccb(periph, 1); 304239213Sgibbs 304342716Smjacob /* It is safe to retry this operation */ 304442716Smjacob scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action, 304579100Smjacob SSD_FULL_SIZE, SCSIOP_TIMEOUT); 304639213Sgibbs 3047112006Sphk error = cam_periph_runccb(ccb, saerror, 0, sf, softc->device_stats); 304853522Smjacob QFRLS(ccb); 304939213Sgibbs if (error == 0) { 305039213Sgibbs if (action == PR_ALLOW) 305139213Sgibbs softc->flags &= ~SA_FLAG_TAPE_LOCKED; 305239213Sgibbs else 305339213Sgibbs softc->flags |= SA_FLAG_TAPE_LOCKED; 305439213Sgibbs } 305539213Sgibbs 305639213Sgibbs xpt_release_ccb(ccb); 305739213Sgibbs} 305839213Sgibbs 305939213Sgibbsstatic int 306039213Sgibbssarewind(struct cam_periph *periph) 306139213Sgibbs{ 306239213Sgibbs union ccb *ccb; 306339213Sgibbs struct sa_softc *softc; 306439213Sgibbs int error; 306539213Sgibbs 306639213Sgibbs softc = (struct sa_softc *)periph->softc; 306739213Sgibbs 306846962Smjacob ccb = cam_periph_getccb(periph, 1); 306939213Sgibbs 307042716Smjacob /* It is safe to retry this operation */ 307146962Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 307253259Smjacob SSD_FULL_SIZE, REWIND_TIMEOUT); 307339213Sgibbs 307443636Smjacob softc->dsreg = MTIO_DSREG_REW; 3075112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 307643636Smjacob softc->dsreg = MTIO_DSREG_REST; 307739213Sgibbs 307839213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 307942716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 308042716Smjacob 308139213Sgibbs xpt_release_ccb(ccb); 308243636Smjacob if (error == 0) 308343636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 308443636Smjacob else 308543636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 308639213Sgibbs return (error); 308739213Sgibbs} 308839213Sgibbs 308939213Sgibbsstatic int 309039213Sgibbssaspace(struct cam_periph *periph, int count, scsi_space_code code) 309139213Sgibbs{ 309239213Sgibbs union ccb *ccb; 309339213Sgibbs struct sa_softc *softc; 309439213Sgibbs int error; 309539213Sgibbs 309639213Sgibbs softc = (struct sa_softc *)periph->softc; 309739213Sgibbs 309846962Smjacob ccb = cam_periph_getccb(periph, 1); 309939213Sgibbs 310042716Smjacob /* This cannot be retried */ 310139213Sgibbs 310242716Smjacob scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count, 310353259Smjacob SSD_FULL_SIZE, SPACE_TIMEOUT); 310439213Sgibbs 310571087Smjacob /* 310671087Smjacob * Clear residual because we will be using it. 310771087Smjacob */ 310871087Smjacob softc->last_ctl_resid = 0; 310971087Smjacob 311043636Smjacob softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD; 3111112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 311243636Smjacob softc->dsreg = MTIO_DSREG_REST; 311342716Smjacob 311439213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 311542716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 311642716Smjacob 311739213Sgibbs xpt_release_ccb(ccb); 311843636Smjacob 311942716Smjacob /* 312043636Smjacob * If a spacing operation has failed, we need to invalidate 312143636Smjacob * this mount. 312243636Smjacob * 312343636Smjacob * If the spacing operation was setmarks or to end of recorded data, 312443636Smjacob * we no longer know our relative position. 312543636Smjacob * 312671087Smjacob * If the spacing operations was spacing files in reverse, we 312771087Smjacob * take account of the residual, but still check against less 312871087Smjacob * than zero- if we've gone negative, we must have hit BOT. 312971087Smjacob * 313071087Smjacob * If the spacing operations was spacing records in reverse and 313171087Smjacob * we have a residual, we've either hit BOT or hit a filemark. 313271087Smjacob * In the former case, we know our new record number (0). In 313371087Smjacob * the latter case, we have absolutely no idea what the real 313471087Smjacob * record number is- we've stopped between the end of the last 313571087Smjacob * record in the previous file and the filemark that stopped 313671087Smjacob * our spacing backwards. 313742716Smjacob */ 313843636Smjacob if (error) { 313943636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 314043636Smjacob } else if (code == SS_SETMARKS || code == SS_EOD) { 314143636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 314243636Smjacob } else if (code == SS_FILEMARKS && softc->fileno != (daddr_t) -1) { 314371087Smjacob softc->fileno += (count - softc->last_ctl_resid); 314471087Smjacob if (softc->fileno < 0) /* we must of hit BOT */ 314571087Smjacob softc->fileno = 0; 314643636Smjacob softc->blkno = 0; 314743636Smjacob } else if (code == SS_BLOCKS && softc->blkno != (daddr_t) -1) { 314871087Smjacob softc->blkno += (count - softc->last_ctl_resid); 314971087Smjacob if (count < 0) { 315071087Smjacob if (softc->last_ctl_resid || softc->blkno < 0) { 315171087Smjacob if (softc->fileno == 0) { 315271087Smjacob softc->blkno = 0; 315371087Smjacob } else { 315471087Smjacob softc->blkno = (daddr_t) -1; 315571087Smjacob } 315671087Smjacob } 315771087Smjacob } 315843636Smjacob } 315939213Sgibbs return (error); 316039213Sgibbs} 316139213Sgibbs 316239213Sgibbsstatic int 316339213Sgibbssawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks) 316439213Sgibbs{ 316539213Sgibbs union ccb *ccb; 316639213Sgibbs struct sa_softc *softc; 316771087Smjacob int error, nwm = 0; 316839213Sgibbs 316939213Sgibbs softc = (struct sa_softc *)periph->softc; 3170154360Smjacob if (softc->open_rdonly) 3171154360Smjacob return (EBADF); 317239213Sgibbs 317346962Smjacob ccb = cam_periph_getccb(periph, 1); 317471087Smjacob /* 317571087Smjacob * Clear residual because we will be using it. 317671087Smjacob */ 317771087Smjacob softc->last_ctl_resid = 0; 317839213Sgibbs 317943636Smjacob softc->dsreg = MTIO_DSREG_FMK; 318042716Smjacob /* this *must* not be retried */ 318142716Smjacob scsi_write_filemarks(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, 318279100Smjacob FALSE, setmarks, nmarks, SSD_FULL_SIZE, IO_TIMEOUT); 318343636Smjacob softc->dsreg = MTIO_DSREG_REST; 318439213Sgibbs 318543636Smjacob 3186112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 318739213Sgibbs 318839213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 318942716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 319039213Sgibbs 319141918Smjacob if (error == 0 && nmarks) { 319241918Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 319371087Smjacob nwm = nmarks - softc->last_ctl_resid; 319471087Smjacob softc->filemarks += nwm; 319539213Sgibbs } 319671087Smjacob 319741918Smjacob xpt_release_ccb(ccb); 319843636Smjacob 319943636Smjacob /* 320043636Smjacob * Update relative positions (if we're doing that). 320143636Smjacob */ 320243636Smjacob if (error) { 320343636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 320443636Smjacob } else if (softc->fileno != (daddr_t) -1) { 320571087Smjacob softc->fileno += nwm; 320643636Smjacob softc->blkno = 0; 320743636Smjacob } 320841918Smjacob return (error); 320941918Smjacob} 321039213Sgibbs 321141918Smjacobstatic int 321241918Smjacobsardpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 321341918Smjacob{ 321441918Smjacob struct scsi_tape_position_data loc; 321541918Smjacob union ccb *ccb; 321646962Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 321741918Smjacob int error; 321841918Smjacob 321941918Smjacob /* 322071082Smjacob * We try and flush any buffered writes here if we were writing 322171082Smjacob * and we're trying to get hardware block position. It eats 322271082Smjacob * up performance substantially, but I'm wary of drive firmware. 322346962Smjacob * 322471082Smjacob * I think that *logical* block position is probably okay- 322571082Smjacob * but hardware block position might have to wait for data 322671082Smjacob * to hit media to be valid. Caveat Emptor. 322741918Smjacob */ 322841918Smjacob 322971082Smjacob if (hard && (softc->flags & SA_FLAG_TAPE_WRITTEN)) { 323046962Smjacob error = sawritefilemarks(periph, 0, 0); 323146962Smjacob if (error && error != EACCES) 323246962Smjacob return (error); 323346962Smjacob } 323441918Smjacob 323566678Smjacob ccb = cam_periph_getccb(periph, 1); 323641918Smjacob scsi_read_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 323779100Smjacob hard, &loc, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 323843636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 3239112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 324043636Smjacob softc->dsreg = MTIO_DSREG_REST; 324141918Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 324241918Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 324341918Smjacob 324441918Smjacob if (error == 0) { 324541918Smjacob if (loc.flags & SA_RPOS_UNCERTAIN) { 324641918Smjacob error = EINVAL; /* nothing is certain */ 324741918Smjacob } else { 324841918Smjacob *blkptr = scsi_4btoul(loc.firstblk); 324941918Smjacob } 325041918Smjacob } 325141918Smjacob 325239213Sgibbs xpt_release_ccb(ccb); 325339213Sgibbs return (error); 325439213Sgibbs} 325539213Sgibbs 325639213Sgibbsstatic int 325741918Smjacobsasetpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 325841918Smjacob{ 325941918Smjacob union ccb *ccb; 326041918Smjacob struct sa_softc *softc; 326141918Smjacob int error; 326241918Smjacob 326341918Smjacob /* 326446962Smjacob * We used to try and flush any buffered writes here. 326546962Smjacob * Now we push this onto user applications to either 326646962Smjacob * flush the pending writes themselves (via a zero count 326746962Smjacob * WRITE FILEMARKS command) or they can trust their tape 326846962Smjacob * drive to do this correctly for them. 326946962Smjacob */ 327041918Smjacob 327141918Smjacob softc = (struct sa_softc *)periph->softc; 327246962Smjacob ccb = cam_periph_getccb(periph, 1); 327341918Smjacob 327443636Smjacob 327541918Smjacob scsi_set_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 327679100Smjacob hard, *blkptr, SSD_FULL_SIZE, SPACE_TIMEOUT); 327743636Smjacob 327879100Smjacob 327943636Smjacob softc->dsreg = MTIO_DSREG_POS; 3280112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 328143636Smjacob softc->dsreg = MTIO_DSREG_REST; 328241918Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 328341918Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 328441918Smjacob xpt_release_ccb(ccb); 328541918Smjacob /* 328646962Smjacob * Note relative file && block number position as now unknown. 328741918Smjacob */ 328843636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 328941918Smjacob return (error); 329041918Smjacob} 329141918Smjacob 329241918Smjacobstatic int 329339213Sgibbssaretension(struct cam_periph *periph) 329439213Sgibbs{ 329539213Sgibbs union ccb *ccb; 329639213Sgibbs struct sa_softc *softc; 329739213Sgibbs int error; 329839213Sgibbs 329939213Sgibbs softc = (struct sa_softc *)periph->softc; 330039213Sgibbs 330146962Smjacob ccb = cam_periph_getccb(periph, 1); 330239213Sgibbs 330342716Smjacob /* It is safe to retry this operation */ 330442716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 330553259Smjacob FALSE, TRUE, TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT); 330639213Sgibbs 330743636Smjacob softc->dsreg = MTIO_DSREG_TEN; 3308112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 330943636Smjacob softc->dsreg = MTIO_DSREG_REST; 331039213Sgibbs 331139213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 331242716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 331339213Sgibbs xpt_release_ccb(ccb); 331443636Smjacob if (error == 0) 331543636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 331643636Smjacob else 331743636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 331854099Smjacob return (error); 331939213Sgibbs} 332039213Sgibbs 332139213Sgibbsstatic int 332239213Sgibbssareservereleaseunit(struct cam_periph *periph, int reserve) 332339213Sgibbs{ 332439213Sgibbs union ccb *ccb; 332539213Sgibbs struct sa_softc *softc; 332654099Smjacob int error; 332739213Sgibbs 332842009Smjacob softc = (struct sa_softc *)periph->softc; 332942716Smjacob ccb = cam_periph_getccb(periph, 1); 333039213Sgibbs 333142716Smjacob /* It is safe to retry this operation */ 333254099Smjacob scsi_reserve_release_unit(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 333379100Smjacob FALSE, 0, SSD_FULL_SIZE, SCSIOP_TIMEOUT, reserve); 333443636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 333554099Smjacob error = cam_periph_runccb(ccb, saerror, 0, 3336112006Sphk SF_RETRY_UA | SF_NO_PRINT, softc->device_stats); 333743636Smjacob softc->dsreg = MTIO_DSREG_REST; 333854099Smjacob QFRLS(ccb); 333939213Sgibbs xpt_release_ccb(ccb); 334039213Sgibbs 334141674Smjacob /* 334241674Smjacob * If the error was Illegal Request, then the device doesn't support 334341674Smjacob * RESERVE/RELEASE. This is not an error. 334441674Smjacob */ 334542009Smjacob if (error == EINVAL) { 334641674Smjacob error = 0; 334742009Smjacob } 334841674Smjacob 334939213Sgibbs return (error); 335039213Sgibbs} 335139213Sgibbs 335239213Sgibbsstatic int 335339213Sgibbssaloadunload(struct cam_periph *periph, int load) 335439213Sgibbs{ 335539213Sgibbs union ccb *ccb; 335639213Sgibbs struct sa_softc *softc; 335739213Sgibbs int error; 335839213Sgibbs 335939213Sgibbs softc = (struct sa_softc *)periph->softc; 336039213Sgibbs 336146962Smjacob ccb = cam_periph_getccb(periph, 1); 336239213Sgibbs 336342716Smjacob /* It is safe to retry this operation */ 336442716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 336554099Smjacob FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT); 336639213Sgibbs 336743636Smjacob softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL; 3368112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 336943636Smjacob softc->dsreg = MTIO_DSREG_REST; 337054099Smjacob QFRLS(ccb); 337139213Sgibbs xpt_release_ccb(ccb); 337243636Smjacob 337343636Smjacob if (error || load == 0) 337443636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 337543636Smjacob else if (error == 0) 337643636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 337739213Sgibbs return (error); 337839213Sgibbs} 337939213Sgibbs 338039213Sgibbsstatic int 338139213Sgibbssaerase(struct cam_periph *periph, int longerase) 338239213Sgibbs{ 338339213Sgibbs 338439213Sgibbs union ccb *ccb; 338539213Sgibbs struct sa_softc *softc; 338639213Sgibbs int error; 338739213Sgibbs 338839213Sgibbs softc = (struct sa_softc *)periph->softc; 3389154360Smjacob if (softc->open_rdonly) 3390154360Smjacob return (EBADF); 339139213Sgibbs 339246962Smjacob ccb = cam_periph_getccb(periph, 1); 339339213Sgibbs 339443636Smjacob scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase, 339553259Smjacob SSD_FULL_SIZE, ERASE_TIMEOUT); 339639213Sgibbs 339743636Smjacob softc->dsreg = MTIO_DSREG_ZER; 3398112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 339943636Smjacob softc->dsreg = MTIO_DSREG_REST; 340039213Sgibbs 340139213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 340243636Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 340339213Sgibbs xpt_release_ccb(ccb); 340439213Sgibbs return (error); 340539213Sgibbs} 340639213Sgibbs 340755205Speter#endif /* _KERNEL */ 340839213Sgibbs 340939213Sgibbs/* 341039213Sgibbs * Read tape block limits command. 341139213Sgibbs */ 341239213Sgibbsvoid 341339213Sgibbsscsi_read_block_limits(struct ccb_scsiio *csio, u_int32_t retries, 341439213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 341539213Sgibbs u_int8_t tag_action, 341639213Sgibbs struct scsi_read_block_limits_data *rlimit_buf, 341739213Sgibbs u_int8_t sense_len, u_int32_t timeout) 341839213Sgibbs{ 341939213Sgibbs struct scsi_read_block_limits *scsi_cmd; 342039213Sgibbs 342146962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 342246962Smjacob (u_int8_t *)rlimit_buf, sizeof(*rlimit_buf), sense_len, 342346962Smjacob sizeof(*scsi_cmd), timeout); 342439213Sgibbs 342539213Sgibbs scsi_cmd = (struct scsi_read_block_limits *)&csio->cdb_io.cdb_bytes; 342639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 342739213Sgibbs scsi_cmd->opcode = READ_BLOCK_LIMITS; 342839213Sgibbs} 342939213Sgibbs 343039213Sgibbsvoid 343139213Sgibbsscsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries, 343239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 343339213Sgibbs u_int8_t tag_action, int readop, int sli, 343439213Sgibbs int fixed, u_int32_t length, u_int8_t *data_ptr, 343539213Sgibbs u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout) 343639213Sgibbs{ 343739213Sgibbs struct scsi_sa_rw *scsi_cmd; 343839213Sgibbs 343939213Sgibbs scsi_cmd = (struct scsi_sa_rw *)&csio->cdb_io.cdb_bytes; 344039213Sgibbs scsi_cmd->opcode = readop ? SA_READ : SA_WRITE; 344139213Sgibbs scsi_cmd->sli_fixed = 0; 344239213Sgibbs if (sli && readop) 344339213Sgibbs scsi_cmd->sli_fixed |= SAR_SLI; 344439213Sgibbs if (fixed) 344539213Sgibbs scsi_cmd->sli_fixed |= SARW_FIXED; 344639213Sgibbs scsi_ulto3b(length, scsi_cmd->length); 344739213Sgibbs scsi_cmd->control = 0; 344839213Sgibbs 344946962Smjacob cam_fill_csio(csio, retries, cbfcnp, readop ? CAM_DIR_IN : CAM_DIR_OUT, 345046962Smjacob tag_action, data_ptr, dxfer_len, sense_len, 345146962Smjacob sizeof(*scsi_cmd), timeout); 345239213Sgibbs} 345339213Sgibbs 345439213Sgibbsvoid 345539213Sgibbsscsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries, 345639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 345739213Sgibbs u_int8_t tag_action, int immediate, int eot, 345839213Sgibbs int reten, int load, u_int8_t sense_len, 345939213Sgibbs u_int32_t timeout) 346039213Sgibbs{ 346139213Sgibbs struct scsi_load_unload *scsi_cmd; 346239213Sgibbs 346339213Sgibbs scsi_cmd = (struct scsi_load_unload *)&csio->cdb_io.cdb_bytes; 346439213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 346539213Sgibbs scsi_cmd->opcode = LOAD_UNLOAD; 346639213Sgibbs if (immediate) 346739213Sgibbs scsi_cmd->immediate = SLU_IMMED; 346839213Sgibbs if (eot) 346939213Sgibbs scsi_cmd->eot_reten_load |= SLU_EOT; 347039213Sgibbs if (reten) 347139213Sgibbs scsi_cmd->eot_reten_load |= SLU_RETEN; 347239213Sgibbs if (load) 347339213Sgibbs scsi_cmd->eot_reten_load |= SLU_LOAD; 347439213Sgibbs 347546962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 347646962Smjacob NULL, 0, sense_len, sizeof(*scsi_cmd), timeout); 347739213Sgibbs} 347839213Sgibbs 347939213Sgibbsvoid 348039213Sgibbsscsi_rewind(struct ccb_scsiio *csio, u_int32_t retries, 348139213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 348239213Sgibbs u_int8_t tag_action, int immediate, u_int8_t sense_len, 348339213Sgibbs u_int32_t timeout) 348439213Sgibbs{ 348539213Sgibbs struct scsi_rewind *scsi_cmd; 348639213Sgibbs 348739213Sgibbs scsi_cmd = (struct scsi_rewind *)&csio->cdb_io.cdb_bytes; 348839213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 348939213Sgibbs scsi_cmd->opcode = REWIND; 349039213Sgibbs if (immediate) 349139213Sgibbs scsi_cmd->immediate = SREW_IMMED; 349239213Sgibbs 349346962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 349446962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 349539213Sgibbs} 349639213Sgibbs 349739213Sgibbsvoid 349839213Sgibbsscsi_space(struct ccb_scsiio *csio, u_int32_t retries, 349939213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 350039213Sgibbs u_int8_t tag_action, scsi_space_code code, 350139213Sgibbs u_int32_t count, u_int8_t sense_len, u_int32_t timeout) 350239213Sgibbs{ 350339213Sgibbs struct scsi_space *scsi_cmd; 350439213Sgibbs 350539213Sgibbs scsi_cmd = (struct scsi_space *)&csio->cdb_io.cdb_bytes; 350639213Sgibbs scsi_cmd->opcode = SPACE; 350739213Sgibbs scsi_cmd->code = code; 350839213Sgibbs scsi_ulto3b(count, scsi_cmd->count); 350939213Sgibbs scsi_cmd->control = 0; 351039213Sgibbs 351146962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 351246962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 351339213Sgibbs} 351439213Sgibbs 351539213Sgibbsvoid 351639213Sgibbsscsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries, 351739213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 351839213Sgibbs u_int8_t tag_action, int immediate, int setmark, 351939213Sgibbs u_int32_t num_marks, u_int8_t sense_len, 352039213Sgibbs u_int32_t timeout) 352139213Sgibbs{ 352239213Sgibbs struct scsi_write_filemarks *scsi_cmd; 352339213Sgibbs 352439213Sgibbs scsi_cmd = (struct scsi_write_filemarks *)&csio->cdb_io.cdb_bytes; 352539213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 352639213Sgibbs scsi_cmd->opcode = WRITE_FILEMARKS; 352739213Sgibbs if (immediate) 352839213Sgibbs scsi_cmd->byte2 |= SWFMRK_IMMED; 352939213Sgibbs if (setmark) 353039213Sgibbs scsi_cmd->byte2 |= SWFMRK_WSMK; 353139213Sgibbs 353239213Sgibbs scsi_ulto3b(num_marks, scsi_cmd->num_marks); 353339213Sgibbs 353446962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 353546962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 353639213Sgibbs} 353739213Sgibbs 353839213Sgibbs/* 353939213Sgibbs * The reserve and release unit commands differ only by their opcodes. 354039213Sgibbs */ 354139213Sgibbsvoid 354239213Sgibbsscsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries, 354339213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 354439213Sgibbs u_int8_t tag_action, int third_party, 354539213Sgibbs int third_party_id, u_int8_t sense_len, 354639213Sgibbs u_int32_t timeout, int reserve) 354739213Sgibbs{ 354839213Sgibbs struct scsi_reserve_release_unit *scsi_cmd; 354939213Sgibbs 355039213Sgibbs scsi_cmd = (struct scsi_reserve_release_unit *)&csio->cdb_io.cdb_bytes; 355139213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 355239213Sgibbs 355339213Sgibbs if (reserve) 355439213Sgibbs scsi_cmd->opcode = RESERVE_UNIT; 355539213Sgibbs else 355639213Sgibbs scsi_cmd->opcode = RELEASE_UNIT; 355739213Sgibbs 355839213Sgibbs if (third_party) { 355939213Sgibbs scsi_cmd->lun_thirdparty |= SRRU_3RD_PARTY; 356039213Sgibbs scsi_cmd->lun_thirdparty |= 356139213Sgibbs ((third_party_id << SRRU_3RD_SHAMT) & SRRU_3RD_MASK); 356239213Sgibbs } 356339213Sgibbs 356446962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 356546962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 356639213Sgibbs} 356739213Sgibbs 356839213Sgibbsvoid 356939213Sgibbsscsi_erase(struct ccb_scsiio *csio, u_int32_t retries, 357039213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 357139213Sgibbs u_int8_t tag_action, int immediate, int long_erase, 357239213Sgibbs u_int8_t sense_len, u_int32_t timeout) 357339213Sgibbs{ 357439213Sgibbs struct scsi_erase *scsi_cmd; 357539213Sgibbs 357639213Sgibbs scsi_cmd = (struct scsi_erase *)&csio->cdb_io.cdb_bytes; 357739213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 357839213Sgibbs 357939213Sgibbs scsi_cmd->opcode = ERASE; 358039213Sgibbs 358139213Sgibbs if (immediate) 358239213Sgibbs scsi_cmd->lun_imm_long |= SE_IMMED; 358339213Sgibbs 358439213Sgibbs if (long_erase) 358539213Sgibbs scsi_cmd->lun_imm_long |= SE_LONG; 358639213Sgibbs 358746962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 358846962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 358939213Sgibbs} 359041918Smjacob 359141918Smjacob/* 359241918Smjacob * Read Tape Position command. 359341918Smjacob */ 359441918Smjacobvoid 359541918Smjacobscsi_read_position(struct ccb_scsiio *csio, u_int32_t retries, 359641918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 359741918Smjacob u_int8_t tag_action, int hardsoft, 359841918Smjacob struct scsi_tape_position_data *sbp, 359941918Smjacob u_int8_t sense_len, u_int32_t timeout) 360041918Smjacob{ 360141918Smjacob struct scsi_tape_read_position *scmd; 360241918Smjacob 360341918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 360441918Smjacob (u_int8_t *)sbp, sizeof (*sbp), sense_len, sizeof(*scmd), timeout); 360541918Smjacob scmd = (struct scsi_tape_read_position *)&csio->cdb_io.cdb_bytes; 360641918Smjacob bzero(scmd, sizeof(*scmd)); 360741918Smjacob scmd->opcode = READ_POSITION; 360841918Smjacob scmd->byte1 = hardsoft; 360941918Smjacob} 361041918Smjacob 361141918Smjacob/* 361241918Smjacob * Set Tape Position command. 361341918Smjacob */ 361441918Smjacobvoid 361541918Smjacobscsi_set_position(struct ccb_scsiio *csio, u_int32_t retries, 361641918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 361741918Smjacob u_int8_t tag_action, int hardsoft, u_int32_t blkno, 361841918Smjacob u_int8_t sense_len, u_int32_t timeout) 361941918Smjacob{ 362041918Smjacob struct scsi_tape_locate *scmd; 362141918Smjacob 362241918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 362341918Smjacob (u_int8_t *)NULL, 0, sense_len, sizeof(*scmd), timeout); 362441918Smjacob scmd = (struct scsi_tape_locate *)&csio->cdb_io.cdb_bytes; 362541918Smjacob bzero(scmd, sizeof(*scmd)); 362641918Smjacob scmd->opcode = LOCATE; 362741918Smjacob if (hardsoft) 362841918Smjacob scmd->byte1 |= SA_SPOS_BT; 362941918Smjacob scsi_ulto4b(blkno, scmd->blkaddr); 363041918Smjacob} 3631