scsi_sa.c revision 168752
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 168752 2007-04-15 08:49:19Z 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 17653283Smjacob/* units are bits 4-7, 16-21 (1024 units) */ 17753283Smjacob#define SAUNIT(DEV) \ 17853283Smjacob (((minor(DEV) & 0xF0) >> 4) | ((minor(DEV) & 0x3f0000) >> 16)) 17953283Smjacob 18053283Smjacob#define SAMODE(z) ((minor(z) & 0x3)) 18153283Smjacob#define SADENSITY(z) (((minor(z) >> 2) & 0x3)) 18253283Smjacob#define SA_IS_CTRL(z) (minor(z) & (1 << 29)) 18353283Smjacob 18453259Smjacob#define SA_NOT_CTLDEV 0 18553259Smjacob#define SA_CTLDEV 1 18653259Smjacob 18753259Smjacob#define SA_ATYPE_R 0 18853259Smjacob#define SA_ATYPE_NR 1 18953259Smjacob#define SA_ATYPE_ER 2 19053259Smjacob 19153259Smjacob#define SAMINOR(ctl, unit, mode, access) \ 19253283Smjacob ((ctl << 29) | ((unit & 0x3f0) << 16) | ((unit & 0xf) << 4) | \ 19353283Smjacob (mode << 0x2) | (access & 0x3)) 19453259Smjacob 19553259Smjacob#define SA_NUM_MODES 4 19653259Smjacobstruct sa_devs { 197130585Sphk struct cdev *ctl_dev; 19853259Smjacob struct sa_mode_devs { 199130585Sphk struct cdev *r_dev; 200130585Sphk struct cdev *nr_dev; 201130585Sphk struct cdev *er_dev; 20253259Smjacob } mode_devs[SA_NUM_MODES]; 20353259Smjacob}; 20453259Smjacob 20539213Sgibbsstruct sa_softc { 20639213Sgibbs sa_state state; 20739213Sgibbs sa_flags flags; 20839213Sgibbs sa_quirks quirks; 20959249Sphk struct bio_queue_head bio_queue; 21046962Smjacob int queue_count; 211112006Sphk struct devstat *device_stats; 21253259Smjacob struct sa_devs devs; 21339213Sgibbs int blk_gran; 21439213Sgibbs int blk_mask; 21539213Sgibbs int blk_shift; 21639213Sgibbs u_int32_t max_blk; 21739213Sgibbs u_int32_t min_blk; 21841674Smjacob u_int32_t comp_algorithm; 21941674Smjacob u_int32_t saved_comp_algorithm; 22039213Sgibbs u_int32_t media_blksize; 22141906Smjacob u_int32_t last_media_blksize; 22239213Sgibbs u_int32_t media_numblks; 22341674Smjacob u_int8_t media_density; 22439213Sgibbs u_int8_t speed; 22541674Smjacob u_int8_t scsi_rev; 22643636Smjacob u_int8_t dsreg; /* mtio mt_dsreg, redux */ 22739213Sgibbs int buffer_mode; 22839213Sgibbs int filemarks; 22939213Sgibbs union ccb saved_ccb; 23071268Smjacob int last_resid_was_io; 23146962Smjacob 23241948Smjacob /* 23343636Smjacob * Relative to BOT Location. 23443636Smjacob */ 23543636Smjacob daddr_t fileno; 23643636Smjacob daddr_t blkno; 23743636Smjacob 23843636Smjacob /* 23941948Smjacob * Latched Error Info 24041948Smjacob */ 24142009Smjacob struct { 24242009Smjacob struct scsi_sense_data _last_io_sense; 24342009Smjacob u_int32_t _last_io_resid; 24442009Smjacob u_int8_t _last_io_cdb[CAM_MAX_CDBLEN]; 24542009Smjacob struct scsi_sense_data _last_ctl_sense; 24642009Smjacob u_int32_t _last_ctl_resid; 24742009Smjacob u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN]; 24842009Smjacob#define last_io_sense errinfo._last_io_sense 24942009Smjacob#define last_io_resid errinfo._last_io_resid 25042009Smjacob#define last_io_cdb errinfo._last_io_cdb 25142009Smjacob#define last_ctl_sense errinfo._last_ctl_sense 25242009Smjacob#define last_ctl_resid errinfo._last_ctl_resid 25342009Smjacob#define last_ctl_cdb errinfo._last_ctl_cdb 25442009Smjacob } errinfo; 25543636Smjacob /* 25643636Smjacob * Misc other flags/state 25743636Smjacob */ 25843636Smjacob u_int32_t 259154360Smjacob : 29, 260154360Smjacob open_rdonly : 1, /* open read-only */ 261154360Smjacob open_pending_mount : 1, /* open pending mount */ 262154360Smjacob ctrl_mode : 1; /* control device open */ 26339213Sgibbs}; 26439213Sgibbs 26539213Sgibbsstruct sa_quirk_entry { 26642563Smjacob struct scsi_inquiry_pattern inq_pat; /* matching pattern */ 26742563Smjacob sa_quirks quirks; /* specific quirk type */ 26842563Smjacob u_int32_t prefblk; /* preferred blocksize when in fixed mode */ 26939213Sgibbs}; 27039213Sgibbs 27139213Sgibbsstatic struct sa_quirk_entry sa_quirk_table[] = 27239213Sgibbs{ 27339213Sgibbs { 27460235Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "OnStream", 27560235Smjacob "ADR*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_NODREAD | 27660235Smjacob SA_QUIRK_1FM|SA_QUIRK_NO_MODESEL, 32768 27760235Smjacob }, 27860235Smjacob { 27939213Sgibbs { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28077810Snon "Python 06408*", "*"}, SA_QUIRK_NODREAD, 0 28177581Snon }, 28277581Snon { 28377581Snon { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28456981Smjacob "Python 25601*", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_NODREAD, 0 28541351Sjoerg }, 28641351Sjoerg { 28742130Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28856981Smjacob "Python*", "*"}, SA_QUIRK_NODREAD, 0 28956981Smjacob }, 29056981Smjacob { 29156981Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 29243636Smjacob "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 29342130Smjacob }, 29442130Smjacob { 29542563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 29668500Smjacob "VIPER 2525 25462", "-011"}, 29768500Smjacob SA_QUIRK_NOCOMP|SA_QUIRK_1FM|SA_QUIRK_NODREAD, 0 29868500Smjacob }, 29968500Smjacob { 30068500Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 30146962Smjacob "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 30242563Smjacob }, 30371082Smjacob#if 0 30442563Smjacob { 30542533Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 30671082Smjacob "C15*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_NO_CPAGE, 0, 30771082Smjacob }, 30871082Smjacob#endif 309107943Strhodes { 310107943Strhodes { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 311107943Strhodes "C56*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 312107943Strhodes }, 31371082Smjacob { 31471082Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 31546962Smjacob "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 31646962Smjacob }, 31746962Smjacob { 31846962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 31944354Smjacob "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 32042533Smjacob }, 32142533Smjacob { 32242716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 32342716Smjacob "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 32442716Smjacob }, 32542716Smjacob { 32642716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", 32742716Smjacob "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 32842716Smjacob }, 32942716Smjacob { 33042716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA", 33142716Smjacob "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 33242716Smjacob }, 33351744Smjacob { /* jreynold@primenet.com */ 33451744Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 33551744Smjacob "STT8000N*", "*"}, SA_QUIRK_1FM, 0 33651744Smjacob }, 33751875Smjacob { /* mike@sentex.net */ 33851875Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 33951875Smjacob "STT20000*", "*"}, SA_QUIRK_1FM, 0 34051875Smjacob }, 34142716Smjacob { 34241351Sjoerg { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 34343636Smjacob " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 34442563Smjacob }, 34542563Smjacob { 34642563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 34747519Smjacob " TDC 3800", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 34847519Smjacob }, 34947519Smjacob { 35047519Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 35148192Smjacob " TDC 4100", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 35248192Smjacob }, 35348192Smjacob { 35448192Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 35543636Smjacob " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 35642563Smjacob }, 35742563Smjacob { 35846962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 35946962Smjacob " SLR*", "*"}, SA_QUIRK_1FM, 0 36046962Smjacob }, 36146962Smjacob { 36242563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 36343636Smjacob "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 36445752Smjacob }, 36545752Smjacob { 36645752Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 36745752Smjacob "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 36839213Sgibbs } 36939213Sgibbs}; 37039213Sgibbs 37139213Sgibbsstatic d_open_t saopen; 37239213Sgibbsstatic d_close_t saclose; 37339213Sgibbsstatic d_strategy_t sastrategy; 37439213Sgibbsstatic d_ioctl_t saioctl; 37539213Sgibbsstatic periph_init_t sainit; 37639213Sgibbsstatic periph_ctor_t saregister; 37740603Skenstatic periph_oninv_t saoninvalidate; 37839213Sgibbsstatic periph_dtor_t sacleanup; 37939213Sgibbsstatic periph_start_t sastart; 38039213Sgibbsstatic void saasync(void *callback_arg, u_int32_t code, 38139213Sgibbs struct cam_path *path, void *arg); 38239213Sgibbsstatic void sadone(struct cam_periph *periph, 38339213Sgibbs union ccb *start_ccb); 38439213Sgibbsstatic int saerror(union ccb *ccb, u_int32_t cam_flags, 38539213Sgibbs u_int32_t sense_flags); 38668114Smjacobstatic int samarkswanted(struct cam_periph *); 38739213Sgibbsstatic int sacheckeod(struct cam_periph *periph); 38839213Sgibbsstatic int sagetparams(struct cam_periph *periph, 38939213Sgibbs sa_params params_to_get, 39039213Sgibbs u_int32_t *blocksize, u_int8_t *density, 39139213Sgibbs u_int32_t *numblocks, int *buff_mode, 39239213Sgibbs u_int8_t *write_protect, u_int8_t *speed, 39339213Sgibbs int *comp_supported, int *comp_enabled, 39439213Sgibbs u_int32_t *comp_algorithm, 39546962Smjacob sa_comp_t *comp_page); 39639213Sgibbsstatic int sasetparams(struct cam_periph *periph, 39739213Sgibbs sa_params params_to_set, 39839213Sgibbs u_int32_t blocksize, u_int8_t density, 39942563Smjacob u_int32_t comp_algorithm, 40042563Smjacob u_int32_t sense_flags); 40139213Sgibbsstatic void saprevent(struct cam_periph *periph, int action); 40239213Sgibbsstatic int sarewind(struct cam_periph *periph); 40339213Sgibbsstatic int saspace(struct cam_periph *periph, int count, 40439213Sgibbs scsi_space_code code); 405130585Sphkstatic int samount(struct cam_periph *, int, struct cdev *); 40639213Sgibbsstatic int saretension(struct cam_periph *periph); 40739213Sgibbsstatic int sareservereleaseunit(struct cam_periph *periph, 40839213Sgibbs int reserve); 40939213Sgibbsstatic int saloadunload(struct cam_periph *periph, int load); 41039213Sgibbsstatic int saerase(struct cam_periph *periph, int longerase); 41139213Sgibbsstatic int sawritefilemarks(struct cam_periph *periph, 41239213Sgibbs int nmarks, int setmarks); 41341918Smjacobstatic int sardpos(struct cam_periph *periph, int, u_int32_t *); 41441918Smjacobstatic int sasetpos(struct cam_periph *periph, int, u_int32_t *); 41539213Sgibbs 41641918Smjacob 41739213Sgibbsstatic struct periph_driver sadriver = 41839213Sgibbs{ 41939213Sgibbs sainit, "sa", 42039213Sgibbs TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0 42139213Sgibbs}; 42239213Sgibbs 42372119SpeterPERIPHDRIVER_DECLARE(sa, sadriver); 42439213Sgibbs 42539213Sgibbs/* For 2.2-stable support */ 42639213Sgibbs#ifndef D_TAPE 42739213Sgibbs#define D_TAPE 0 42839213Sgibbs#endif 42939213Sgibbs 43039213Sgibbs 43147625Sphkstatic struct cdevsw sa_cdevsw = { 432126080Sphk .d_version = D_VERSION, 433111815Sphk .d_open = saopen, 434111815Sphk .d_close = saclose, 435111815Sphk .d_read = physread, 436111815Sphk .d_write = physwrite, 437111815Sphk .d_ioctl = saioctl, 438111815Sphk .d_strategy = sastrategy, 439111815Sphk .d_name = "sa", 440126080Sphk .d_flags = D_TAPE | D_NEEDGIANT, 44139213Sgibbs}; 44239213Sgibbs 44339213Sgibbsstatic int 444130585Sphksaopen(struct cdev *dev, int flags, int fmt, struct thread *td) 44539213Sgibbs{ 44639213Sgibbs struct cam_periph *periph; 44739213Sgibbs struct sa_softc *softc; 44839213Sgibbs int unit; 44939213Sgibbs int error; 45039213Sgibbs 45139213Sgibbs unit = SAUNIT(dev); 45239213Sgibbs 453101940Snjl periph = (struct cam_periph *)dev->si_drv1; 454168752Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 455168752Sscottl return (ENXIO); 45653259Smjacob } 457168752Sscottl 458168752Sscottl cam_periph_lock(periph); 459168752Sscottl 46039213Sgibbs softc = (struct sa_softc *)periph->softc; 46139213Sgibbs 46246962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 46346962Smjacob ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); 46439213Sgibbs 46543636Smjacob if (SA_IS_CTRL(dev)) { 46643636Smjacob softc->ctrl_mode = 1; 46753259Smjacob cam_periph_unlock(periph); 46843636Smjacob return (0); 46943636Smjacob } 47043636Smjacob 471168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 472168752Sscottl cam_periph_unlock(periph); 473168752Sscottl cam_periph_release(periph); 474168752Sscottl return (error); 475168752Sscottl } 476168752Sscottl 47753259Smjacob if (softc->flags & SA_FLAG_OPEN) { 47853259Smjacob error = EBUSY; 47953259Smjacob } else if (softc->flags & SA_FLAG_INVALID) { 48053259Smjacob error = ENXIO; 48153259Smjacob } else { 48253259Smjacob /* 483154360Smjacob * Preserve whether this is a read_only open. 484154360Smjacob */ 485154360Smjacob softc->open_rdonly = (flags & O_RDWR) == O_RDONLY; 486154360Smjacob 487154360Smjacob /* 48853259Smjacob * The function samount ensures media is loaded and ready. 48953259Smjacob * It also does a device RESERVE if the tape isn't yet mounted. 490154360Smjacob * 491154360Smjacob * If the mount fails and this was a non-blocking open, 492154360Smjacob * make this a 'open_pending_mount' action. 49353259Smjacob */ 49453259Smjacob error = samount(periph, flags, dev); 495154360Smjacob if (error && (flags & O_NONBLOCK)) { 496154360Smjacob softc->flags |= SA_FLAG_OPEN; 497154360Smjacob softc->open_pending_mount = 1; 498168752Sscottl cam_periph_unhold(periph); 499154360Smjacob cam_periph_unlock(periph); 500154360Smjacob return (0); 501154360Smjacob } 50239213Sgibbs } 50339213Sgibbs 50453259Smjacob if (error) { 505168752Sscottl cam_periph_unhold(periph); 506168752Sscottl cam_periph_unlock(periph); 50753259Smjacob cam_periph_release(periph); 508168752Sscottl return (error); 50939213Sgibbs } 510168752Sscottl 511168752Sscottl saprevent(periph, PR_PREVENT); 512168752Sscottl softc->flags |= SA_FLAG_OPEN; 513168752Sscottl 514168752Sscottl cam_periph_unhold(periph); 51539213Sgibbs cam_periph_unlock(periph); 51639213Sgibbs return (error); 51739213Sgibbs} 51839213Sgibbs 51939213Sgibbsstatic int 520130585Sphksaclose(struct cdev *dev, int flag, int fmt, struct thread *td) 52139213Sgibbs{ 52239213Sgibbs struct cam_periph *periph; 52339213Sgibbs struct sa_softc *softc; 52446962Smjacob int unit, mode, error, writing, tmp; 52542009Smjacob int closedbits = SA_FLAG_OPEN; 52639213Sgibbs 52739213Sgibbs unit = SAUNIT(dev); 52839213Sgibbs mode = SAMODE(dev); 529101940Snjl periph = (struct cam_periph *)dev->si_drv1; 53039213Sgibbs if (periph == NULL) 53139213Sgibbs return (ENXIO); 53239213Sgibbs 533168752Sscottl cam_periph_lock(periph); 534168752Sscottl 53539213Sgibbs softc = (struct sa_softc *)periph->softc; 53639213Sgibbs 53746962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 53846962Smjacob ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); 53946962Smjacob 54046962Smjacob 541154360Smjacob softc->open_rdonly = 0; 54243636Smjacob if (SA_IS_CTRL(dev)) { 54343636Smjacob softc->ctrl_mode = 0; 544168752Sscottl cam_periph_unlock(periph); 54553259Smjacob cam_periph_release(periph); 54643636Smjacob return (0); 54743636Smjacob } 54843636Smjacob 549154360Smjacob if (softc->open_pending_mount) { 550154360Smjacob softc->flags &= ~SA_FLAG_OPEN; 551154360Smjacob softc->open_pending_mount = 0; 552168752Sscottl cam_periph_unlock(periph); 553154360Smjacob cam_periph_release(periph); 554154360Smjacob return (0); 555154360Smjacob } 556154360Smjacob 557168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 558168752Sscottl cam_periph_unlock(periph); 559168752Sscottl return (error); 560168752Sscottl } 561168752Sscottl 56241906Smjacob /* 56346962Smjacob * Were we writing the tape? 56441906Smjacob */ 56546962Smjacob writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0; 56646962Smjacob 56746962Smjacob /* 56846962Smjacob * See whether or not we need to write filemarks. If this 56946962Smjacob * fails, we probably have to assume we've lost tape 57046962Smjacob * position. 57146962Smjacob */ 57241906Smjacob error = sacheckeod(periph); 57341906Smjacob if (error) { 574164906Smjacob xpt_print(periph->path, 575164906Smjacob "failed to write terminating filemark(s)\n"); 57646962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 57741906Smjacob } 57839213Sgibbs 57941906Smjacob /* 58041906Smjacob * Whatever we end up doing, allow users to eject tapes from here on. 58141906Smjacob */ 58239213Sgibbs saprevent(periph, PR_ALLOW); 58339213Sgibbs 58441906Smjacob /* 58541906Smjacob * Decide how to end... 58641906Smjacob */ 58753522Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 58853522Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 58953522Smjacob } else switch (mode) { 59039213Sgibbs case SA_MODE_OFFLINE: 59146962Smjacob /* 59246962Smjacob * An 'offline' close is an unconditional release of 59346962Smjacob * frozen && mount conditions, irrespective of whether 59446962Smjacob * these operations succeeded. The reason for this is 59546962Smjacob * to allow at least some kind of programmatic way 59646962Smjacob * around our state getting all fouled up. If somebody 59746962Smjacob * issues an 'offline' command, that will be allowed 59846962Smjacob * to clear state. 59946962Smjacob */ 60046962Smjacob (void) sarewind(periph); 60146962Smjacob (void) saloadunload(periph, FALSE); 60246962Smjacob closedbits |= SA_FLAG_TAPE_MOUNTED|SA_FLAG_TAPE_FROZEN; 60339213Sgibbs break; 60441906Smjacob case SA_MODE_REWIND: 60546962Smjacob /* 60646962Smjacob * If the rewind fails, return an error- if anyone cares, 60746962Smjacob * but not overwriting any previous error. 60846962Smjacob * 60946962Smjacob * We don't clear the notion of mounted here, but we do 61046962Smjacob * clear the notion of frozen if we successfully rewound. 61146962Smjacob */ 61246962Smjacob tmp = sarewind(periph); 61346962Smjacob if (tmp) { 61446962Smjacob if (error != 0) 61546962Smjacob error = tmp; 61646962Smjacob } else { 61746962Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 61846962Smjacob } 61941906Smjacob break; 62039213Sgibbs case SA_MODE_NOREWIND: 62141906Smjacob /* 62241906Smjacob * If we're not rewinding/unloading the tape, find out 62341906Smjacob * whether we need to back up over one of two filemarks 62441906Smjacob * we wrote (if we wrote two filemarks) so that appends 62541906Smjacob * from this point on will be sane. 62641906Smjacob */ 62746962Smjacob if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) { 62846962Smjacob tmp = saspace(periph, -1, SS_FILEMARKS); 62946962Smjacob if (tmp) { 630164906Smjacob xpt_print(periph->path, "unable to backspace " 631164906Smjacob "over one of double filemarks at end of " 632164906Smjacob "tape\n"); 633164906Smjacob xpt_print(periph->path, "it is possible that " 634164906Smjacob "this device needs a SA_QUIRK_1FM quirk set" 635164906Smjacob "for it\n"); 63646962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 63741906Smjacob } 63841906Smjacob } 63939213Sgibbs break; 64046962Smjacob default: 641164906Smjacob xpt_print(periph->path, "unknown mode 0x%x in saclose\n", mode); 64246962Smjacob /* NOTREACHED */ 64346962Smjacob break; 64439213Sgibbs } 64539213Sgibbs 64641906Smjacob /* 64741948Smjacob * We wish to note here that there are no more filemarks to be written. 64841906Smjacob */ 64941906Smjacob softc->filemarks = 0; 65041948Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 65141906Smjacob 65241906Smjacob /* 65341906Smjacob * And we are no longer open for business. 65441906Smjacob */ 65542009Smjacob softc->flags &= ~closedbits; 65646962Smjacob 65746962Smjacob /* 65846962Smjacob * Inform users if tape state if frozen.... 65946962Smjacob */ 66046962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 661164906Smjacob xpt_print(periph->path, "tape is now frozen- use an OFFLINE, " 662164906Smjacob "REWIND or MTEOM command to clear this state.\n"); 66346962Smjacob } 66439213Sgibbs 66553259Smjacob /* release the device if it is no longer mounted */ 66653259Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) 66753259Smjacob sareservereleaseunit(periph, FALSE); 66839213Sgibbs 669168752Sscottl cam_periph_unhold(periph); 67039213Sgibbs cam_periph_unlock(periph); 67139213Sgibbs cam_periph_release(periph); 67239213Sgibbs 67346962Smjacob return (error); 67439213Sgibbs} 67539213Sgibbs 67639213Sgibbs/* 67739213Sgibbs * Actually translate the requested transfer into one the physical driver 67839213Sgibbs * can understand. The transfer is described by a buf and will include 67939213Sgibbs * only one physical transfer. 68039213Sgibbs */ 68139213Sgibbsstatic void 68259249Sphksastrategy(struct bio *bp) 68339213Sgibbs{ 68439213Sgibbs struct cam_periph *periph; 68539213Sgibbs struct sa_softc *softc; 68639213Sgibbs 68776362Sphk bp->bio_resid = bp->bio_bcount; 68859249Sphk if (SA_IS_CTRL(bp->bio_dev)) { 68976362Sphk biofinish(bp, NULL, EINVAL); 69076362Sphk return; 69143636Smjacob } 692101940Snjl periph = (struct cam_periph *)bp->bio_dev->si_drv1; 69339213Sgibbs if (periph == NULL) { 69476362Sphk biofinish(bp, NULL, ENXIO); 69576362Sphk return; 69639213Sgibbs } 697168752Sscottl cam_periph_lock(periph); 698168752Sscottl 69939213Sgibbs softc = (struct sa_softc *)periph->softc; 70039213Sgibbs 70140603Sken if (softc->flags & SA_FLAG_INVALID) { 702168752Sscottl cam_periph_unlock(periph); 70376362Sphk biofinish(bp, NULL, ENXIO); 70476362Sphk return; 70540603Sken } 70640603Sken 70746962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 708168752Sscottl cam_periph_unlock(periph); 70976362Sphk biofinish(bp, NULL, EPERM); 71076362Sphk return; 71146962Smjacob } 71246962Smjacob 713154360Smjacob /* 714154360Smjacob * This should actually never occur as the write(2) 715154360Smjacob * system call traps attempts to write to a read-only 716154360Smjacob * file descriptor. 717154360Smjacob */ 718154360Smjacob if (bp->bio_cmd == BIO_WRITE && softc->open_rdonly) { 719168752Sscottl cam_periph_unlock(periph); 720154360Smjacob biofinish(bp, NULL, EBADF); 721154360Smjacob return; 722154360Smjacob } 723154360Smjacob 724154360Smjacob if (softc->open_pending_mount) { 725154360Smjacob int error = samount(periph, 0, bp->bio_dev); 726154360Smjacob if (error) { 727168752Sscottl cam_periph_unlock(periph); 728154360Smjacob biofinish(bp, NULL, ENXIO); 729154360Smjacob return; 730154360Smjacob } 731154360Smjacob saprevent(periph, PR_PREVENT); 732154360Smjacob softc->open_pending_mount = 0; 733154360Smjacob } 734154360Smjacob 735154360Smjacob 73639213Sgibbs /* 737154360Smjacob * If it's a null transfer, return immediately 73839213Sgibbs */ 73976362Sphk if (bp->bio_bcount == 0) { 740168752Sscottl cam_periph_unlock(periph); 74176362Sphk biodone(bp); 74276362Sphk return; 74376362Sphk } 74439213Sgibbs 74539213Sgibbs /* valid request? */ 74639213Sgibbs if (softc->flags & SA_FLAG_FIXED) { 74739213Sgibbs /* 74839213Sgibbs * Fixed block device. The byte count must 74939213Sgibbs * be a multiple of our block size. 75039213Sgibbs */ 75142716Smjacob if (((softc->blk_mask != ~0) && 75259249Sphk ((bp->bio_bcount & softc->blk_mask) != 0)) || 75342716Smjacob ((softc->blk_mask == ~0) && 75459249Sphk ((bp->bio_bcount % softc->min_blk) != 0))) { 755164906Smjacob xpt_print(periph->path, "Invalid request. Fixed block " 756164906Smjacob "device requests must be a multiple of %d bytes\n", 757164906Smjacob softc->min_blk); 758168752Sscottl cam_periph_unlock(periph); 75976362Sphk biofinish(bp, NULL, EINVAL); 76076362Sphk return; 76139213Sgibbs } 76259249Sphk } else if ((bp->bio_bcount > softc->max_blk) || 76359249Sphk (bp->bio_bcount < softc->min_blk) || 76459249Sphk (bp->bio_bcount & softc->blk_mask) != 0) { 76539213Sgibbs 76639213Sgibbs xpt_print_path(periph->path); 767164906Smjacob printf("Invalid request. Variable block " 768164906Smjacob "device requests must be "); 76939213Sgibbs if (softc->blk_mask != 0) { 77042716Smjacob printf("a multiple of %d ", (0x1 << softc->blk_gran)); 77139213Sgibbs } 77242716Smjacob printf("between %d and %d bytes\n", softc->min_blk, 77342716Smjacob softc->max_blk); 774168752Sscottl cam_periph_unlock(periph); 77576362Sphk biofinish(bp, NULL, EINVAL); 77676362Sphk return; 77739213Sgibbs } 77839213Sgibbs 77939213Sgibbs /* 78042716Smjacob * Place it at the end of the queue. 78139213Sgibbs */ 78259249Sphk bioq_insert_tail(&softc->bio_queue, bp); 78346962Smjacob softc->queue_count++; 784115660Smjacob#if 0 785115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 786115660Smjacob ("sastrategy: queuing a %ld %s byte %s\n", bp->bio_bcount, 787115660Smjacob (softc->flags & SA_FLAG_FIXED)? "fixed" : "variable", 788115660Smjacob (bp->bio_cmd == BIO_READ)? "read" : "write")); 789115660Smjacob#endif 790115660Smjacob if (softc->queue_count > 1) { 791115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 792115660Smjacob ("sastrategy: queue count now %d\n", softc->queue_count)); 793115660Smjacob } 79439213Sgibbs 79539213Sgibbs /* 79639213Sgibbs * Schedule ourselves for performing the work. 79739213Sgibbs */ 79842716Smjacob xpt_schedule(periph, 1); 799168752Sscottl cam_periph_unlock(periph); 80039213Sgibbs 80139213Sgibbs return; 80239213Sgibbs} 80339213Sgibbs 804154360Smjacob 805154360Smjacob#define PENDING_MOUNT_CHECK(softc, periph, dev) \ 806154360Smjacob if (softc->open_pending_mount) { \ 807154360Smjacob error = samount(periph, 0, dev); \ 808154360Smjacob if (error) { \ 809154360Smjacob break; \ 810154360Smjacob } \ 811154360Smjacob saprevent(periph, PR_PREVENT); \ 812154360Smjacob softc->open_pending_mount = 0; \ 813154360Smjacob } 814154360Smjacob 81539213Sgibbsstatic int 816130585Sphksaioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 81739213Sgibbs{ 81839213Sgibbs struct cam_periph *periph; 81939213Sgibbs struct sa_softc *softc; 82048520Speter scsi_space_code spaceop; 82143636Smjacob int didlockperiph = 0; 82239213Sgibbs int mode; 82353259Smjacob int error = 0; 82439213Sgibbs 82539213Sgibbs mode = SAMODE(dev); 82648520Speter error = 0; /* shut up gcc */ 82748520Speter spaceop = 0; /* shut up gcc */ 82839213Sgibbs 829101940Snjl periph = (struct cam_periph *)dev->si_drv1; 83039213Sgibbs if (periph == NULL) 83139213Sgibbs return (ENXIO); 83239213Sgibbs 833168752Sscottl cam_periph_lock(periph); 83439213Sgibbs softc = (struct sa_softc *)periph->softc; 83539213Sgibbs 83639213Sgibbs /* 83743636Smjacob * Check for control mode accesses. We allow MTIOCGET and 83843636Smjacob * MTIOCERRSTAT (but need to be the only one open in order 83943636Smjacob * to clear latched status), and MTSETBSIZE, MTSETDNSTY 84043636Smjacob * and MTCOMP (but need to be the only one accessing this 84143636Smjacob * device to run those). 84243636Smjacob */ 84343636Smjacob 84443636Smjacob if (SA_IS_CTRL(dev)) { 84543636Smjacob switch (cmd) { 84646962Smjacob case MTIOCGETEOTMODEL: 84743636Smjacob case MTIOCGET: 84843636Smjacob break; 84943636Smjacob case MTIOCERRSTAT: 85043636Smjacob /* 85143636Smjacob * If the periph isn't already locked, lock it 85243636Smjacob * so our MTIOCERRSTAT can reset latched error stats. 85343636Smjacob * 85443636Smjacob * If the periph is already locked, skip it because 85543636Smjacob * we're just getting status and it'll be up to the 85643636Smjacob * other thread that has this device open to do 85743636Smjacob * an MTIOCERRSTAT that would clear latched status. 85843636Smjacob */ 85943636Smjacob if ((periph->flags & CAM_PERIPH_LOCKED) == 0) { 860168752Sscottl error = cam_periph_hold(periph, PRIBIO|PCATCH); 861168752Sscottl if (error != 0) 86243636Smjacob return (error); 86343636Smjacob didlockperiph = 1; 86443636Smjacob } 86543636Smjacob break; 86643636Smjacob 867145050Smjacob case MTIOCTOP: 868145050Smjacob { 869145050Smjacob struct mtop *mt = (struct mtop *) arg; 870145050Smjacob 871145050Smjacob /* 872145050Smjacob * Check to make sure it's an OP we can perform 873145050Smjacob * with no media inserted. 874145050Smjacob */ 875145050Smjacob switch (mt->mt_op) { 876145050Smjacob case MTSETBSIZ: 877145050Smjacob case MTSETDNSTY: 878145050Smjacob case MTCOMP: 879145050Smjacob mt = NULL; 880145050Smjacob /* FALLTHROUGH */ 881145050Smjacob default: 882145050Smjacob break; 883145050Smjacob } 884145050Smjacob if (mt != NULL) { 885145050Smjacob break; 886145050Smjacob } 887145050Smjacob /* FALLTHROUGH */ 888145050Smjacob } 88946962Smjacob case MTIOCSETEOTMODEL: 89043636Smjacob /* 89143636Smjacob * We need to acquire the peripheral here rather 89243636Smjacob * than at open time because we are sharing writable 89343636Smjacob * access to data structures. 89443636Smjacob */ 895168752Sscottl error = cam_periph_hold(periph, PRIBIO|PCATCH); 896168752Sscottl if (error != 0) 89743636Smjacob return (error); 89843636Smjacob didlockperiph = 1; 89943636Smjacob break; 90043636Smjacob 90143636Smjacob default: 90243636Smjacob return (EINVAL); 90343636Smjacob } 90443636Smjacob } 90543636Smjacob 90643636Smjacob /* 90739213Sgibbs * Find the device that the user is talking about 90839213Sgibbs */ 90939213Sgibbs switch (cmd) { 91039213Sgibbs case MTIOCGET: 91139213Sgibbs { 91239213Sgibbs struct mtget *g = (struct mtget *)arg; 91339213Sgibbs 91453259Smjacob /* 91553259Smjacob * If this isn't the control mode device, actually go out 91653259Smjacob * and ask the drive again what it's set to. 91753259Smjacob */ 918154360Smjacob if (!SA_IS_CTRL(dev) && !softc->open_pending_mount) { 91953259Smjacob u_int8_t write_protect; 92053259Smjacob int comp_enabled, comp_supported; 92153259Smjacob error = sagetparams(periph, SA_PARAM_ALL, 92253259Smjacob &softc->media_blksize, &softc->media_density, 92353259Smjacob &softc->media_numblks, &softc->buffer_mode, 92453259Smjacob &write_protect, &softc->speed, &comp_supported, 92553259Smjacob &comp_enabled, &softc->comp_algorithm, NULL); 92653259Smjacob if (error) 92753259Smjacob break; 92853259Smjacob if (write_protect) 92953259Smjacob softc->flags |= SA_FLAG_TAPE_WP; 93053259Smjacob else 93153259Smjacob softc->flags &= ~SA_FLAG_TAPE_WP; 93253259Smjacob softc->flags &= ~(SA_FLAG_COMP_SUPP| 93353259Smjacob SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP); 93453259Smjacob if (comp_supported) { 93553259Smjacob if (softc->saved_comp_algorithm == 0) 93653259Smjacob softc->saved_comp_algorithm = 93753259Smjacob softc->comp_algorithm; 93853259Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 93953259Smjacob if (comp_enabled) 94053259Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 94153259Smjacob } else 94253259Smjacob softc->flags |= SA_FLAG_COMP_UNSUPP; 94353259Smjacob } 94439213Sgibbs bzero(g, sizeof(struct mtget)); 94541948Smjacob g->mt_type = MT_ISAR; 94639213Sgibbs if (softc->flags & SA_FLAG_COMP_UNSUPP) { 94739213Sgibbs g->mt_comp = MT_COMP_UNSUPP; 94839213Sgibbs g->mt_comp0 = MT_COMP_UNSUPP; 94939213Sgibbs g->mt_comp1 = MT_COMP_UNSUPP; 95039213Sgibbs g->mt_comp2 = MT_COMP_UNSUPP; 95139213Sgibbs g->mt_comp3 = MT_COMP_UNSUPP; 95239213Sgibbs } else { 95346962Smjacob if ((softc->flags & SA_FLAG_COMP_ENABLED) == 0) { 95446962Smjacob g->mt_comp = MT_COMP_DISABLED; 95546962Smjacob } else { 95646962Smjacob g->mt_comp = softc->comp_algorithm; 95746962Smjacob } 95839213Sgibbs g->mt_comp0 = softc->comp_algorithm; 95939213Sgibbs g->mt_comp1 = softc->comp_algorithm; 96039213Sgibbs g->mt_comp2 = softc->comp_algorithm; 96139213Sgibbs g->mt_comp3 = softc->comp_algorithm; 96239213Sgibbs } 96346962Smjacob g->mt_density = softc->media_density; 96439213Sgibbs g->mt_density0 = softc->media_density; 96539213Sgibbs g->mt_density1 = softc->media_density; 96639213Sgibbs g->mt_density2 = softc->media_density; 96739213Sgibbs g->mt_density3 = softc->media_density; 96846962Smjacob g->mt_blksiz = softc->media_blksize; 96939213Sgibbs g->mt_blksiz0 = softc->media_blksize; 97039213Sgibbs g->mt_blksiz1 = softc->media_blksize; 97139213Sgibbs g->mt_blksiz2 = softc->media_blksize; 97239213Sgibbs g->mt_blksiz3 = softc->media_blksize; 97343636Smjacob g->mt_fileno = softc->fileno; 97443636Smjacob g->mt_blkno = softc->blkno; 97543636Smjacob g->mt_dsreg = (short) softc->dsreg; 97671268Smjacob /* 97771268Smjacob * Yes, we know that this is likely to overflow 97871268Smjacob */ 97971268Smjacob if (softc->last_resid_was_io) { 98071268Smjacob if ((g->mt_resid = (short) softc->last_io_resid) != 0) { 98171268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 98271268Smjacob softc->last_io_resid = 0; 98371268Smjacob } 98471268Smjacob } 98571268Smjacob } else { 98671268Smjacob if ((g->mt_resid = (short)softc->last_ctl_resid) != 0) { 98771268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 98871268Smjacob softc->last_ctl_resid = 0; 98971268Smjacob } 99071268Smjacob } 99171268Smjacob } 99239213Sgibbs error = 0; 99339213Sgibbs break; 99439213Sgibbs } 99541948Smjacob case MTIOCERRSTAT: 99641948Smjacob { 99741948Smjacob struct scsi_tape_errors *sep = 99841948Smjacob &((union mterrstat *)arg)->scsi_errstat; 99941948Smjacob 100041948Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 100141948Smjacob ("saioctl: MTIOCERRSTAT\n")); 100241948Smjacob 100341948Smjacob bzero(sep, sizeof(*sep)); 100441948Smjacob sep->io_resid = softc->last_io_resid; 100541948Smjacob bcopy((caddr_t) &softc->last_io_sense, sep->io_sense, 100641948Smjacob sizeof (sep->io_sense)); 100742009Smjacob bcopy((caddr_t) &softc->last_io_cdb, sep->io_cdb, 100842009Smjacob sizeof (sep->io_cdb)); 100942009Smjacob sep->ctl_resid = softc->last_ctl_resid; 101041948Smjacob bcopy((caddr_t) &softc->last_ctl_sense, sep->ctl_sense, 101141948Smjacob sizeof (sep->ctl_sense)); 101242009Smjacob bcopy((caddr_t) &softc->last_ctl_cdb, sep->ctl_cdb, 101342009Smjacob sizeof (sep->ctl_cdb)); 101443636Smjacob 1015154360Smjacob if ((SA_IS_CTRL(dev) == 0 && softc->open_pending_mount) || 1016154360Smjacob didlockperiph) 101743636Smjacob bzero((caddr_t) &softc->errinfo, 101843636Smjacob sizeof (softc->errinfo)); 101941948Smjacob error = 0; 102041948Smjacob break; 102141948Smjacob } 102239213Sgibbs case MTIOCTOP: 102339213Sgibbs { 102439213Sgibbs struct mtop *mt; 102539213Sgibbs int count; 102639213Sgibbs 1027154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1028154360Smjacob 102939213Sgibbs mt = (struct mtop *)arg; 103039213Sgibbs 1031154360Smjacob 103239213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 103339213Sgibbs ("saioctl: op=0x%x count=0x%x\n", 103439213Sgibbs mt->mt_op, mt->mt_count)); 103539213Sgibbs 103639213Sgibbs count = mt->mt_count; 103739213Sgibbs switch (mt->mt_op) { 103841906Smjacob case MTWEOF: /* write an end-of-file marker */ 103968114Smjacob /* 104068114Smjacob * We don't need to clear the SA_FLAG_TAPE_WRITTEN 104168114Smjacob * flag because by keeping track of filemarks 104268114Smjacob * we have last written we know ehether or not 104368114Smjacob * we need to write more when we close the device. 104468114Smjacob */ 104541906Smjacob error = sawritefilemarks(periph, count, FALSE); 104639213Sgibbs break; 104742009Smjacob case MTWSS: /* write a setmark */ 104842009Smjacob error = sawritefilemarks(periph, count, TRUE); 104942009Smjacob break; 105039213Sgibbs case MTBSR: /* backward space record */ 105139213Sgibbs case MTFSR: /* forward space record */ 105239213Sgibbs case MTBSF: /* backward space file */ 105339213Sgibbs case MTFSF: /* forward space file */ 105442009Smjacob case MTBSS: /* backward space setmark */ 105542009Smjacob case MTFSS: /* forward space setmark */ 105639213Sgibbs case MTEOD: /* space to end of recorded medium */ 105739213Sgibbs { 105839213Sgibbs int nmarks; 105939213Sgibbs 106048520Speter spaceop = SS_FILEMARKS; 106139213Sgibbs nmarks = softc->filemarks; 106239213Sgibbs error = sacheckeod(periph); 106341906Smjacob if (error) { 1064164906Smjacob xpt_print(periph->path, 1065164906Smjacob "EOD check prior to spacing failed\n"); 106641906Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 106741906Smjacob break; 106841906Smjacob } 106939213Sgibbs nmarks -= softc->filemarks; 107042009Smjacob switch(mt->mt_op) { 107142009Smjacob case MTBSR: 107239213Sgibbs count = -count; 107342009Smjacob /* FALLTHROUGH */ 107442009Smjacob case MTFSR: 107539213Sgibbs spaceop = SS_BLOCKS; 107642009Smjacob break; 107742009Smjacob case MTBSF: 107842009Smjacob count = -count; 107942009Smjacob /* FALLTHROUGH */ 108042009Smjacob case MTFSF: 108142009Smjacob break; 108242009Smjacob case MTBSS: 108342009Smjacob count = -count; 108442009Smjacob /* FALLTHROUGH */ 108542009Smjacob case MTFSS: 108642009Smjacob spaceop = SS_SETMARKS; 108742009Smjacob break; 108842009Smjacob case MTEOD: 108939213Sgibbs spaceop = SS_EOD; 109039213Sgibbs count = 0; 109139213Sgibbs nmarks = 0; 109242009Smjacob break; 109342009Smjacob default: 109442009Smjacob error = EINVAL; 109542009Smjacob break; 109639213Sgibbs } 109742009Smjacob if (error) 109842009Smjacob break; 109939213Sgibbs 110039213Sgibbs nmarks = softc->filemarks; 110142009Smjacob /* 110242009Smjacob * XXX: Why are we checking again? 110342009Smjacob */ 110439213Sgibbs error = sacheckeod(periph); 110542009Smjacob if (error) 110642009Smjacob break; 110739213Sgibbs nmarks -= softc->filemarks; 110842009Smjacob error = saspace(periph, count - nmarks, spaceop); 110941906Smjacob /* 111041906Smjacob * At this point, clear that we've written the tape 111141906Smjacob * and that we've written any filemarks. We really 111241906Smjacob * don't know what the applications wishes to do next- 111341906Smjacob * the sacheckeod's will make sure we terminated the 111441906Smjacob * tape correctly if we'd been writing, but the next 111541906Smjacob * action the user application takes will set again 111641906Smjacob * whether we need to write filemarks. 111741906Smjacob */ 111846962Smjacob softc->flags &= 111946962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 112041906Smjacob softc->filemarks = 0; 112139213Sgibbs break; 112239213Sgibbs } 112339213Sgibbs case MTREW: /* rewind */ 1124154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 112541906Smjacob (void) sacheckeod(periph); 112639213Sgibbs error = sarewind(periph); 112741906Smjacob /* see above */ 112842009Smjacob softc->flags &= 112946962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 113082575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 113141906Smjacob softc->filemarks = 0; 113239213Sgibbs break; 113339213Sgibbs case MTERASE: /* erase */ 1134154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 113539213Sgibbs error = saerase(periph, count); 113646962Smjacob softc->flags &= 113746962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 113882575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 113939213Sgibbs break; 114039213Sgibbs case MTRETENS: /* re-tension tape */ 1141154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 114239213Sgibbs error = saretension(periph); 114346962Smjacob softc->flags &= 114446962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 114582575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 114639213Sgibbs break; 114739213Sgibbs case MTOFFL: /* rewind and put the drive offline */ 114841906Smjacob 1149154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1150154360Smjacob 115141906Smjacob (void) sacheckeod(periph); 115241906Smjacob /* see above */ 115341906Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 115441906Smjacob softc->filemarks = 0; 115541906Smjacob 115646962Smjacob error = sarewind(periph); 115753522Smjacob /* clear the frozen flag anyway */ 115853522Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 115946962Smjacob 116039213Sgibbs /* 116153522Smjacob * Be sure to allow media removal before ejecting. 116239213Sgibbs */ 116346962Smjacob 116439213Sgibbs saprevent(periph, PR_ALLOW); 116553522Smjacob if (error == 0) { 116643636Smjacob error = saloadunload(periph, FALSE); 116753522Smjacob if (error == 0) { 116853522Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 116953522Smjacob } 117053522Smjacob } 117146962Smjacob break; 117239213Sgibbs 117339213Sgibbs case MTNOP: /* no operation, sets status only */ 117439213Sgibbs case MTCACHE: /* enable controller cache */ 117539213Sgibbs case MTNOCACHE: /* disable controller cache */ 117639213Sgibbs error = 0; 117739213Sgibbs break; 117846962Smjacob 117939213Sgibbs case MTSETBSIZ: /* Set block size for device */ 118039213Sgibbs 1181154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1182154360Smjacob 118339213Sgibbs error = sasetparams(periph, SA_PARAM_BLOCKSIZE, count, 118442563Smjacob 0, 0, 0); 118541674Smjacob if (error == 0) { 118641906Smjacob softc->last_media_blksize = 118741906Smjacob softc->media_blksize; 118841674Smjacob softc->media_blksize = count; 118941674Smjacob if (count) { 119041674Smjacob softc->flags |= SA_FLAG_FIXED; 119141674Smjacob if (powerof2(count)) { 119241674Smjacob softc->blk_shift = 119341674Smjacob ffs(count) - 1; 119441674Smjacob softc->blk_mask = count - 1; 119541674Smjacob } else { 119641674Smjacob softc->blk_mask = ~0; 119741674Smjacob softc->blk_shift = 0; 119841674Smjacob } 119941906Smjacob /* 120041906Smjacob * Make the user's desire 'persistent'. 120141906Smjacob */ 120241906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 120341906Smjacob softc->quirks |= SA_QUIRK_FIXED; 120441674Smjacob } else { 120541674Smjacob softc->flags &= ~SA_FLAG_FIXED; 120641674Smjacob if (softc->max_blk == 0) { 120741674Smjacob softc->max_blk = ~0; 120841674Smjacob } 120941674Smjacob softc->blk_shift = 0; 121041674Smjacob if (softc->blk_gran != 0) { 121141674Smjacob softc->blk_mask = 121241674Smjacob softc->blk_gran - 1; 121341674Smjacob } else { 121441674Smjacob softc->blk_mask = 0; 121541674Smjacob } 121641906Smjacob /* 121741906Smjacob * Make the user's desire 'persistent'. 121841906Smjacob */ 121941906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 122041906Smjacob softc->quirks &= ~SA_QUIRK_FIXED; 122141674Smjacob } 122241674Smjacob } 122339213Sgibbs break; 122439213Sgibbs case MTSETDNSTY: /* Set density for device and mode */ 1225154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1226154360Smjacob 122739213Sgibbs if (count > UCHAR_MAX) { 122839213Sgibbs error = EINVAL; 122939213Sgibbs break; 123039213Sgibbs } else { 123139213Sgibbs error = sasetparams(periph, SA_PARAM_DENSITY, 123242563Smjacob 0, count, 0, 0); 123339213Sgibbs } 123439213Sgibbs break; 123539213Sgibbs case MTCOMP: /* enable compression */ 1236154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 123739213Sgibbs /* 123839213Sgibbs * Some devices don't support compression, and 123939213Sgibbs * don't like it if you ask them for the 124039213Sgibbs * compression page. 124139213Sgibbs */ 124243636Smjacob if ((softc->quirks & SA_QUIRK_NOCOMP) || 124343636Smjacob (softc->flags & SA_FLAG_COMP_UNSUPP)) { 124439213Sgibbs error = ENODEV; 124539213Sgibbs break; 124639213Sgibbs } 124739213Sgibbs error = sasetparams(periph, SA_PARAM_COMPRESSION, 124854099Smjacob 0, 0, count, SF_NO_PRINT); 124939213Sgibbs break; 125039213Sgibbs default: 125139213Sgibbs error = EINVAL; 125239213Sgibbs } 125339213Sgibbs break; 125439213Sgibbs } 125539213Sgibbs case MTIOCIEOT: 125639213Sgibbs case MTIOCEEOT: 125739213Sgibbs error = 0; 125839213Sgibbs break; 125941918Smjacob case MTIOCRDSPOS: 1260154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 126141918Smjacob error = sardpos(periph, 0, (u_int32_t *) arg); 126241918Smjacob break; 126341918Smjacob case MTIOCRDHPOS: 1264154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 126541918Smjacob error = sardpos(periph, 1, (u_int32_t *) arg); 126641918Smjacob break; 126741918Smjacob case MTIOCSLOCATE: 1268154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 126941918Smjacob error = sasetpos(periph, 0, (u_int32_t *) arg); 127041918Smjacob break; 127141918Smjacob case MTIOCHLOCATE: 1272154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 127341918Smjacob error = sasetpos(periph, 1, (u_int32_t *) arg); 127441918Smjacob break; 127546962Smjacob case MTIOCGETEOTMODEL: 127646962Smjacob error = 0; 127746962Smjacob if (softc->quirks & SA_QUIRK_1FM) 127846962Smjacob mode = 1; 127946962Smjacob else 128046962Smjacob mode = 2; 128146962Smjacob *((u_int32_t *) arg) = mode; 128246962Smjacob break; 128346962Smjacob case MTIOCSETEOTMODEL: 128446962Smjacob error = 0; 128546962Smjacob switch (*((u_int32_t *) arg)) { 128646962Smjacob case 1: 128746962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 128846962Smjacob softc->quirks |= SA_QUIRK_1FM; 128946962Smjacob break; 129046962Smjacob case 2: 129146962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 129246962Smjacob softc->quirks |= SA_QUIRK_2FM; 129346962Smjacob break; 129446962Smjacob default: 129546962Smjacob error = EINVAL; 129646962Smjacob break; 129746962Smjacob } 129846962Smjacob break; 129939213Sgibbs default: 130039213Sgibbs error = cam_periph_ioctl(periph, cmd, arg, saerror); 130139213Sgibbs break; 130239213Sgibbs } 130371268Smjacob 130471268Smjacob /* 130571268Smjacob * Check to see if we cleared a frozen state 130671268Smjacob */ 130771268Smjacob if (error == 0 && (softc->flags & SA_FLAG_TAPE_FROZEN)) { 130871268Smjacob switch(cmd) { 130971268Smjacob case MTIOCRDSPOS: 131071268Smjacob case MTIOCRDHPOS: 131171268Smjacob case MTIOCSLOCATE: 131271268Smjacob case MTIOCHLOCATE: 131371268Smjacob softc->fileno = (daddr_t) -1; 131471268Smjacob softc->blkno = (daddr_t) -1; 131571268Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 1316164906Smjacob xpt_print(periph->path, 1317164906Smjacob "tape state now unfrozen.\n"); 131871268Smjacob break; 131971268Smjacob default: 132071268Smjacob break; 132171268Smjacob } 132271268Smjacob } 132343636Smjacob if (didlockperiph) { 1324168752Sscottl cam_periph_unhold(periph); 132543636Smjacob } 1326168752Sscottl cam_periph_unlock(periph); 132739213Sgibbs return (error); 132839213Sgibbs} 132939213Sgibbs 133039213Sgibbsstatic void 133139213Sgibbssainit(void) 133239213Sgibbs{ 133339213Sgibbs cam_status status; 133439213Sgibbs struct cam_path *path; 133539213Sgibbs 133639213Sgibbs /* 133739213Sgibbs * Install a global async callback. 133839213Sgibbs */ 133939213Sgibbs status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 134039213Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 134139213Sgibbs 134239213Sgibbs if (status == CAM_REQ_CMP) { 134339213Sgibbs /* Register the async callbacks of interrest */ 134439213Sgibbs struct ccb_setasync csa; /* 134539213Sgibbs * This is an immediate CCB, 134639213Sgibbs * so using the stack is OK 134739213Sgibbs */ 134846962Smjacob xpt_setup_ccb(&csa.ccb_h, path, 5); 134939213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 135039213Sgibbs csa.event_enable = AC_FOUND_DEVICE; 135139213Sgibbs csa.callback = saasync; 135239213Sgibbs csa.callback_arg = NULL; 135339213Sgibbs xpt_action((union ccb *)&csa); 135439213Sgibbs status = csa.ccb_h.status; 135539213Sgibbs xpt_free_path(path); 135639213Sgibbs } 135739213Sgibbs 135839213Sgibbs if (status != CAM_REQ_CMP) { 135939213Sgibbs printf("sa: Failed to attach master async callback " 136039213Sgibbs "due to status 0x%x!\n", status); 136139213Sgibbs } 136239213Sgibbs} 136339213Sgibbs 136439213Sgibbsstatic void 136540603Skensaoninvalidate(struct cam_periph *periph) 136640603Sken{ 136740603Sken struct sa_softc *softc; 136840603Sken struct ccb_setasync csa; 136940603Sken 137040603Sken softc = (struct sa_softc *)periph->softc; 137140603Sken 137240603Sken /* 137340603Sken * De-register any async callbacks. 137440603Sken */ 137540603Sken xpt_setup_ccb(&csa.ccb_h, periph->path, 137640603Sken /* priority */ 5); 137740603Sken csa.ccb_h.func_code = XPT_SASYNC_CB; 137840603Sken csa.event_enable = 0; 137940603Sken csa.callback = saasync; 138040603Sken csa.callback_arg = periph; 138140603Sken xpt_action((union ccb *)&csa); 138240603Sken 138340603Sken softc->flags |= SA_FLAG_INVALID; 138440603Sken 138540603Sken /* 138640603Sken * Return all queued I/O with ENXIO. 138740603Sken * XXX Handle any transactions queued to the card 138840603Sken * with XPT_ABORT_CCB. 138940603Sken */ 1390112946Sphk bioq_flush(&softc->bio_queue, NULL, ENXIO); 139146962Smjacob softc->queue_count = 0; 139240603Sken 1393164906Smjacob xpt_print(periph->path, "lost device\n"); 139440603Sken 139540603Sken} 139640603Sken 139740603Skenstatic void 139839213Sgibbssacleanup(struct cam_periph *periph) 139939213Sgibbs{ 140040603Sken struct sa_softc *softc; 140153259Smjacob int i; 140240603Sken 140340603Sken softc = (struct sa_softc *)periph->softc; 140440603Sken 1405112006Sphk devstat_remove_entry(softc->device_stats); 140653259Smjacob 140753259Smjacob destroy_dev(softc->devs.ctl_dev); 140853259Smjacob 140953259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 141053259Smjacob destroy_dev(softc->devs.mode_devs[i].r_dev); 141153259Smjacob destroy_dev(softc->devs.mode_devs[i].nr_dev); 141253259Smjacob destroy_dev(softc->devs.mode_devs[i].er_dev); 141353259Smjacob } 141453259Smjacob 1415164906Smjacob xpt_print(periph->path, "removing device entry\n"); 1416147723Savatar free(softc, M_SCSISA); 141739213Sgibbs} 141839213Sgibbs 141939213Sgibbsstatic void 142039213Sgibbssaasync(void *callback_arg, u_int32_t code, 142139213Sgibbs struct cam_path *path, void *arg) 142239213Sgibbs{ 142339213Sgibbs struct cam_periph *periph; 142439213Sgibbs 142539213Sgibbs periph = (struct cam_periph *)callback_arg; 142639213Sgibbs switch (code) { 142739213Sgibbs case AC_FOUND_DEVICE: 142839213Sgibbs { 142939213Sgibbs struct ccb_getdev *cgd; 143039213Sgibbs cam_status status; 143139213Sgibbs 143239213Sgibbs cgd = (struct ccb_getdev *)arg; 143379177Smjacob if (cgd == NULL) 143479177Smjacob break; 143539213Sgibbs 143656148Smjacob if (SID_TYPE(&cgd->inq_data) != T_SEQUENTIAL) 143739213Sgibbs break; 143839213Sgibbs 143939213Sgibbs /* 144039213Sgibbs * Allocate a peripheral instance for 144139213Sgibbs * this device and start the probe 144239213Sgibbs * process. 144339213Sgibbs */ 144440603Sken status = cam_periph_alloc(saregister, saoninvalidate, 144540603Sken sacleanup, sastart, 144639213Sgibbs "sa", CAM_PERIPH_BIO, cgd->ccb_h.path, 144739213Sgibbs saasync, AC_FOUND_DEVICE, cgd); 144839213Sgibbs 144939213Sgibbs if (status != CAM_REQ_CMP 145039213Sgibbs && status != CAM_REQ_INPROG) 145139213Sgibbs printf("saasync: Unable to probe new device " 145239213Sgibbs "due to status 0x%x\n", status); 145339213Sgibbs break; 145439213Sgibbs } 145539213Sgibbs default: 145647413Sgibbs cam_periph_async(periph, code, path, arg); 145739213Sgibbs break; 145839213Sgibbs } 145939213Sgibbs} 146039213Sgibbs 146139213Sgibbsstatic cam_status 146239213Sgibbssaregister(struct cam_periph *periph, void *arg) 146339213Sgibbs{ 146439213Sgibbs struct sa_softc *softc; 146539213Sgibbs struct ccb_setasync csa; 146639213Sgibbs struct ccb_getdev *cgd; 146739213Sgibbs caddr_t match; 146853259Smjacob int i; 146939213Sgibbs 147039213Sgibbs cgd = (struct ccb_getdev *)arg; 147139213Sgibbs if (periph == NULL) { 147239213Sgibbs printf("saregister: periph was NULL!!\n"); 147354099Smjacob return (CAM_REQ_CMP_ERR); 147439213Sgibbs } 147539213Sgibbs 147639213Sgibbs if (cgd == NULL) { 147739213Sgibbs printf("saregister: no getdev CCB, can't register device\n"); 147854099Smjacob return (CAM_REQ_CMP_ERR); 147939213Sgibbs } 148039213Sgibbs 148167723Smjacob softc = (struct sa_softc *) 1482147723Savatar malloc(sizeof (*softc), M_SCSISA, M_NOWAIT | M_ZERO); 148339213Sgibbs if (softc == NULL) { 148439213Sgibbs printf("saregister: Unable to probe new device. " 148539213Sgibbs "Unable to allocate softc\n"); 148654099Smjacob return (CAM_REQ_CMP_ERR); 148739213Sgibbs } 148841674Smjacob softc->scsi_rev = SID_ANSI_REV(&cgd->inq_data); 148939213Sgibbs softc->state = SA_STATE_NORMAL; 149043636Smjacob softc->fileno = (daddr_t) -1; 149143636Smjacob softc->blkno = (daddr_t) -1; 149243636Smjacob 149359249Sphk bioq_init(&softc->bio_queue); 149439213Sgibbs periph->softc = softc; 149539213Sgibbs 149639213Sgibbs /* 149739213Sgibbs * See if this device has any quirks. 149839213Sgibbs */ 149939213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 150039213Sgibbs (caddr_t)sa_quirk_table, 150139213Sgibbs sizeof(sa_quirk_table)/sizeof(*sa_quirk_table), 150239213Sgibbs sizeof(*sa_quirk_table), scsi_inquiry_match); 150339213Sgibbs 150442563Smjacob if (match != NULL) { 150539213Sgibbs softc->quirks = ((struct sa_quirk_entry *)match)->quirks; 150642563Smjacob softc->last_media_blksize = 150742563Smjacob ((struct sa_quirk_entry *)match)->prefblk; 150842563Smjacob#ifdef CAMDEBUG 1509164906Smjacob xpt_print(periph->path, "found quirk entry %d\n", 1510164906Smjacob (int) (((struct sa_quirk_entry *) match) - sa_quirk_table)); 151142563Smjacob#endif 151242563Smjacob } else 151339213Sgibbs softc->quirks = SA_QUIRK_NONE; 151439213Sgibbs 151539213Sgibbs /* 151639213Sgibbs * The SA driver supports a blocksize, but we don't know the 151746962Smjacob * blocksize until we media is inserted. So, set a flag to 151839213Sgibbs * indicate that the blocksize is unavailable right now. 151939213Sgibbs */ 1520112006Sphk softc->device_stats = devstat_new_entry("sa", periph->unit_number, 0, 152156148Smjacob DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) | 152256148Smjacob DEVSTAT_TYPE_IF_SCSI, DEVSTAT_PRIORITY_TAPE); 152353259Smjacob 152453259Smjacob softc->devs.ctl_dev = make_dev(&sa_cdevsw, SAMINOR(SA_CTLDEV, 152553259Smjacob periph->unit_number, 0, SA_ATYPE_R), UID_ROOT, GID_OPERATOR, 152672804Smjacob 0660, "%s%d.ctl", periph->periph_name, periph->unit_number); 1527101940Snjl softc->devs.ctl_dev->si_drv1 = periph; 152853259Smjacob 152953259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 153053283Smjacob 153153259Smjacob softc->devs.mode_devs[i].r_dev = make_dev(&sa_cdevsw, 153253259Smjacob SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_R), 153372804Smjacob UID_ROOT, GID_OPERATOR, 0660, "%s%d.%d", 153453259Smjacob periph->periph_name, periph->unit_number, i); 1535101940Snjl softc->devs.mode_devs[i].r_dev->si_drv1 = periph; 153653283Smjacob 153753259Smjacob softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw, 153853259Smjacob SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_NR), 153972804Smjacob UID_ROOT, GID_OPERATOR, 0660, "n%s%d.%d", 154053259Smjacob periph->periph_name, periph->unit_number, i); 1541101940Snjl softc->devs.mode_devs[i].nr_dev->si_drv1 = periph; 154253259Smjacob 154353283Smjacob softc->devs.mode_devs[i].er_dev = make_dev(&sa_cdevsw, 154453259Smjacob SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_ER), 154572804Smjacob UID_ROOT, GID_OPERATOR, 0660, "e%s%d.%d", 154653259Smjacob periph->periph_name, periph->unit_number, i); 1547101940Snjl softc->devs.mode_devs[i].er_dev->si_drv1 = periph; 154865838Smjacob 154965838Smjacob /* 155065838Smjacob * Make the (well known) aliases for the first mode. 155165838Smjacob */ 155265838Smjacob if (i == 0) { 1553130585Sphk struct cdev *alias; 1554101940Snjl 1555101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].r_dev, 155672804Smjacob "%s%d", periph->periph_name, periph->unit_number); 1557101940Snjl alias->si_drv1 = periph; 1558101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].nr_dev, 155972804Smjacob "n%s%d", periph->periph_name, periph->unit_number); 1560101940Snjl alias->si_drv1 = periph; 1561101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].er_dev, 156272804Smjacob "e%s%d", periph->periph_name, periph->unit_number); 1563101940Snjl alias->si_drv1 = periph; 156465838Smjacob } 156553259Smjacob } 156653259Smjacob 156739213Sgibbs /* 156839213Sgibbs * Add an async callback so that we get 156939213Sgibbs * notified if this device goes away. 157039213Sgibbs */ 157139213Sgibbs xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 157239213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 157339213Sgibbs csa.event_enable = AC_LOST_DEVICE; 157439213Sgibbs csa.callback = saasync; 157539213Sgibbs csa.callback_arg = periph; 157639213Sgibbs xpt_action((union ccb *)&csa); 157739213Sgibbs 157839213Sgibbs xpt_announce_periph(periph, NULL); 157939213Sgibbs 158054099Smjacob return (CAM_REQ_CMP); 158139213Sgibbs} 158239213Sgibbs 158339213Sgibbsstatic void 158439213Sgibbssastart(struct cam_periph *periph, union ccb *start_ccb) 158539213Sgibbs{ 158639213Sgibbs struct sa_softc *softc; 158739213Sgibbs 158839213Sgibbs softc = (struct sa_softc *)periph->softc; 158939213Sgibbs 1590115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sastart\n")); 159171082Smjacob 159239213Sgibbs 159339213Sgibbs switch (softc->state) { 159439213Sgibbs case SA_STATE_NORMAL: 159539213Sgibbs { 159639213Sgibbs /* Pull a buffer from the queue and get going on it */ 159759249Sphk struct bio *bp; 159839213Sgibbs 159939213Sgibbs /* 160039213Sgibbs * See if there is a buf with work for us to do.. 160139213Sgibbs */ 160259249Sphk bp = bioq_first(&softc->bio_queue); 160339213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 160439213Sgibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 160539213Sgibbs ("queuing for immediate ccb\n")); 160671082Smjacob Set_CCB_Type(start_ccb, SA_CCB_WAITING); 160739213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 160839213Sgibbs periph_links.sle); 160939213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 161039213Sgibbs wakeup(&periph->ccb_list); 161139213Sgibbs } else if (bp == NULL) { 161239213Sgibbs xpt_release_ccb(start_ccb); 161339213Sgibbs } else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) { 161459249Sphk struct bio *done_bp; 161582575Smjacobagain: 161646962Smjacob softc->queue_count--; 161759249Sphk bioq_remove(&softc->bio_queue, bp); 161859249Sphk bp->bio_resid = bp->bio_bcount; 161982575Smjacob done_bp = bp; 162039213Sgibbs if ((softc->flags & SA_FLAG_EOM_PENDING) != 0) { 162182575Smjacob /* 162282575Smjacob * We now just clear errors in this case 162382575Smjacob * and let the residual be the notifier. 162482575Smjacob */ 162582575Smjacob bp->bio_error = 0; 162682575Smjacob } else if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) { 162782575Smjacob /* 162882575Smjacob * This can only happen if we're reading 162982575Smjacob * in fixed length mode. In this case, 163082575Smjacob * we dump the rest of the list the 163182575Smjacob * same way. 163282575Smjacob */ 163382575Smjacob bp->bio_error = 0; 163482575Smjacob if (bioq_first(&softc->bio_queue) != NULL) { 163582575Smjacob biodone(done_bp); 163682575Smjacob goto again; 163782575Smjacob } 163882575Smjacob } else if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) { 163959249Sphk bp->bio_error = EIO; 164082575Smjacob bp->bio_flags |= BIO_ERROR; 164141948Smjacob } 164259249Sphk bp = bioq_first(&softc->bio_queue); 164344354Smjacob /* 164444354Smjacob * Only if we have no other buffers queued up 164544354Smjacob * do we clear the pending error flag. 164644354Smjacob */ 164744354Smjacob if (bp == NULL) 164844354Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 164944354Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 165046962Smjacob ("sastart- ERR_PENDING now 0x%x, bp is %sNULL, " 165146962Smjacob "%d more buffers queued up\n", 165244354Smjacob (softc->flags & SA_FLAG_ERR_PENDING), 165346962Smjacob (bp != NULL)? "not " : " ", softc->queue_count)); 165444354Smjacob xpt_release_ccb(start_ccb); 165541948Smjacob biodone(done_bp); 165639213Sgibbs } else { 165739213Sgibbs u_int32_t length; 165839213Sgibbs 165959249Sphk bioq_remove(&softc->bio_queue, bp); 166046962Smjacob softc->queue_count--; 166139213Sgibbs 166239213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) { 166339213Sgibbs if (softc->blk_shift != 0) { 166439213Sgibbs length = 166559249Sphk bp->bio_bcount >> softc->blk_shift; 166643636Smjacob } else if (softc->media_blksize != 0) { 166771082Smjacob length = bp->bio_bcount / 166871082Smjacob softc->media_blksize; 166943636Smjacob } else { 167059249Sphk bp->bio_error = EIO; 1671164906Smjacob xpt_print(periph->path, "zero blocksize" 1672164906Smjacob " for FIXED length writes?\n"); 167343636Smjacob biodone(bp); 167443636Smjacob break; 167539213Sgibbs } 1676115660Smjacob#if 0 1677115660Smjacob CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 1678115660Smjacob ("issuing a %d fixed record %s\n", 1679115660Smjacob length, (bp->bio_cmd == BIO_READ)? "read" : 1680115660Smjacob "write")); 1681115660Smjacob#endif 168239213Sgibbs } else { 168359249Sphk length = bp->bio_bcount; 1684115660Smjacob#if 0 168541906Smjacob CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 1686115660Smjacob ("issuing a %d variable byte %s\n", 1687115660Smjacob length, (bp->bio_cmd == BIO_READ)? "read" : 1688115660Smjacob "write")); 1689115660Smjacob#endif 169039213Sgibbs } 1691112260Sphk devstat_start_transaction_bio(softc->device_stats, bp); 169239213Sgibbs /* 169341906Smjacob * Some people have theorized that we should 169439213Sgibbs * suppress illegal length indication if we are 169539213Sgibbs * running in variable block mode so that we don't 169639213Sgibbs * have to request sense every time our requested 169739213Sgibbs * block size is larger than the written block. 169839213Sgibbs * The residual information from the ccb allows 169939213Sgibbs * us to identify this situation anyway. The only 170039213Sgibbs * problem with this is that we will not get 170139213Sgibbs * information about blocks that are larger than 170239213Sgibbs * our read buffer unless we set the block size 170339213Sgibbs * in the mode page to something other than 0. 170441906Smjacob * 170541906Smjacob * I believe that this is a non-issue. If user apps 170641906Smjacob * don't adjust their read size to match our record 170741906Smjacob * size, that's just life. Anyway, the typical usage 170841906Smjacob * would be to issue, e.g., 64KB reads and occasionally 170941906Smjacob * have to do deal with 512 byte or 1KB intermediate 171041906Smjacob * records. 171139213Sgibbs */ 171259249Sphk softc->dsreg = (bp->bio_cmd == BIO_READ)? 171343636Smjacob MTIO_DSREG_RD : MTIO_DSREG_WR; 171446962Smjacob scsi_sa_read_write(&start_ccb->csio, 0, sadone, 171559249Sphk MSG_SIMPLE_Q_TAG, (bp->bio_cmd == BIO_READ), 171646962Smjacob FALSE, (softc->flags & SA_FLAG_FIXED) != 0, 171759249Sphk length, bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE, 171879100Smjacob IO_TIMEOUT); 171971082Smjacob start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED; 172071082Smjacob Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO); 172139213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 172259249Sphk bp = bioq_first(&softc->bio_queue); 172339213Sgibbs xpt_action(start_ccb); 172439213Sgibbs } 172539213Sgibbs 172639213Sgibbs if (bp != NULL) { 172739213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 172846962Smjacob xpt_schedule(periph, 1); 172939213Sgibbs } 173039213Sgibbs break; 173139213Sgibbs } 173246962Smjacob case SA_STATE_ABNORMAL: 173346962Smjacob default: 173446962Smjacob panic("state 0x%x in sastart", softc->state); 173546962Smjacob break; 173639213Sgibbs } 173739213Sgibbs} 173839213Sgibbs 173939213Sgibbs 174039213Sgibbsstatic void 174139213Sgibbssadone(struct cam_periph *periph, union ccb *done_ccb) 174239213Sgibbs{ 174339213Sgibbs struct sa_softc *softc; 174439213Sgibbs struct ccb_scsiio *csio; 174539213Sgibbs 174639213Sgibbs softc = (struct sa_softc *)periph->softc; 174739213Sgibbs csio = &done_ccb->csio; 174871082Smjacob switch (CCB_Type(csio)) { 174939213Sgibbs case SA_CCB_BUFFER_IO: 175039213Sgibbs { 175159249Sphk struct bio *bp; 175239213Sgibbs int error; 175339213Sgibbs 175443636Smjacob softc->dsreg = MTIO_DSREG_REST; 175559249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 175639213Sgibbs error = 0; 175739213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 175839213Sgibbs if ((error = saerror(done_ccb, 0, 0)) == ERESTART) { 175939213Sgibbs /* 176041948Smjacob * A retry was scheduled, so just return. 176139213Sgibbs */ 176239213Sgibbs return; 176339213Sgibbs } 176439213Sgibbs } 176539213Sgibbs 176639213Sgibbs if (error == EIO) { 176739213Sgibbs 176839213Sgibbs /* 176953522Smjacob * Catastrophic error. Mark the tape as frozen 177053522Smjacob * (we no longer know tape position). 177153522Smjacob * 177244354Smjacob * Return all queued I/O with EIO, and unfreeze 177339213Sgibbs * our queue so that future transactions that 177439213Sgibbs * attempt to fix this problem can get to the 177539213Sgibbs * device. 177639213Sgibbs * 177739213Sgibbs */ 177839213Sgibbs 177953522Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 1780112946Sphk bioq_flush(&softc->bio_queue, NULL, EIO); 178139213Sgibbs } 178239213Sgibbs if (error != 0) { 178359249Sphk bp->bio_resid = bp->bio_bcount; 178459249Sphk bp->bio_error = error; 178559249Sphk bp->bio_flags |= BIO_ERROR; 178643636Smjacob /* 178743636Smjacob * In the error case, position is updated in saerror. 178843636Smjacob */ 178939213Sgibbs } else { 179059249Sphk bp->bio_resid = csio->resid; 179159249Sphk bp->bio_error = 0; 179239213Sgibbs if (csio->resid != 0) { 179359249Sphk bp->bio_flags |= BIO_ERROR; 179439213Sgibbs } 179559249Sphk if (bp->bio_cmd == BIO_WRITE) { 179639213Sgibbs softc->flags |= SA_FLAG_TAPE_WRITTEN; 179739213Sgibbs softc->filemarks = 0; 179839213Sgibbs } 179971082Smjacob if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) && 180071082Smjacob (softc->blkno != (daddr_t) -1)) { 180143636Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 180243636Smjacob u_int32_t l; 180343636Smjacob if (softc->blk_shift != 0) { 180459249Sphk l = bp->bio_bcount >> 180543636Smjacob softc->blk_shift; 180643636Smjacob } else { 180759249Sphk l = bp->bio_bcount / 180843636Smjacob softc->media_blksize; 180943636Smjacob } 181043636Smjacob softc->blkno += (daddr_t) l; 181143636Smjacob } else { 181243636Smjacob softc->blkno++; 181343636Smjacob } 181443636Smjacob } 181539213Sgibbs } 181646962Smjacob /* 181746962Smjacob * If we had an error (immediate or pending), 181846962Smjacob * release the device queue now. 181946962Smjacob */ 182046962Smjacob if (error || (softc->flags & SA_FLAG_ERR_PENDING)) 182146962Smjacob cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0); 182241674Smjacob#ifdef CAMDEBUG 182359249Sphk if (error || bp->bio_resid) { 182441674Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 182541674Smjacob ("error %d resid %ld count %ld\n", error, 182659249Sphk bp->bio_resid, bp->bio_bcount)); 182741674Smjacob } 182841674Smjacob#endif 1829112006Sphk biofinish(bp, softc->device_stats, 0); 183039213Sgibbs break; 183139213Sgibbs } 183239213Sgibbs case SA_CCB_WAITING: 183339213Sgibbs { 183439213Sgibbs /* Caller will release the CCB */ 183539213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 183639213Sgibbs return; 183739213Sgibbs } 183839213Sgibbs } 183939213Sgibbs xpt_release_ccb(done_ccb); 184039213Sgibbs} 184139213Sgibbs 184241906Smjacob/* 184341906Smjacob * Mount the tape (make sure it's ready for I/O). 184441906Smjacob */ 184539213Sgibbsstatic int 1846130585Sphksamount(struct cam_periph *periph, int oflags, struct cdev *dev) 184739213Sgibbs{ 184839213Sgibbs struct sa_softc *softc; 184939213Sgibbs union ccb *ccb; 185039213Sgibbs int error; 185139213Sgibbs 185241906Smjacob /* 185341906Smjacob * oflags can be checked for 'kind' of open (read-only check) - later 185441906Smjacob * dev can be checked for a control-mode or compression open - later 185541906Smjacob */ 185641906Smjacob UNUSED_PARAMETER(oflags); 185741906Smjacob UNUSED_PARAMETER(dev); 185841906Smjacob 185941906Smjacob 186039213Sgibbs softc = (struct sa_softc *)periph->softc; 186139213Sgibbs 186239213Sgibbs /* 186353259Smjacob * This should determine if something has happend since the last 186453259Smjacob * open/mount that would invalidate the mount. We do *not* want 186553259Smjacob * to retry this command- we just want the status. But we only 186653259Smjacob * do this if we're mounted already- if we're not mounted, 186753259Smjacob * we don't care about the unit read state and can instead use 186853259Smjacob * this opportunity to attempt to reserve the tape unit. 186939213Sgibbs */ 187053259Smjacob 187153259Smjacob if (softc->flags & SA_FLAG_TAPE_MOUNTED) { 187253259Smjacob ccb = cam_periph_getccb(periph, 1); 187353259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 187479100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 187554099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1876112006Sphk softc->device_stats); 187753259Smjacob QFRLS(ccb); 187853259Smjacob if (error == ENXIO) { 187953259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 188053259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 188179100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 188254099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1883112006Sphk softc->device_stats); 188453259Smjacob QFRLS(ccb); 188553259Smjacob } else if (error) { 188654099Smjacob /* 188754099Smjacob * We don't need to freeze the tape because we 188854099Smjacob * will now attempt to rewind/load it. 188954099Smjacob */ 189053259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 1891144430Ssam if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 1892164906Smjacob xpt_print(periph->path, 1893164906Smjacob "error %d on TUR in samount\n", error); 189454099Smjacob } 189553259Smjacob } 189653259Smjacob } else { 189753259Smjacob error = sareservereleaseunit(periph, TRUE); 189853259Smjacob if (error) { 189953259Smjacob return (error); 190053259Smjacob } 190153259Smjacob ccb = cam_periph_getccb(periph, 1); 190254105Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 190379100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 190454105Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1905112006Sphk softc->device_stats); 190654105Smjacob QFRLS(ccb); 190753259Smjacob } 190839213Sgibbs 190939213Sgibbs if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 191053259Smjacob struct scsi_read_block_limits_data *rblim = NULL; 191153259Smjacob int comp_enabled, comp_supported; 191241906Smjacob u_int8_t write_protect, guessing = 0; 191339213Sgibbs 191439213Sgibbs /* 191539213Sgibbs * Clear out old state. 191639213Sgibbs */ 191739213Sgibbs softc->flags &= ~(SA_FLAG_TAPE_WP|SA_FLAG_TAPE_WRITTEN| 191839213Sgibbs SA_FLAG_ERR_PENDING|SA_FLAG_COMP_ENABLED| 191946962Smjacob SA_FLAG_COMP_SUPP|SA_FLAG_COMP_UNSUPP); 192039213Sgibbs softc->filemarks = 0; 192139213Sgibbs 192239213Sgibbs /* 192343636Smjacob * *Very* first off, make sure we're loaded to BOT. 192439213Sgibbs */ 192543636Smjacob scsi_load_unload(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 192654099Smjacob FALSE, FALSE, 1, SSD_FULL_SIZE, REWIND_TIMEOUT); 192754099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1928112006Sphk softc->device_stats); 192953259Smjacob QFRLS(ccb); 193053259Smjacob 193143636Smjacob /* 193244354Smjacob * In case this doesn't work, do a REWIND instead 193343636Smjacob */ 193444354Smjacob if (error) { 193553259Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 193653259Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 193754099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1938112006Sphk softc->device_stats); 193953259Smjacob QFRLS(ccb); 194043636Smjacob } 194143636Smjacob if (error) { 194243636Smjacob xpt_release_ccb(ccb); 194343636Smjacob goto exit; 194443636Smjacob } 194543636Smjacob 194643636Smjacob /* 194753259Smjacob * Do a dummy test read to force access to the 194853259Smjacob * media so that the drive will really know what's 194954099Smjacob * there. We actually don't really care what the 195054099Smjacob * blocksize on tape is and don't expect to really 195154099Smjacob * read a full record. 195243636Smjacob */ 195339213Sgibbs rblim = (struct scsi_read_block_limits_data *) 1954111119Simp malloc(8192, M_TEMP, M_WAITOK); 195553259Smjacob if (rblim == NULL) { 1956164906Smjacob xpt_print(periph->path, "no memory for test read\n"); 195753259Smjacob xpt_release_ccb(ccb); 195853259Smjacob error = ENOMEM; 195953259Smjacob goto exit; 196053259Smjacob } 196156981Smjacob 196256981Smjacob if ((softc->quirks & SA_QUIRK_NODREAD) == 0) { 196356981Smjacob scsi_sa_read_write(&ccb->csio, 0, sadone, 196456981Smjacob MSG_SIMPLE_Q_TAG, 1, FALSE, 0, 8192, 196556981Smjacob (void *) rblim, 8192, SSD_FULL_SIZE, 196679100Smjacob IO_TIMEOUT); 196756981Smjacob (void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1968112006Sphk softc->device_stats); 196956981Smjacob QFRLS(ccb); 197056981Smjacob scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 197156981Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 197274840Sken error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, 197374840Sken SF_NO_PRINT | SF_RETRY_UA, 1974112006Sphk softc->device_stats); 197556981Smjacob QFRLS(ccb); 197656981Smjacob if (error) { 1977164906Smjacob xpt_print(periph->path, 1978164906Smjacob "unable to rewind after test read\n"); 197956981Smjacob xpt_release_ccb(ccb); 198056981Smjacob goto exit; 198156981Smjacob } 198253259Smjacob } 198339213Sgibbs 198453259Smjacob /* 198553259Smjacob * Next off, determine block limits. 198653259Smjacob */ 198753259Smjacob scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 198879100Smjacob rblim, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 198939213Sgibbs 199074840Sken error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, 1991112006Sphk SF_NO_PRINT | SF_RETRY_UA, softc->device_stats); 199274840Sken 199353259Smjacob QFRLS(ccb); 199439213Sgibbs xpt_release_ccb(ccb); 199539213Sgibbs 199641674Smjacob if (error != 0) { 199741674Smjacob /* 199841674Smjacob * If it's less than SCSI-2, READ BLOCK LIMITS is not 199941674Smjacob * a MANDATORY command. Anyway- it doesn't matter- 200041674Smjacob * we can proceed anyway. 200141674Smjacob */ 200241674Smjacob softc->blk_gran = 0; 200341674Smjacob softc->max_blk = ~0; 200441674Smjacob softc->min_blk = 0; 200541674Smjacob } else { 200674840Sken if (softc->scsi_rev >= SCSI_REV_SPC) { 200741674Smjacob softc->blk_gran = RBL_GRAN(rblim); 200841674Smjacob } else { 200941674Smjacob softc->blk_gran = 0; 201041674Smjacob } 201141674Smjacob /* 201241674Smjacob * We take max_blk == min_blk to mean a default to 201341674Smjacob * fixed mode- but note that whatever we get out of 201441674Smjacob * sagetparams below will actually determine whether 201541674Smjacob * we are actually *in* fixed mode. 201641674Smjacob */ 201741674Smjacob softc->max_blk = scsi_3btoul(rblim->maximum); 201841674Smjacob softc->min_blk = scsi_2btoul(rblim->minimum); 201941674Smjacob 202041674Smjacob 202141674Smjacob } 202241674Smjacob /* 202341674Smjacob * Next, perform a mode sense to determine 202441674Smjacob * current density, blocksize, compression etc. 202541674Smjacob */ 202641674Smjacob error = sagetparams(periph, SA_PARAM_ALL, 202741674Smjacob &softc->media_blksize, 202841674Smjacob &softc->media_density, 202941674Smjacob &softc->media_numblks, 203041674Smjacob &softc->buffer_mode, &write_protect, 203141674Smjacob &softc->speed, &comp_supported, 203241674Smjacob &comp_enabled, &softc->comp_algorithm, 203341674Smjacob NULL); 203441674Smjacob 203541674Smjacob if (error != 0) { 203641674Smjacob /* 203741674Smjacob * We could work a little harder here. We could 203841674Smjacob * adjust our attempts to get information. It 203941674Smjacob * might be an ancient tape drive. If someone 204041674Smjacob * nudges us, we'll do that. 204141674Smjacob */ 204239213Sgibbs goto exit; 204341674Smjacob } 204439213Sgibbs 204541906Smjacob /* 204641906Smjacob * If no quirk has determined that this is a device that is 204741906Smjacob * preferred to be in fixed or variable mode, now is the time 204841906Smjacob * to find out. 204941906Smjacob */ 205041906Smjacob if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) { 205141906Smjacob guessing = 1; 205243636Smjacob /* 205343636Smjacob * This could be expensive to find out. Luckily we 205443636Smjacob * only need to do this once. If we start out in 205543636Smjacob * 'default' mode, try and set ourselves to one 205643636Smjacob * of the densities that would determine a wad 205743636Smjacob * of other stuff. Go from highest to lowest. 205843636Smjacob */ 205943636Smjacob if (softc->media_density == SCSI_DEFAULT_DENSITY) { 206043636Smjacob int i; 206143636Smjacob static u_int8_t ctry[] = { 206243636Smjacob SCSI_DENSITY_HALFINCH_PE, 206343636Smjacob SCSI_DENSITY_HALFINCH_6250C, 206443636Smjacob SCSI_DENSITY_HALFINCH_6250, 206543636Smjacob SCSI_DENSITY_HALFINCH_1600, 206643636Smjacob SCSI_DENSITY_HALFINCH_800, 206746962Smjacob SCSI_DENSITY_QIC_4GB, 206846962Smjacob SCSI_DENSITY_QIC_2GB, 206943636Smjacob SCSI_DENSITY_QIC_525_320, 207043636Smjacob SCSI_DENSITY_QIC_150, 207143636Smjacob SCSI_DENSITY_QIC_120, 207243636Smjacob SCSI_DENSITY_QIC_24, 207343636Smjacob SCSI_DENSITY_QIC_11_9TRK, 207443636Smjacob SCSI_DENSITY_QIC_11_4TRK, 207546962Smjacob SCSI_DENSITY_QIC_1320, 207646962Smjacob SCSI_DENSITY_QIC_3080, 207743636Smjacob 0 207843636Smjacob }; 207943636Smjacob for (i = 0; ctry[i]; i++) { 208043636Smjacob error = sasetparams(periph, 208143636Smjacob SA_PARAM_DENSITY, 0, ctry[i], 208243636Smjacob 0, SF_NO_PRINT); 208343636Smjacob if (error == 0) { 208443636Smjacob softc->media_density = ctry[i]; 208543636Smjacob break; 208643636Smjacob } 208743636Smjacob } 208843636Smjacob } 208941906Smjacob switch (softc->media_density) { 209041906Smjacob case SCSI_DENSITY_QIC_11_4TRK: 209141906Smjacob case SCSI_DENSITY_QIC_11_9TRK: 209241906Smjacob case SCSI_DENSITY_QIC_24: 209341906Smjacob case SCSI_DENSITY_QIC_120: 209441906Smjacob case SCSI_DENSITY_QIC_150: 209565861Smjacob case SCSI_DENSITY_QIC_525_320: 209643636Smjacob case SCSI_DENSITY_QIC_1320: 209743636Smjacob case SCSI_DENSITY_QIC_3080: 209846962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 209943636Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 210041906Smjacob softc->last_media_blksize = 512; 210141906Smjacob break; 210246962Smjacob case SCSI_DENSITY_QIC_4GB: 210346962Smjacob case SCSI_DENSITY_QIC_2GB: 210446962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 210546962Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 210646962Smjacob softc->last_media_blksize = 1024; 210746962Smjacob break; 210841906Smjacob default: 210941906Smjacob softc->last_media_blksize = 211041906Smjacob softc->media_blksize; 211141906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 211241906Smjacob break; 211341906Smjacob } 211441906Smjacob } 211542563Smjacob 211641906Smjacob /* 211741906Smjacob * If no quirk has determined that this is a device that needs 211841906Smjacob * to have 2 Filemarks at EOD, now is the time to find out. 211941906Smjacob */ 212042563Smjacob 212142735Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) { 212241906Smjacob switch (softc->media_density) { 212341906Smjacob case SCSI_DENSITY_HALFINCH_800: 212441906Smjacob case SCSI_DENSITY_HALFINCH_1600: 212541906Smjacob case SCSI_DENSITY_HALFINCH_6250: 212641906Smjacob case SCSI_DENSITY_HALFINCH_6250C: 212741906Smjacob case SCSI_DENSITY_HALFINCH_PE: 212846962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 212941906Smjacob softc->quirks |= SA_QUIRK_2FM; 213041906Smjacob break; 213141906Smjacob default: 213241906Smjacob break; 213341906Smjacob } 213441906Smjacob } 213541906Smjacob 213641906Smjacob /* 213741906Smjacob * Now validate that some info we got makes sense. 213841906Smjacob */ 213941674Smjacob if ((softc->max_blk < softc->media_blksize) || 214041674Smjacob (softc->min_blk > softc->media_blksize && 214141674Smjacob softc->media_blksize)) { 2142164906Smjacob xpt_print(periph->path, 2143164906Smjacob "BLOCK LIMITS (%d..%d) could not match current " 214441674Smjacob "block settings (%d)- adjusting\n", softc->min_blk, 214541674Smjacob softc->max_blk, softc->media_blksize); 214641674Smjacob softc->max_blk = softc->min_blk = 214741674Smjacob softc->media_blksize; 214841674Smjacob } 214941906Smjacob 215041674Smjacob /* 215141906Smjacob * Now put ourselves into the right frame of mind based 215241906Smjacob * upon quirks... 215341906Smjacob */ 215441906Smjacobtryagain: 215542563Smjacob /* 215642563Smjacob * If we want to be in FIXED mode and our current blocksize 215742563Smjacob * is not equal to our last blocksize (if nonzero), try and 215842563Smjacob * set ourselves to this last blocksize (as the 'preferred' 215942563Smjacob * block size). The initial quirkmatch at registry sets the 216042563Smjacob * initial 'last' blocksize. If, for whatever reason, this 216142563Smjacob * 'last' blocksize is zero, set the blocksize to 512, 216242563Smjacob * or min_blk if that's larger. 216342563Smjacob */ 216441906Smjacob if ((softc->quirks & SA_QUIRK_FIXED) && 216560235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0 && 216642563Smjacob (softc->media_blksize != softc->last_media_blksize)) { 216741906Smjacob softc->media_blksize = softc->last_media_blksize; 216841906Smjacob if (softc->media_blksize == 0) { 216942563Smjacob softc->media_blksize = 512; 217041906Smjacob if (softc->media_blksize < softc->min_blk) { 217141906Smjacob softc->media_blksize = softc->min_blk; 217241906Smjacob } 217341906Smjacob } 217441906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 217542563Smjacob softc->media_blksize, 0, 0, SF_NO_PRINT); 217641906Smjacob if (error) { 2177164906Smjacob xpt_print(periph->path, 2178164906Smjacob "unable to set fixed blocksize to %d\n", 2179164906Smjacob softc->media_blksize); 218041906Smjacob goto exit; 218141906Smjacob } 218241906Smjacob } 218341906Smjacob 218441906Smjacob if ((softc->quirks & SA_QUIRK_VARIABLE) && 218541906Smjacob (softc->media_blksize != 0)) { 218641906Smjacob softc->last_media_blksize = softc->media_blksize; 218741906Smjacob softc->media_blksize = 0; 218841906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 218942563Smjacob 0, 0, 0, SF_NO_PRINT); 219041906Smjacob if (error) { 219141906Smjacob /* 219241906Smjacob * If this fails and we were guessing, just 219341906Smjacob * assume that we got it wrong and go try 219442563Smjacob * fixed block mode. Don't even check against 219542563Smjacob * density code at this point. 219641906Smjacob */ 219742563Smjacob if (guessing) { 219841906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 219941906Smjacob softc->quirks |= SA_QUIRK_FIXED; 220041906Smjacob if (softc->last_media_blksize == 0) 220141906Smjacob softc->last_media_blksize = 512; 220241906Smjacob goto tryagain; 220341906Smjacob } 2204164906Smjacob xpt_print(periph->path, 2205164906Smjacob "unable to set variable blocksize\n"); 220641906Smjacob goto exit; 220741906Smjacob } 220841906Smjacob } 220941906Smjacob 221041906Smjacob /* 221141674Smjacob * Now that we have the current block size, 221241674Smjacob * set up some parameters for sastart's usage. 221341674Smjacob */ 221441674Smjacob if (softc->media_blksize) { 221539213Sgibbs softc->flags |= SA_FLAG_FIXED; 221641674Smjacob if (powerof2(softc->media_blksize)) { 221741674Smjacob softc->blk_shift = 221841674Smjacob ffs(softc->media_blksize) - 1; 221941674Smjacob softc->blk_mask = softc->media_blksize - 1; 222039213Sgibbs } else { 222139213Sgibbs softc->blk_mask = ~0; 222239213Sgibbs softc->blk_shift = 0; 222339213Sgibbs } 222439213Sgibbs } else { 222539213Sgibbs /* 222641674Smjacob * The SCSI-3 spec allows 0 to mean "unspecified". 222741674Smjacob * The SCSI-1 spec allows 0 to mean 'infinite'. 222841674Smjacob * 222941674Smjacob * Either works here. 223039213Sgibbs */ 223139213Sgibbs if (softc->max_blk == 0) { 223239213Sgibbs softc->max_blk = ~0; 223339213Sgibbs } 223439213Sgibbs softc->blk_shift = 0; 223539213Sgibbs if (softc->blk_gran != 0) { 223639213Sgibbs softc->blk_mask = softc->blk_gran - 1; 223739213Sgibbs } else { 223839213Sgibbs softc->blk_mask = 0; 223939213Sgibbs } 224039213Sgibbs } 224139213Sgibbs 224239213Sgibbs if (write_protect) 224339213Sgibbs softc->flags |= SA_FLAG_TAPE_WP; 224439213Sgibbs 224539213Sgibbs if (comp_supported) { 224643636Smjacob if (softc->saved_comp_algorithm == 0) 224743636Smjacob softc->saved_comp_algorithm = 224843636Smjacob softc->comp_algorithm; 224946962Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 225046962Smjacob if (comp_enabled) 225146962Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 225239213Sgibbs } else 225339213Sgibbs softc->flags |= SA_FLAG_COMP_UNSUPP; 225439213Sgibbs 225560235Smjacob if ((softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) && 225660235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0) { 225741906Smjacob error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0, 225842563Smjacob 0, 0, SF_NO_PRINT); 225983473Smjacob if (error == 0) { 226041906Smjacob softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF; 226183473Smjacob } else { 2262164906Smjacob xpt_print(periph->path, 2263164906Smjacob "unable to set buffered mode\n"); 226483473Smjacob } 226560235Smjacob error = 0; /* not an error */ 226641906Smjacob } 226739213Sgibbs 226839213Sgibbs 226944354Smjacob if (error == 0) { 227041906Smjacob softc->flags |= SA_FLAG_TAPE_MOUNTED; 227144354Smjacob } 227239213Sgibbsexit: 227339213Sgibbs if (rblim != NULL) 227439213Sgibbs free(rblim, M_TEMP); 227539213Sgibbs 227643636Smjacob if (error != 0) { 227743636Smjacob softc->dsreg = MTIO_DSREG_NIL; 227844354Smjacob } else { 227944354Smjacob softc->fileno = softc->blkno = 0; 228043636Smjacob softc->dsreg = MTIO_DSREG_REST; 228144354Smjacob } 228251875Smjacob#ifdef SA_1FM_AT_EOD 228351875Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) 228451875Smjacob softc->quirks |= SA_QUIRK_1FM; 228551875Smjacob#else 228646962Smjacob if ((softc->quirks & SA_QUIRK_1FM) == 0) 228743636Smjacob softc->quirks |= SA_QUIRK_2FM; 228843636Smjacob#endif 228939213Sgibbs } else 229039213Sgibbs xpt_release_ccb(ccb); 229139213Sgibbs 229253259Smjacob /* 229353259Smjacob * If we return an error, we're not mounted any more, 229453259Smjacob * so release any device reservation. 229553259Smjacob */ 229653259Smjacob if (error != 0) { 229753259Smjacob (void) sareservereleaseunit(periph, FALSE); 229882575Smjacob } else { 229982575Smjacob /* 230082575Smjacob * Clear I/O residual. 230182575Smjacob */ 230282575Smjacob softc->last_io_resid = 0; 230382575Smjacob softc->last_ctl_resid = 0; 230453259Smjacob } 230554099Smjacob return (error); 230639213Sgibbs} 230739213Sgibbs 230868114Smjacob/* 230968114Smjacob * How many filemarks do we need to write if we were to terminate the 231068114Smjacob * tape session right now? Note that this can be a negative number 231168114Smjacob */ 231268114Smjacob 231339213Sgibbsstatic int 231468114Smjacobsamarkswanted(struct cam_periph *periph) 231539213Sgibbs{ 231639213Sgibbs int markswanted; 231739213Sgibbs struct sa_softc *softc; 231839213Sgibbs 231939213Sgibbs softc = (struct sa_softc *)periph->softc; 232039213Sgibbs markswanted = 0; 232139213Sgibbs if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) { 232239213Sgibbs markswanted++; 232346962Smjacob if (softc->quirks & SA_QUIRK_2FM) 232439213Sgibbs markswanted++; 232539213Sgibbs } 232668114Smjacob markswanted -= softc->filemarks; 232768114Smjacob return (markswanted); 232868114Smjacob} 232939213Sgibbs 233068114Smjacobstatic int 233168114Smjacobsacheckeod(struct cam_periph *periph) 233268114Smjacob{ 233368114Smjacob int error; 233468114Smjacob int markswanted; 233568114Smjacob 233668114Smjacob markswanted = samarkswanted(periph); 233768114Smjacob 233868114Smjacob if (markswanted > 0) { 233941906Smjacob error = sawritefilemarks(periph, markswanted, FALSE); 234039213Sgibbs } else { 234139213Sgibbs error = 0; 234239213Sgibbs } 234339213Sgibbs return (error); 234439213Sgibbs} 234539213Sgibbs 234639213Sgibbsstatic int 234746962Smjacobsaerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) 234839213Sgibbs{ 234946962Smjacob static const char *toobig = 235098449Srobert "%d-byte tape record bigger than supplied buffer\n"; 235139213Sgibbs struct cam_periph *periph; 235239213Sgibbs struct sa_softc *softc; 235339213Sgibbs struct ccb_scsiio *csio; 235439213Sgibbs struct scsi_sense_data *sense; 235553259Smjacob u_int32_t resid = 0; 235653259Smjacob int32_t info = 0; 235782575Smjacob cam_status status; 235882575Smjacob int error_code, sense_key, asc, ascq, error, aqvalid; 235939213Sgibbs 236039213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 236139213Sgibbs softc = (struct sa_softc *)periph->softc; 236239213Sgibbs csio = &ccb->csio; 236339213Sgibbs sense = &csio->sense_data; 236439213Sgibbs scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); 236582575Smjacob aqvalid = sense->extra_len >= 6; 236639213Sgibbs error = 0; 236746962Smjacob 236882575Smjacob status = csio->ccb_h.status & CAM_STATUS_MASK; 236982575Smjacob 237046962Smjacob /* 237182575Smjacob * Calculate/latch up, any residuals... We do this in a funny 2-step 237282575Smjacob * so we can print stuff here if we have CAM_DEBUG enabled for this 237382575Smjacob * unit. 237446962Smjacob */ 237582575Smjacob if (status == CAM_SCSI_STATUS_ERROR) { 237639213Sgibbs if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { 237746962Smjacob info = (int32_t) scsi_4btoul(sense->info); 237839213Sgibbs resid = info; 237939213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) 238039213Sgibbs resid *= softc->media_blksize; 238139213Sgibbs } else { 238239213Sgibbs resid = csio->dxfer_len; 238339213Sgibbs info = resid; 238441674Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 238541674Smjacob if (softc->media_blksize) 238641674Smjacob info /= softc->media_blksize; 238741674Smjacob } 238839213Sgibbs } 238971082Smjacob if (CCB_Type(csio) == SA_CCB_BUFFER_IO) { 239041948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense, 239141948Smjacob sizeof (struct scsi_sense_data)); 239242009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb, 239342009Smjacob (int) csio->cdb_len); 239441948Smjacob softc->last_io_resid = resid; 239571268Smjacob softc->last_resid_was_io = 1; 239641948Smjacob } else { 239741948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_ctl_sense, 239841948Smjacob sizeof (struct scsi_sense_data)); 239942009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_ctl_cdb, 240042009Smjacob (int) csio->cdb_len); 240141948Smjacob softc->last_ctl_resid = resid; 240271268Smjacob softc->last_resid_was_io = 0; 240341948Smjacob } 240482575Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x " 240582575Smjacob "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %d " 240682575Smjacob "dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff, 240782575Smjacob sense_key, asc, ascq, status, 240882575Smjacob sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len)); 240953259Smjacob } else { 241082575Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 241182575Smjacob ("Cam Status 0x%x\n", status)); 241241948Smjacob } 241341948Smjacob 241482575Smjacob switch (status) { 241582575Smjacob case CAM_REQ_CMP: 241682575Smjacob return (0); 241782575Smjacob case CAM_SCSI_STATUS_ERROR: 241882575Smjacob /* 241982575Smjacob * If a read/write command, we handle it here. 242082575Smjacob */ 242182575Smjacob if (CCB_Type(csio) != SA_CCB_WAITING) { 242282575Smjacob break; 242382575Smjacob } 242482575Smjacob /* 242582575Smjacob * If this was just EOM/EOP, Filemark, Setmark or ILI detected 242682575Smjacob * on a non read/write command, we assume it's not an error 242782575Smjacob * and propagate the residule and return. 242882575Smjacob */ 242982575Smjacob if ((aqvalid && asc == 0 && ascq > 0 && ascq <= 5) || 243082575Smjacob (aqvalid == 0 && sense_key == SSD_KEY_NO_SENSE)) { 243182575Smjacob csio->resid = resid; 243282575Smjacob QFRLS(ccb); 243382575Smjacob return (0); 243482575Smjacob } 243582575Smjacob /* 243682575Smjacob * Otherwise, we let the common code handle this. 243782575Smjacob */ 243846962Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 243941948Smjacob 244046962Smjacob /* 244182575Smjacob * XXX: To Be Fixed 244282575Smjacob * We cannot depend upon CAM honoring retry counts for these. 244346962Smjacob */ 244482575Smjacob case CAM_SCSI_BUS_RESET: 244582575Smjacob case CAM_BDR_SENT: 244682575Smjacob if (ccb->ccb_h.retry_count <= 0) { 244782575Smjacob return (EIO); 244882575Smjacob } 244982575Smjacob /* FALLTHROUGH */ 245082575Smjacob default: 245182575Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 245246962Smjacob } 245346962Smjacob 245446962Smjacob /* 245546962Smjacob * Handle filemark, end of tape, mismatched record sizes.... 245646962Smjacob * From this point out, we're only handling read/write cases. 245746962Smjacob * Handle writes && reads differently. 245846962Smjacob */ 245982575Smjacob 246046962Smjacob if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) { 246182575Smjacob if (sense_key == SSD_KEY_VOLUME_OVERFLOW) { 246239213Sgibbs csio->resid = resid; 246382575Smjacob error = ENOSPC; 246482575Smjacob } else if (sense->flags & SSD_EOM) { 246582575Smjacob softc->flags |= SA_FLAG_EOM_PENDING; 246682575Smjacob /* 246782575Smjacob * Grotesque as it seems, the few times 246882575Smjacob * I've actually seen a non-zero resid, 246982575Smjacob * the tape drive actually lied and had 2470124645Sjohan * written all the data!. 247182575Smjacob */ 247282575Smjacob csio->resid = 0; 247339213Sgibbs } 247446962Smjacob } else { 247582575Smjacob csio->resid = resid; 247646962Smjacob if (sense_key == SSD_KEY_BLANK_CHECK) { 247782575Smjacob if (softc->quirks & SA_QUIRK_1FM) { 247882575Smjacob error = 0; 247946962Smjacob softc->flags |= SA_FLAG_EOM_PENDING; 248046962Smjacob } else { 248146962Smjacob error = EIO; 248246962Smjacob } 248382575Smjacob } else if (sense->flags & SSD_FILEMARK) { 248482575Smjacob if (softc->flags & SA_FLAG_FIXED) { 248546962Smjacob error = -1; 248639213Sgibbs softc->flags |= SA_FLAG_EOF_PENDING; 248746962Smjacob } 248846962Smjacob /* 248946962Smjacob * Unconditionally, if we detected a filemark on a read, 249046962Smjacob * mark that we've run moved a file ahead. 249146962Smjacob */ 249243636Smjacob if (softc->fileno != (daddr_t) -1) { 249343636Smjacob softc->fileno++; 249443636Smjacob softc->blkno = 0; 249571082Smjacob csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED; 249643636Smjacob } 249739213Sgibbs } 249846962Smjacob } 249982575Smjacob 250046962Smjacob /* 250146962Smjacob * Incorrect Length usually applies to read, but can apply to writes. 250246962Smjacob */ 250346962Smjacob if (error == 0 && (sense->flags & SSD_ILI)) { 250446962Smjacob if (info < 0) { 2505164906Smjacob xpt_print(csio->ccb_h.path, toobig, 2506164906Smjacob csio->dxfer_len - info); 250746962Smjacob csio->resid = csio->dxfer_len; 250846962Smjacob error = EIO; 250946962Smjacob } else { 251046962Smjacob csio->resid = resid; 251182575Smjacob if (softc->flags & SA_FLAG_FIXED) { 251282575Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 251346962Smjacob } 251446962Smjacob /* 251546962Smjacob * Bump the block number if we hadn't seen a filemark. 251646962Smjacob * Do this independent of errors (we've moved anyway). 251746962Smjacob */ 251846962Smjacob if ((sense->flags & SSD_FILEMARK) == 0) { 251946962Smjacob if (softc->blkno != (daddr_t) -1) { 252046962Smjacob softc->blkno++; 252171082Smjacob csio->ccb_h.ccb_pflags |= 252271082Smjacob SA_POSITION_UPDATED; 252339213Sgibbs } 252439213Sgibbs } 252539213Sgibbs } 252639213Sgibbs } 252782575Smjacob 252882575Smjacob if (error <= 0) { 252982575Smjacob /* 253082575Smjacob * Unfreeze the queue if frozen as we're not returning anything 253182575Smjacob * to our waiters that would indicate an I/O error has occurred 253282575Smjacob * (yet). 253382575Smjacob */ 253482575Smjacob QFRLS(ccb); 253582575Smjacob error = 0; 253680575Smjacob } 253782575Smjacob return (error); 253839213Sgibbs} 253939213Sgibbs 254039213Sgibbsstatic int 254139213Sgibbssagetparams(struct cam_periph *periph, sa_params params_to_get, 254239213Sgibbs u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks, 254339213Sgibbs int *buff_mode, u_int8_t *write_protect, u_int8_t *speed, 254439213Sgibbs int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm, 254546962Smjacob sa_comp_t *tcs) 254639213Sgibbs{ 254739213Sgibbs union ccb *ccb; 254839213Sgibbs void *mode_buffer; 254939213Sgibbs struct scsi_mode_header_6 *mode_hdr; 255039213Sgibbs struct scsi_mode_blk_desc *mode_blk; 255139213Sgibbs int mode_buffer_len; 255239213Sgibbs struct sa_softc *softc; 255346962Smjacob u_int8_t cpage; 255439213Sgibbs int error; 255539213Sgibbs cam_status status; 255639213Sgibbs 255739213Sgibbs softc = (struct sa_softc *)periph->softc; 255846962Smjacob ccb = cam_periph_getccb(periph, 1); 255971082Smjacob if (softc->quirks & SA_QUIRK_NO_CPAGE) 256071082Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 256171082Smjacob else 256271082Smjacob cpage = SA_DATA_COMPRESSION_PAGE; 256339213Sgibbs 256439213Sgibbsretry: 256539213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 256639213Sgibbs 256739213Sgibbs if (params_to_get & SA_PARAM_COMPRESSION) { 256839213Sgibbs if (softc->quirks & SA_QUIRK_NOCOMP) { 256939213Sgibbs *comp_supported = FALSE; 257039213Sgibbs params_to_get &= ~SA_PARAM_COMPRESSION; 257139213Sgibbs } else 257246962Smjacob mode_buffer_len += sizeof (sa_comp_t); 257339213Sgibbs } 257454099Smjacob 2575111119Simp mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO); 257639213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 257739213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 257839213Sgibbs 257942716Smjacob /* it is safe to retry this */ 258042716Smjacob scsi_mode_sense(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 258142716Smjacob SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ? 258246962Smjacob cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len, 258379100Smjacob SSD_FULL_SIZE, SCSIOP_TIMEOUT); 258439213Sgibbs 258554099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 2586112006Sphk softc->device_stats); 258754099Smjacob QFRLS(ccb); 258839213Sgibbs 258939213Sgibbs status = ccb->ccb_h.status & CAM_STATUS_MASK; 259039213Sgibbs 259142716Smjacob if (error == EINVAL && (params_to_get & SA_PARAM_COMPRESSION) != 0) { 259239213Sgibbs /* 259346962Smjacob * Hmm. Let's see if we can try another page... 259446962Smjacob * If we've already done that, give up on compression 259546962Smjacob * for this device and remember this for the future 259646962Smjacob * and attempt the request without asking for compression 259746962Smjacob * info. 259839213Sgibbs */ 259946962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 260046962Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 260146962Smjacob goto retry; 260246962Smjacob } 260339213Sgibbs softc->quirks |= SA_QUIRK_NOCOMP; 260439213Sgibbs free(mode_buffer, M_TEMP); 260539213Sgibbs goto retry; 260646962Smjacob } else if (status == CAM_SCSI_STATUS_ERROR) { 260746962Smjacob /* Tell the user about the fatal error. */ 260846962Smjacob scsi_sense_print(&ccb->csio); 260946962Smjacob goto sagetparamsexit; 261046962Smjacob } 261139213Sgibbs 261246962Smjacob /* 261346962Smjacob * If the user only wants the compression information, and 261446962Smjacob * the device doesn't send back the block descriptor, it's 261546962Smjacob * no big deal. If the user wants more than just 261646962Smjacob * compression, though, and the device doesn't pass back the 261746962Smjacob * block descriptor, we need to send another mode sense to 261846962Smjacob * get the block descriptor. 261946962Smjacob */ 262046962Smjacob if ((mode_hdr->blk_desc_len == 0) && 262146962Smjacob (params_to_get & SA_PARAM_COMPRESSION) && 262246962Smjacob (params_to_get & ~(SA_PARAM_COMPRESSION))) { 262339213Sgibbs 262439213Sgibbs /* 262546962Smjacob * Decrease the mode buffer length by the size of 262646962Smjacob * the compression page, to make sure the data 262746962Smjacob * there doesn't get overwritten. 262839213Sgibbs */ 262946962Smjacob mode_buffer_len -= sizeof (sa_comp_t); 263039213Sgibbs 263146962Smjacob /* 263246962Smjacob * Now move the compression page that we presumably 263346962Smjacob * got back down the memory chunk a little bit so 263446962Smjacob * it doesn't get spammed. 263546962Smjacob */ 263654099Smjacob bcopy(&mode_hdr[0], &mode_hdr[1], sizeof (sa_comp_t)); 263754099Smjacob bzero(&mode_hdr[0], sizeof (mode_hdr[0])); 263839213Sgibbs 263946962Smjacob /* 264046962Smjacob * Now, we issue another mode sense and just ask 264146962Smjacob * for the block descriptor, etc. 264246962Smjacob */ 264339213Sgibbs 264446962Smjacob scsi_mode_sense(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 264546962Smjacob SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE, 264679100Smjacob mode_buffer, mode_buffer_len, SSD_FULL_SIZE, 264779100Smjacob SCSIOP_TIMEOUT); 264839213Sgibbs 264954099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 2650112006Sphk softc->device_stats); 265154099Smjacob QFRLS(ccb); 265239213Sgibbs 265346962Smjacob if (error != 0) 265446962Smjacob goto sagetparamsexit; 265546962Smjacob } 265639213Sgibbs 265746962Smjacob if (params_to_get & SA_PARAM_BLOCKSIZE) 265846962Smjacob *blocksize = scsi_3btoul(mode_blk->blklen); 265939213Sgibbs 266046962Smjacob if (params_to_get & SA_PARAM_NUMBLOCKS) 266146962Smjacob *numblocks = scsi_3btoul(mode_blk->nblocks); 266239213Sgibbs 266346962Smjacob if (params_to_get & SA_PARAM_BUFF_MODE) 266446962Smjacob *buff_mode = mode_hdr->dev_spec & SMH_SA_BUF_MODE_MASK; 266539213Sgibbs 266646962Smjacob if (params_to_get & SA_PARAM_DENSITY) 266746962Smjacob *density = mode_blk->density; 266839213Sgibbs 266946962Smjacob if (params_to_get & SA_PARAM_WP) 267046962Smjacob *write_protect = (mode_hdr->dev_spec & SMH_SA_WP)? TRUE : FALSE; 267139213Sgibbs 267246962Smjacob if (params_to_get & SA_PARAM_SPEED) 267346962Smjacob *speed = mode_hdr->dev_spec & SMH_SA_SPEED_MASK; 267439213Sgibbs 267546962Smjacob if (params_to_get & SA_PARAM_COMPRESSION) { 267654099Smjacob sa_comp_t *ntcs = (sa_comp_t *) &mode_blk[1]; 267746962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 267846962Smjacob struct scsi_data_compression_page *cp = &ntcs->dcomp; 267946962Smjacob *comp_supported = 268046962Smjacob (cp->dce_and_dcc & SA_DCP_DCC)? TRUE : FALSE; 268146962Smjacob *comp_enabled = 268246962Smjacob (cp->dce_and_dcc & SA_DCP_DCE)? TRUE : FALSE; 268346962Smjacob *comp_algorithm = scsi_4btoul(cp->comp_algorithm); 268446962Smjacob } else { 268546962Smjacob struct scsi_dev_conf_page *cp = &ntcs->dconf; 268646962Smjacob /* 268746962Smjacob * We don't really know whether this device supports 268846962Smjacob * Data Compression if the the algorithm field is 268946962Smjacob * zero. Just say we do. 269046962Smjacob */ 269146962Smjacob *comp_supported = TRUE; 269246962Smjacob *comp_enabled = 269346962Smjacob (cp->sel_comp_alg != SA_COMP_NONE)? TRUE : FALSE; 269446962Smjacob *comp_algorithm = cp->sel_comp_alg; 269541906Smjacob } 269646962Smjacob if (tcs != NULL) 269754099Smjacob bcopy(ntcs, tcs, sizeof (sa_comp_t)); 269839213Sgibbs } 269939213Sgibbs 270046962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 270146962Smjacob int idx; 270246962Smjacob char *xyz = mode_buffer; 270346962Smjacob xpt_print_path(periph->path); 270446962Smjacob printf("Mode Sense Data="); 270546962Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 270646962Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 270746962Smjacob printf("\n"); 270846962Smjacob } 270946962Smjacob 271039213Sgibbssagetparamsexit: 271139213Sgibbs 271239213Sgibbs xpt_release_ccb(ccb); 271339213Sgibbs free(mode_buffer, M_TEMP); 271454099Smjacob return (error); 271539213Sgibbs} 271639213Sgibbs 271739213Sgibbs/* 271839213Sgibbs * The purpose of this function is to set one of four different parameters 271939213Sgibbs * for a tape drive: 272039213Sgibbs * - blocksize 272139213Sgibbs * - density 272239213Sgibbs * - compression / compression algorithm 272339213Sgibbs * - buffering mode 272439213Sgibbs * 272539213Sgibbs * The assumption is that this will be called from saioctl(), and therefore 272639213Sgibbs * from a process context. Thus the waiting malloc calls below. If that 272739213Sgibbs * assumption ever changes, the malloc calls should be changed to be 272839213Sgibbs * NOWAIT mallocs. 272939213Sgibbs * 273039213Sgibbs * Any or all of the four parameters may be set when this function is 273139213Sgibbs * called. It should handle setting more than one parameter at once. 273239213Sgibbs */ 273339213Sgibbsstatic int 273439213Sgibbssasetparams(struct cam_periph *periph, sa_params params_to_set, 273546962Smjacob u_int32_t blocksize, u_int8_t density, u_int32_t calg, 273642563Smjacob u_int32_t sense_flags) 273739213Sgibbs{ 273839213Sgibbs struct sa_softc *softc; 273939213Sgibbs u_int32_t current_blocksize; 274046962Smjacob u_int32_t current_calg; 274139213Sgibbs u_int8_t current_density; 274239213Sgibbs u_int8_t current_speed; 274339213Sgibbs int comp_enabled, comp_supported; 274439213Sgibbs void *mode_buffer; 274539213Sgibbs int mode_buffer_len; 274639213Sgibbs struct scsi_mode_header_6 *mode_hdr; 274739213Sgibbs struct scsi_mode_blk_desc *mode_blk; 274846962Smjacob sa_comp_t *ccomp, *cpage; 274939213Sgibbs int buff_mode; 275046962Smjacob union ccb *ccb = NULL; 275139213Sgibbs int error; 275239213Sgibbs 275339213Sgibbs softc = (struct sa_softc *)periph->softc; 275439213Sgibbs 2755111119Simp ccomp = malloc(sizeof (sa_comp_t), M_TEMP, M_WAITOK); 275639213Sgibbs 275739213Sgibbs /* 275839213Sgibbs * Since it doesn't make sense to set the number of blocks, or 275939213Sgibbs * write protection, we won't try to get the current value. We 276039213Sgibbs * always want to get the blocksize, so we can set it back to the 276139213Sgibbs * proper value. 276239213Sgibbs */ 276346962Smjacob error = sagetparams(periph, 276446962Smjacob params_to_set | SA_PARAM_BLOCKSIZE | SA_PARAM_SPEED, 276546962Smjacob ¤t_blocksize, ¤t_density, NULL, &buff_mode, NULL, 276646962Smjacob ¤t_speed, &comp_supported, &comp_enabled, 276746962Smjacob ¤t_calg, ccomp); 276839213Sgibbs 276939213Sgibbs if (error != 0) { 277046962Smjacob free(ccomp, M_TEMP); 277154099Smjacob return (error); 277239213Sgibbs } 277339213Sgibbs 277439213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 277539213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 277646962Smjacob mode_buffer_len += sizeof (sa_comp_t); 277739213Sgibbs 2778111119Simp mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO); 277939213Sgibbs 278039213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 278139213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 278239213Sgibbs 278353259Smjacob ccb = cam_periph_getccb(periph, 1); 278453259Smjacob 278553259Smjacobretry: 278653259Smjacob 278739213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) { 278853259Smjacob if (mode_blk) { 278953259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 279053259Smjacob } else { 279153259Smjacob cpage = (sa_comp_t *)&mode_hdr[1]; 279253259Smjacob } 279346962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 279454099Smjacob cpage->hdr.pagecode &= ~0x80; 279539213Sgibbs } else 279646962Smjacob cpage = NULL; 279739213Sgibbs 279839213Sgibbs /* 279939213Sgibbs * If the caller wants us to set the blocksize, use the one they 280039213Sgibbs * pass in. Otherwise, use the blocksize we got back from the 280139213Sgibbs * mode select above. 280239213Sgibbs */ 280353259Smjacob if (mode_blk) { 280453259Smjacob if (params_to_set & SA_PARAM_BLOCKSIZE) 280553259Smjacob scsi_ulto3b(blocksize, mode_blk->blklen); 280653259Smjacob else 280753259Smjacob scsi_ulto3b(current_blocksize, mode_blk->blklen); 280839213Sgibbs 280953259Smjacob /* 281053259Smjacob * Set density if requested, else preserve old density. 281153259Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 281253259Smjacob * devices, else density we've latched up in our softc. 281353259Smjacob */ 281453259Smjacob if (params_to_set & SA_PARAM_DENSITY) { 281553259Smjacob mode_blk->density = density; 281653259Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 281753259Smjacob mode_blk->density = SCSI_SAME_DENSITY; 281853259Smjacob } else { 281953259Smjacob mode_blk->density = softc->media_density; 282053259Smjacob } 282141674Smjacob } 282239213Sgibbs 282339213Sgibbs /* 282439213Sgibbs * For mode selects, these two fields must be zero. 282539213Sgibbs */ 282639213Sgibbs mode_hdr->data_length = 0; 282739213Sgibbs mode_hdr->medium_type = 0; 282839213Sgibbs 282939213Sgibbs /* set the speed to the current value */ 283039213Sgibbs mode_hdr->dev_spec = current_speed; 283139213Sgibbs 2832120019Smjacob /* if set, set single-initiator buffering mode */ 2833120019Smjacob if (softc->buffer_mode == SMH_SA_BUF_MODE_SIBUF) { 2834120019Smjacob mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF; 2835120019Smjacob } 283639213Sgibbs 283753259Smjacob if (mode_blk) 283853259Smjacob mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc); 283953259Smjacob else 284053259Smjacob mode_hdr->blk_desc_len = 0; 284139213Sgibbs 284239213Sgibbs /* 284339213Sgibbs * First, if the user wants us to set the compression algorithm or 284439213Sgibbs * just turn compression on, check to make sure that this drive 284539213Sgibbs * supports compression. 284639213Sgibbs */ 284746962Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 284839213Sgibbs /* 284939213Sgibbs * If the compression algorithm is 0, disable compression. 285039213Sgibbs * If the compression algorithm is non-zero, enable 285139213Sgibbs * compression and set the compression type to the 285239213Sgibbs * specified compression algorithm, unless the algorithm is 285339213Sgibbs * MT_COMP_ENABLE. In that case, we look at the 285439213Sgibbs * compression algorithm that is currently set and if it is 285539213Sgibbs * non-zero, we leave it as-is. If it is zero, and we have 285639213Sgibbs * saved a compression algorithm from a time when 285739213Sgibbs * compression was enabled before, set the compression to 285839213Sgibbs * the saved value. 285939213Sgibbs */ 286054099Smjacob switch (ccomp->hdr.pagecode & ~0x80) { 2861115660Smjacob case SA_DEVICE_CONFIGURATION_PAGE: 2862115660Smjacob { 2863115660Smjacob struct scsi_dev_conf_page *dcp = &cpage->dconf; 2864115660Smjacob if (calg == 0) { 2865115660Smjacob dcp->sel_comp_alg = SA_COMP_NONE; 2866115660Smjacob break; 2867115660Smjacob } 2868115660Smjacob if (calg != MT_COMP_ENABLE) { 2869115660Smjacob dcp->sel_comp_alg = calg; 2870115660Smjacob } else if (dcp->sel_comp_alg == SA_COMP_NONE && 2871115660Smjacob softc->saved_comp_algorithm != 0) { 2872115660Smjacob dcp->sel_comp_alg = softc->saved_comp_algorithm; 2873115660Smjacob } 2874115660Smjacob break; 2875115660Smjacob } 287646962Smjacob case SA_DATA_COMPRESSION_PAGE: 287746962Smjacob if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) { 287846962Smjacob struct scsi_data_compression_page *dcp = &cpage->dcomp; 287946962Smjacob if (calg == 0) { 288054099Smjacob /* 288154099Smjacob * Disable compression, but leave the 288254099Smjacob * decompression and the capability bit 288354099Smjacob * alone. 288454099Smjacob */ 288554099Smjacob dcp->dce_and_dcc = SA_DCP_DCC; 288654099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 288746962Smjacob break; 288846962Smjacob } 288953259Smjacob /* enable compression && decompression */ 289054099Smjacob dcp->dce_and_dcc = SA_DCP_DCE | SA_DCP_DCC; 289154099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 289253259Smjacob /* 289353259Smjacob * If there, use compression algorithm from caller. 289453259Smjacob * Otherwise, if there's a saved compression algorithm 289553259Smjacob * and there is no current algorithm, use the saved 289653259Smjacob * algorithm. Else parrot back what we got and hope 289753259Smjacob * for the best. 289853259Smjacob */ 289946962Smjacob if (calg != MT_COMP_ENABLE) { 290046962Smjacob scsi_ulto4b(calg, dcp->comp_algorithm); 290153259Smjacob scsi_ulto4b(calg, dcp->decomp_algorithm); 290246962Smjacob } else if (scsi_4btoul(dcp->comp_algorithm) == 0 && 290346962Smjacob softc->saved_comp_algorithm != 0) { 290439213Sgibbs scsi_ulto4b(softc->saved_comp_algorithm, 290546962Smjacob dcp->comp_algorithm); 290653259Smjacob scsi_ulto4b(softc->saved_comp_algorithm, 290753259Smjacob dcp->decomp_algorithm); 290839213Sgibbs } 290946962Smjacob break; 291039213Sgibbs } 2911115660Smjacob /* 2912115660Smjacob * Compression does not appear to be supported- 2913115660Smjacob * at least via the DATA COMPRESSION page. It 2914115660Smjacob * would be too much to ask us to believe that 2915115660Smjacob * the page itself is supported, but incorrectly 2916115660Smjacob * reports an ability to manipulate data compression, 2917115660Smjacob * so we'll assume that this device doesn't support 2918115660Smjacob * compression. We can just fall through for that. 2919115660Smjacob */ 2920115660Smjacob /* FALLTHROUGH */ 292146962Smjacob default: 292246962Smjacob /* 292354099Smjacob * The drive doesn't seem to support compression, 292446962Smjacob * so turn off the set compression bit. 292546962Smjacob */ 292646962Smjacob params_to_set &= ~SA_PARAM_COMPRESSION; 2927164906Smjacob xpt_print(periph->path, 2928164906Smjacob "device does not seem to support compression\n"); 292954099Smjacob 293046962Smjacob /* 293146962Smjacob * If that was the only thing the user wanted us to set, 293246962Smjacob * clean up allocated resources and return with 293346962Smjacob * 'operation not supported'. 293446962Smjacob */ 293546962Smjacob if (params_to_set == SA_PARAM_NONE) { 293646962Smjacob free(mode_buffer, M_TEMP); 293754099Smjacob xpt_release_ccb(ccb); 293854099Smjacob return (ENODEV); 293946962Smjacob } 294046962Smjacob 294146962Smjacob /* 294246962Smjacob * That wasn't the only thing the user wanted us to set. 294346962Smjacob * So, decrease the stated mode buffer length by the 294446962Smjacob * size of the compression mode page. 294546962Smjacob */ 294646962Smjacob mode_buffer_len -= sizeof(sa_comp_t); 294746962Smjacob } 294839213Sgibbs } 294939213Sgibbs 295046962Smjacob /* It is safe to retry this operation */ 295146962Smjacob scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 295246962Smjacob (params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE, 295379100Smjacob FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 295441674Smjacob 295546962Smjacob error = cam_periph_runccb(ccb, saerror, 0, 2956112006Sphk sense_flags, softc->device_stats); 295754099Smjacob QFRLS(ccb); 295839213Sgibbs 295946962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 296041906Smjacob int idx; 296141674Smjacob char *xyz = mode_buffer; 296241674Smjacob xpt_print_path(periph->path); 296342009Smjacob printf("Err%d, Mode Select Data=", error); 296441906Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 296542009Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 296641674Smjacob printf("\n"); 296741674Smjacob } 296841674Smjacob 296939213Sgibbs 297053259Smjacob if (error) { 297139213Sgibbs /* 297253259Smjacob * If we can, try without setting density/blocksize. 297353259Smjacob */ 297453259Smjacob if (mode_blk) { 297553259Smjacob if ((params_to_set & 297653259Smjacob (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) { 297753259Smjacob mode_blk = NULL; 297853259Smjacob goto retry; 297953259Smjacob } 298053259Smjacob } else { 298153259Smjacob mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 298253259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 298353259Smjacob } 298453259Smjacob 298553259Smjacob /* 298639213Sgibbs * If we were setting the blocksize, and that failed, we 298739213Sgibbs * want to set it to its original value. If we weren't 298839213Sgibbs * setting the blocksize, we don't want to change it. 298939213Sgibbs */ 299039213Sgibbs scsi_ulto3b(current_blocksize, mode_blk->blklen); 299139213Sgibbs 299239213Sgibbs /* 299341674Smjacob * Set density if requested, else preserve old density. 299441674Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 299541674Smjacob * devices, else density we've latched up in our softc. 299639213Sgibbs */ 299741674Smjacob if (params_to_set & SA_PARAM_DENSITY) { 299839213Sgibbs mode_blk->density = current_density; 299941674Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 300041674Smjacob mode_blk->density = SCSI_SAME_DENSITY; 300141674Smjacob } else { 300241674Smjacob mode_blk->density = softc->media_density; 300341674Smjacob } 300439213Sgibbs 300539213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 300646962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 300739213Sgibbs 300839213Sgibbs /* 300939213Sgibbs * The retry count is the only CCB field that might have been 301039213Sgibbs * changed that we care about, so reset it back to 1. 301139213Sgibbs */ 301239213Sgibbs ccb->ccb_h.retry_count = 1; 301354099Smjacob cam_periph_runccb(ccb, saerror, 0, sense_flags, 3014112006Sphk softc->device_stats); 301554099Smjacob QFRLS(ccb); 301639213Sgibbs } 301739213Sgibbs 301853259Smjacob xpt_release_ccb(ccb); 301953259Smjacob 302046962Smjacob if (ccomp != NULL) 302146962Smjacob free(ccomp, M_TEMP); 302239213Sgibbs 302341948Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 302441948Smjacob if (error) { 302541948Smjacob softc->flags &= ~SA_FLAG_COMP_ENABLED; 302646962Smjacob /* 302746962Smjacob * Even if we get an error setting compression, 302846962Smjacob * do not say that we don't support it. We could 302946962Smjacob * have been wrong, or it may be media specific. 303046962Smjacob * softc->flags &= ~SA_FLAG_COMP_SUPP; 303146962Smjacob */ 303241948Smjacob softc->saved_comp_algorithm = softc->comp_algorithm; 303341948Smjacob softc->comp_algorithm = 0; 303441948Smjacob } else { 303541948Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 303646962Smjacob softc->comp_algorithm = calg; 303741948Smjacob } 303841948Smjacob } 303941948Smjacob 304039213Sgibbs free(mode_buffer, M_TEMP); 304154099Smjacob return (error); 304239213Sgibbs} 304339213Sgibbs 304439213Sgibbsstatic void 304539213Sgibbssaprevent(struct cam_periph *periph, int action) 304639213Sgibbs{ 304739213Sgibbs struct sa_softc *softc; 304839213Sgibbs union ccb *ccb; 304942735Smjacob int error, sf; 305039213Sgibbs 305139213Sgibbs softc = (struct sa_softc *)periph->softc; 305239213Sgibbs 305342735Smjacob if ((action == PR_ALLOW) && (softc->flags & SA_FLAG_TAPE_LOCKED) == 0) 305439213Sgibbs return; 305542735Smjacob if ((action == PR_PREVENT) && (softc->flags & SA_FLAG_TAPE_LOCKED) != 0) 305642735Smjacob return; 305739213Sgibbs 305856981Smjacob /* 305956981Smjacob * We can be quiet about illegal requests. 306056981Smjacob */ 306156981Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 306242735Smjacob sf = 0; 306356981Smjacob } else 306442735Smjacob sf = SF_QUIET_IR; 306542735Smjacob 306642716Smjacob ccb = cam_periph_getccb(periph, 1); 306739213Sgibbs 306842716Smjacob /* It is safe to retry this operation */ 306942716Smjacob scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action, 307079100Smjacob SSD_FULL_SIZE, SCSIOP_TIMEOUT); 307139213Sgibbs 3072112006Sphk error = cam_periph_runccb(ccb, saerror, 0, sf, softc->device_stats); 307353522Smjacob QFRLS(ccb); 307439213Sgibbs if (error == 0) { 307539213Sgibbs if (action == PR_ALLOW) 307639213Sgibbs softc->flags &= ~SA_FLAG_TAPE_LOCKED; 307739213Sgibbs else 307839213Sgibbs softc->flags |= SA_FLAG_TAPE_LOCKED; 307939213Sgibbs } 308039213Sgibbs 308139213Sgibbs xpt_release_ccb(ccb); 308239213Sgibbs} 308339213Sgibbs 308439213Sgibbsstatic int 308539213Sgibbssarewind(struct cam_periph *periph) 308639213Sgibbs{ 308739213Sgibbs union ccb *ccb; 308839213Sgibbs struct sa_softc *softc; 308939213Sgibbs int error; 309039213Sgibbs 309139213Sgibbs softc = (struct sa_softc *)periph->softc; 309239213Sgibbs 309346962Smjacob ccb = cam_periph_getccb(periph, 1); 309439213Sgibbs 309542716Smjacob /* It is safe to retry this operation */ 309646962Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 309753259Smjacob SSD_FULL_SIZE, REWIND_TIMEOUT); 309839213Sgibbs 309943636Smjacob softc->dsreg = MTIO_DSREG_REW; 3100112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 310143636Smjacob softc->dsreg = MTIO_DSREG_REST; 310239213Sgibbs 310339213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 310442716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 310542716Smjacob 310639213Sgibbs xpt_release_ccb(ccb); 310743636Smjacob if (error == 0) 310843636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 310943636Smjacob else 311043636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 311139213Sgibbs return (error); 311239213Sgibbs} 311339213Sgibbs 311439213Sgibbsstatic int 311539213Sgibbssaspace(struct cam_periph *periph, int count, scsi_space_code code) 311639213Sgibbs{ 311739213Sgibbs union ccb *ccb; 311839213Sgibbs struct sa_softc *softc; 311939213Sgibbs int error; 312039213Sgibbs 312139213Sgibbs softc = (struct sa_softc *)periph->softc; 312239213Sgibbs 312346962Smjacob ccb = cam_periph_getccb(periph, 1); 312439213Sgibbs 312542716Smjacob /* This cannot be retried */ 312639213Sgibbs 312742716Smjacob scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count, 312853259Smjacob SSD_FULL_SIZE, SPACE_TIMEOUT); 312939213Sgibbs 313071087Smjacob /* 313171087Smjacob * Clear residual because we will be using it. 313271087Smjacob */ 313371087Smjacob softc->last_ctl_resid = 0; 313471087Smjacob 313543636Smjacob softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD; 3136112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 313743636Smjacob softc->dsreg = MTIO_DSREG_REST; 313842716Smjacob 313939213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 314042716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 314142716Smjacob 314239213Sgibbs xpt_release_ccb(ccb); 314343636Smjacob 314442716Smjacob /* 314543636Smjacob * If a spacing operation has failed, we need to invalidate 314643636Smjacob * this mount. 314743636Smjacob * 314843636Smjacob * If the spacing operation was setmarks or to end of recorded data, 314943636Smjacob * we no longer know our relative position. 315043636Smjacob * 315171087Smjacob * If the spacing operations was spacing files in reverse, we 315271087Smjacob * take account of the residual, but still check against less 315371087Smjacob * than zero- if we've gone negative, we must have hit BOT. 315471087Smjacob * 315571087Smjacob * If the spacing operations was spacing records in reverse and 315671087Smjacob * we have a residual, we've either hit BOT or hit a filemark. 315771087Smjacob * In the former case, we know our new record number (0). In 315871087Smjacob * the latter case, we have absolutely no idea what the real 315971087Smjacob * record number is- we've stopped between the end of the last 316071087Smjacob * record in the previous file and the filemark that stopped 316171087Smjacob * our spacing backwards. 316242716Smjacob */ 316343636Smjacob if (error) { 316443636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 316543636Smjacob } else if (code == SS_SETMARKS || code == SS_EOD) { 316643636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 316743636Smjacob } else if (code == SS_FILEMARKS && softc->fileno != (daddr_t) -1) { 316871087Smjacob softc->fileno += (count - softc->last_ctl_resid); 316971087Smjacob if (softc->fileno < 0) /* we must of hit BOT */ 317071087Smjacob softc->fileno = 0; 317143636Smjacob softc->blkno = 0; 317243636Smjacob } else if (code == SS_BLOCKS && softc->blkno != (daddr_t) -1) { 317371087Smjacob softc->blkno += (count - softc->last_ctl_resid); 317471087Smjacob if (count < 0) { 317571087Smjacob if (softc->last_ctl_resid || softc->blkno < 0) { 317671087Smjacob if (softc->fileno == 0) { 317771087Smjacob softc->blkno = 0; 317871087Smjacob } else { 317971087Smjacob softc->blkno = (daddr_t) -1; 318071087Smjacob } 318171087Smjacob } 318271087Smjacob } 318343636Smjacob } 318439213Sgibbs return (error); 318539213Sgibbs} 318639213Sgibbs 318739213Sgibbsstatic int 318839213Sgibbssawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks) 318939213Sgibbs{ 319039213Sgibbs union ccb *ccb; 319139213Sgibbs struct sa_softc *softc; 319271087Smjacob int error, nwm = 0; 319339213Sgibbs 319439213Sgibbs softc = (struct sa_softc *)periph->softc; 3195154360Smjacob if (softc->open_rdonly) 3196154360Smjacob return (EBADF); 319739213Sgibbs 319846962Smjacob ccb = cam_periph_getccb(periph, 1); 319971087Smjacob /* 320071087Smjacob * Clear residual because we will be using it. 320171087Smjacob */ 320271087Smjacob softc->last_ctl_resid = 0; 320339213Sgibbs 320443636Smjacob softc->dsreg = MTIO_DSREG_FMK; 320542716Smjacob /* this *must* not be retried */ 320642716Smjacob scsi_write_filemarks(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, 320779100Smjacob FALSE, setmarks, nmarks, SSD_FULL_SIZE, IO_TIMEOUT); 320843636Smjacob softc->dsreg = MTIO_DSREG_REST; 320939213Sgibbs 321043636Smjacob 3211112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 321239213Sgibbs 321339213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 321442716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 321539213Sgibbs 321641918Smjacob if (error == 0 && nmarks) { 321741918Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 321871087Smjacob nwm = nmarks - softc->last_ctl_resid; 321971087Smjacob softc->filemarks += nwm; 322039213Sgibbs } 322171087Smjacob 322241918Smjacob xpt_release_ccb(ccb); 322343636Smjacob 322443636Smjacob /* 322543636Smjacob * Update relative positions (if we're doing that). 322643636Smjacob */ 322743636Smjacob if (error) { 322843636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 322943636Smjacob } else if (softc->fileno != (daddr_t) -1) { 323071087Smjacob softc->fileno += nwm; 323143636Smjacob softc->blkno = 0; 323243636Smjacob } 323341918Smjacob return (error); 323441918Smjacob} 323539213Sgibbs 323641918Smjacobstatic int 323741918Smjacobsardpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 323841918Smjacob{ 323941918Smjacob struct scsi_tape_position_data loc; 324041918Smjacob union ccb *ccb; 324146962Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 324241918Smjacob int error; 324341918Smjacob 324441918Smjacob /* 324571082Smjacob * We try and flush any buffered writes here if we were writing 324671082Smjacob * and we're trying to get hardware block position. It eats 324771082Smjacob * up performance substantially, but I'm wary of drive firmware. 324846962Smjacob * 324971082Smjacob * I think that *logical* block position is probably okay- 325071082Smjacob * but hardware block position might have to wait for data 325171082Smjacob * to hit media to be valid. Caveat Emptor. 325241918Smjacob */ 325341918Smjacob 325471082Smjacob if (hard && (softc->flags & SA_FLAG_TAPE_WRITTEN)) { 325546962Smjacob error = sawritefilemarks(periph, 0, 0); 325646962Smjacob if (error && error != EACCES) 325746962Smjacob return (error); 325846962Smjacob } 325941918Smjacob 326066678Smjacob ccb = cam_periph_getccb(periph, 1); 326141918Smjacob scsi_read_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 326279100Smjacob hard, &loc, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 326343636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 3264112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 326543636Smjacob softc->dsreg = MTIO_DSREG_REST; 326641918Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 326741918Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 326841918Smjacob 326941918Smjacob if (error == 0) { 327041918Smjacob if (loc.flags & SA_RPOS_UNCERTAIN) { 327141918Smjacob error = EINVAL; /* nothing is certain */ 327241918Smjacob } else { 327341918Smjacob *blkptr = scsi_4btoul(loc.firstblk); 327441918Smjacob } 327541918Smjacob } 327641918Smjacob 327739213Sgibbs xpt_release_ccb(ccb); 327839213Sgibbs return (error); 327939213Sgibbs} 328039213Sgibbs 328139213Sgibbsstatic int 328241918Smjacobsasetpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 328341918Smjacob{ 328441918Smjacob union ccb *ccb; 328541918Smjacob struct sa_softc *softc; 328641918Smjacob int error; 328741918Smjacob 328841918Smjacob /* 328946962Smjacob * We used to try and flush any buffered writes here. 329046962Smjacob * Now we push this onto user applications to either 329146962Smjacob * flush the pending writes themselves (via a zero count 329246962Smjacob * WRITE FILEMARKS command) or they can trust their tape 329346962Smjacob * drive to do this correctly for them. 329446962Smjacob */ 329541918Smjacob 329641918Smjacob softc = (struct sa_softc *)periph->softc; 329746962Smjacob ccb = cam_periph_getccb(periph, 1); 329841918Smjacob 329943636Smjacob 330041918Smjacob scsi_set_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 330179100Smjacob hard, *blkptr, SSD_FULL_SIZE, SPACE_TIMEOUT); 330243636Smjacob 330379100Smjacob 330443636Smjacob softc->dsreg = MTIO_DSREG_POS; 3305112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 330643636Smjacob softc->dsreg = MTIO_DSREG_REST; 330741918Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 330841918Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 330941918Smjacob xpt_release_ccb(ccb); 331041918Smjacob /* 331146962Smjacob * Note relative file && block number position as now unknown. 331241918Smjacob */ 331343636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 331441918Smjacob return (error); 331541918Smjacob} 331641918Smjacob 331741918Smjacobstatic int 331839213Sgibbssaretension(struct cam_periph *periph) 331939213Sgibbs{ 332039213Sgibbs union ccb *ccb; 332139213Sgibbs struct sa_softc *softc; 332239213Sgibbs int error; 332339213Sgibbs 332439213Sgibbs softc = (struct sa_softc *)periph->softc; 332539213Sgibbs 332646962Smjacob ccb = cam_periph_getccb(periph, 1); 332739213Sgibbs 332842716Smjacob /* It is safe to retry this operation */ 332942716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 333053259Smjacob FALSE, TRUE, TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT); 333139213Sgibbs 333243636Smjacob softc->dsreg = MTIO_DSREG_TEN; 3333112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 333443636Smjacob softc->dsreg = MTIO_DSREG_REST; 333539213Sgibbs 333639213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 333742716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 333839213Sgibbs xpt_release_ccb(ccb); 333943636Smjacob if (error == 0) 334043636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 334143636Smjacob else 334243636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 334354099Smjacob return (error); 334439213Sgibbs} 334539213Sgibbs 334639213Sgibbsstatic int 334739213Sgibbssareservereleaseunit(struct cam_periph *periph, int reserve) 334839213Sgibbs{ 334939213Sgibbs union ccb *ccb; 335039213Sgibbs struct sa_softc *softc; 335154099Smjacob int error; 335239213Sgibbs 335342009Smjacob softc = (struct sa_softc *)periph->softc; 335442716Smjacob ccb = cam_periph_getccb(periph, 1); 335539213Sgibbs 335642716Smjacob /* It is safe to retry this operation */ 335754099Smjacob scsi_reserve_release_unit(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 335879100Smjacob FALSE, 0, SSD_FULL_SIZE, SCSIOP_TIMEOUT, reserve); 335943636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 336054099Smjacob error = cam_periph_runccb(ccb, saerror, 0, 3361112006Sphk SF_RETRY_UA | SF_NO_PRINT, softc->device_stats); 336243636Smjacob softc->dsreg = MTIO_DSREG_REST; 336354099Smjacob QFRLS(ccb); 336439213Sgibbs xpt_release_ccb(ccb); 336539213Sgibbs 336641674Smjacob /* 336741674Smjacob * If the error was Illegal Request, then the device doesn't support 336841674Smjacob * RESERVE/RELEASE. This is not an error. 336941674Smjacob */ 337042009Smjacob if (error == EINVAL) { 337141674Smjacob error = 0; 337242009Smjacob } 337341674Smjacob 337439213Sgibbs return (error); 337539213Sgibbs} 337639213Sgibbs 337739213Sgibbsstatic int 337839213Sgibbssaloadunload(struct cam_periph *periph, int load) 337939213Sgibbs{ 338039213Sgibbs union ccb *ccb; 338139213Sgibbs struct sa_softc *softc; 338239213Sgibbs int error; 338339213Sgibbs 338439213Sgibbs softc = (struct sa_softc *)periph->softc; 338539213Sgibbs 338646962Smjacob ccb = cam_periph_getccb(periph, 1); 338739213Sgibbs 338842716Smjacob /* It is safe to retry this operation */ 338942716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 339054099Smjacob FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT); 339139213Sgibbs 339243636Smjacob softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL; 3393112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 339443636Smjacob softc->dsreg = MTIO_DSREG_REST; 339554099Smjacob QFRLS(ccb); 339639213Sgibbs xpt_release_ccb(ccb); 339743636Smjacob 339843636Smjacob if (error || load == 0) 339943636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 340043636Smjacob else if (error == 0) 340143636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 340239213Sgibbs return (error); 340339213Sgibbs} 340439213Sgibbs 340539213Sgibbsstatic int 340639213Sgibbssaerase(struct cam_periph *periph, int longerase) 340739213Sgibbs{ 340839213Sgibbs 340939213Sgibbs union ccb *ccb; 341039213Sgibbs struct sa_softc *softc; 341139213Sgibbs int error; 341239213Sgibbs 341339213Sgibbs softc = (struct sa_softc *)periph->softc; 3414154360Smjacob if (softc->open_rdonly) 3415154360Smjacob return (EBADF); 341639213Sgibbs 341746962Smjacob ccb = cam_periph_getccb(periph, 1); 341839213Sgibbs 341943636Smjacob scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase, 342053259Smjacob SSD_FULL_SIZE, ERASE_TIMEOUT); 342139213Sgibbs 342243636Smjacob softc->dsreg = MTIO_DSREG_ZER; 3423112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 342443636Smjacob softc->dsreg = MTIO_DSREG_REST; 342539213Sgibbs 342639213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 342743636Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 342839213Sgibbs xpt_release_ccb(ccb); 342939213Sgibbs return (error); 343039213Sgibbs} 343139213Sgibbs 343255205Speter#endif /* _KERNEL */ 343339213Sgibbs 343439213Sgibbs/* 343539213Sgibbs * Read tape block limits command. 343639213Sgibbs */ 343739213Sgibbsvoid 343839213Sgibbsscsi_read_block_limits(struct ccb_scsiio *csio, u_int32_t retries, 343939213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 344039213Sgibbs u_int8_t tag_action, 344139213Sgibbs struct scsi_read_block_limits_data *rlimit_buf, 344239213Sgibbs u_int8_t sense_len, u_int32_t timeout) 344339213Sgibbs{ 344439213Sgibbs struct scsi_read_block_limits *scsi_cmd; 344539213Sgibbs 344646962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 344746962Smjacob (u_int8_t *)rlimit_buf, sizeof(*rlimit_buf), sense_len, 344846962Smjacob sizeof(*scsi_cmd), timeout); 344939213Sgibbs 345039213Sgibbs scsi_cmd = (struct scsi_read_block_limits *)&csio->cdb_io.cdb_bytes; 345139213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 345239213Sgibbs scsi_cmd->opcode = READ_BLOCK_LIMITS; 345339213Sgibbs} 345439213Sgibbs 345539213Sgibbsvoid 345639213Sgibbsscsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries, 345739213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 345839213Sgibbs u_int8_t tag_action, int readop, int sli, 345939213Sgibbs int fixed, u_int32_t length, u_int8_t *data_ptr, 346039213Sgibbs u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout) 346139213Sgibbs{ 346239213Sgibbs struct scsi_sa_rw *scsi_cmd; 346339213Sgibbs 346439213Sgibbs scsi_cmd = (struct scsi_sa_rw *)&csio->cdb_io.cdb_bytes; 346539213Sgibbs scsi_cmd->opcode = readop ? SA_READ : SA_WRITE; 346639213Sgibbs scsi_cmd->sli_fixed = 0; 346739213Sgibbs if (sli && readop) 346839213Sgibbs scsi_cmd->sli_fixed |= SAR_SLI; 346939213Sgibbs if (fixed) 347039213Sgibbs scsi_cmd->sli_fixed |= SARW_FIXED; 347139213Sgibbs scsi_ulto3b(length, scsi_cmd->length); 347239213Sgibbs scsi_cmd->control = 0; 347339213Sgibbs 347446962Smjacob cam_fill_csio(csio, retries, cbfcnp, readop ? CAM_DIR_IN : CAM_DIR_OUT, 347546962Smjacob tag_action, data_ptr, dxfer_len, sense_len, 347646962Smjacob sizeof(*scsi_cmd), timeout); 347739213Sgibbs} 347839213Sgibbs 347939213Sgibbsvoid 348039213Sgibbsscsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries, 348139213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 348239213Sgibbs u_int8_t tag_action, int immediate, int eot, 348339213Sgibbs int reten, int load, u_int8_t sense_len, 348439213Sgibbs u_int32_t timeout) 348539213Sgibbs{ 348639213Sgibbs struct scsi_load_unload *scsi_cmd; 348739213Sgibbs 348839213Sgibbs scsi_cmd = (struct scsi_load_unload *)&csio->cdb_io.cdb_bytes; 348939213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 349039213Sgibbs scsi_cmd->opcode = LOAD_UNLOAD; 349139213Sgibbs if (immediate) 349239213Sgibbs scsi_cmd->immediate = SLU_IMMED; 349339213Sgibbs if (eot) 349439213Sgibbs scsi_cmd->eot_reten_load |= SLU_EOT; 349539213Sgibbs if (reten) 349639213Sgibbs scsi_cmd->eot_reten_load |= SLU_RETEN; 349739213Sgibbs if (load) 349839213Sgibbs scsi_cmd->eot_reten_load |= SLU_LOAD; 349939213Sgibbs 350046962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 350146962Smjacob NULL, 0, sense_len, sizeof(*scsi_cmd), timeout); 350239213Sgibbs} 350339213Sgibbs 350439213Sgibbsvoid 350539213Sgibbsscsi_rewind(struct ccb_scsiio *csio, u_int32_t retries, 350639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 350739213Sgibbs u_int8_t tag_action, int immediate, u_int8_t sense_len, 350839213Sgibbs u_int32_t timeout) 350939213Sgibbs{ 351039213Sgibbs struct scsi_rewind *scsi_cmd; 351139213Sgibbs 351239213Sgibbs scsi_cmd = (struct scsi_rewind *)&csio->cdb_io.cdb_bytes; 351339213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 351439213Sgibbs scsi_cmd->opcode = REWIND; 351539213Sgibbs if (immediate) 351639213Sgibbs scsi_cmd->immediate = SREW_IMMED; 351739213Sgibbs 351846962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 351946962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 352039213Sgibbs} 352139213Sgibbs 352239213Sgibbsvoid 352339213Sgibbsscsi_space(struct ccb_scsiio *csio, u_int32_t retries, 352439213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 352539213Sgibbs u_int8_t tag_action, scsi_space_code code, 352639213Sgibbs u_int32_t count, u_int8_t sense_len, u_int32_t timeout) 352739213Sgibbs{ 352839213Sgibbs struct scsi_space *scsi_cmd; 352939213Sgibbs 353039213Sgibbs scsi_cmd = (struct scsi_space *)&csio->cdb_io.cdb_bytes; 353139213Sgibbs scsi_cmd->opcode = SPACE; 353239213Sgibbs scsi_cmd->code = code; 353339213Sgibbs scsi_ulto3b(count, scsi_cmd->count); 353439213Sgibbs scsi_cmd->control = 0; 353539213Sgibbs 353646962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 353746962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 353839213Sgibbs} 353939213Sgibbs 354039213Sgibbsvoid 354139213Sgibbsscsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries, 354239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 354339213Sgibbs u_int8_t tag_action, int immediate, int setmark, 354439213Sgibbs u_int32_t num_marks, u_int8_t sense_len, 354539213Sgibbs u_int32_t timeout) 354639213Sgibbs{ 354739213Sgibbs struct scsi_write_filemarks *scsi_cmd; 354839213Sgibbs 354939213Sgibbs scsi_cmd = (struct scsi_write_filemarks *)&csio->cdb_io.cdb_bytes; 355039213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 355139213Sgibbs scsi_cmd->opcode = WRITE_FILEMARKS; 355239213Sgibbs if (immediate) 355339213Sgibbs scsi_cmd->byte2 |= SWFMRK_IMMED; 355439213Sgibbs if (setmark) 355539213Sgibbs scsi_cmd->byte2 |= SWFMRK_WSMK; 355639213Sgibbs 355739213Sgibbs scsi_ulto3b(num_marks, scsi_cmd->num_marks); 355839213Sgibbs 355946962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 356046962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 356139213Sgibbs} 356239213Sgibbs 356339213Sgibbs/* 356439213Sgibbs * The reserve and release unit commands differ only by their opcodes. 356539213Sgibbs */ 356639213Sgibbsvoid 356739213Sgibbsscsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries, 356839213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 356939213Sgibbs u_int8_t tag_action, int third_party, 357039213Sgibbs int third_party_id, u_int8_t sense_len, 357139213Sgibbs u_int32_t timeout, int reserve) 357239213Sgibbs{ 357339213Sgibbs struct scsi_reserve_release_unit *scsi_cmd; 357439213Sgibbs 357539213Sgibbs scsi_cmd = (struct scsi_reserve_release_unit *)&csio->cdb_io.cdb_bytes; 357639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 357739213Sgibbs 357839213Sgibbs if (reserve) 357939213Sgibbs scsi_cmd->opcode = RESERVE_UNIT; 358039213Sgibbs else 358139213Sgibbs scsi_cmd->opcode = RELEASE_UNIT; 358239213Sgibbs 358339213Sgibbs if (third_party) { 358439213Sgibbs scsi_cmd->lun_thirdparty |= SRRU_3RD_PARTY; 358539213Sgibbs scsi_cmd->lun_thirdparty |= 358639213Sgibbs ((third_party_id << SRRU_3RD_SHAMT) & SRRU_3RD_MASK); 358739213Sgibbs } 358839213Sgibbs 358946962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 359046962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 359139213Sgibbs} 359239213Sgibbs 359339213Sgibbsvoid 359439213Sgibbsscsi_erase(struct ccb_scsiio *csio, u_int32_t retries, 359539213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 359639213Sgibbs u_int8_t tag_action, int immediate, int long_erase, 359739213Sgibbs u_int8_t sense_len, u_int32_t timeout) 359839213Sgibbs{ 359939213Sgibbs struct scsi_erase *scsi_cmd; 360039213Sgibbs 360139213Sgibbs scsi_cmd = (struct scsi_erase *)&csio->cdb_io.cdb_bytes; 360239213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 360339213Sgibbs 360439213Sgibbs scsi_cmd->opcode = ERASE; 360539213Sgibbs 360639213Sgibbs if (immediate) 360739213Sgibbs scsi_cmd->lun_imm_long |= SE_IMMED; 360839213Sgibbs 360939213Sgibbs if (long_erase) 361039213Sgibbs scsi_cmd->lun_imm_long |= SE_LONG; 361139213Sgibbs 361246962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 361346962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 361439213Sgibbs} 361541918Smjacob 361641918Smjacob/* 361741918Smjacob * Read Tape Position command. 361841918Smjacob */ 361941918Smjacobvoid 362041918Smjacobscsi_read_position(struct ccb_scsiio *csio, u_int32_t retries, 362141918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 362241918Smjacob u_int8_t tag_action, int hardsoft, 362341918Smjacob struct scsi_tape_position_data *sbp, 362441918Smjacob u_int8_t sense_len, u_int32_t timeout) 362541918Smjacob{ 362641918Smjacob struct scsi_tape_read_position *scmd; 362741918Smjacob 362841918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 362941918Smjacob (u_int8_t *)sbp, sizeof (*sbp), sense_len, sizeof(*scmd), timeout); 363041918Smjacob scmd = (struct scsi_tape_read_position *)&csio->cdb_io.cdb_bytes; 363141918Smjacob bzero(scmd, sizeof(*scmd)); 363241918Smjacob scmd->opcode = READ_POSITION; 363341918Smjacob scmd->byte1 = hardsoft; 363441918Smjacob} 363541918Smjacob 363641918Smjacob/* 363741918Smjacob * Set Tape Position command. 363841918Smjacob */ 363941918Smjacobvoid 364041918Smjacobscsi_set_position(struct ccb_scsiio *csio, u_int32_t retries, 364141918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 364241918Smjacob u_int8_t tag_action, int hardsoft, u_int32_t blkno, 364341918Smjacob u_int8_t sense_len, u_int32_t timeout) 364441918Smjacob{ 364541918Smjacob struct scsi_tape_locate *scmd; 364641918Smjacob 364741918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 364841918Smjacob (u_int8_t *)NULL, 0, sense_len, sizeof(*scmd), timeout); 364941918Smjacob scmd = (struct scsi_tape_locate *)&csio->cdb_io.cdb_bytes; 365041918Smjacob bzero(scmd, sizeof(*scmd)); 365141918Smjacob scmd->opcode = LOCATE; 365241918Smjacob if (hardsoft) 365341918Smjacob scmd->byte1 |= SA_SPOS_BT; 365441918Smjacob scsi_ulto4b(blkno, scmd->blkaddr); 365541918Smjacob} 3656