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$"); 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 105249132Smavstatic MALLOC_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 176251386Ssmh#define SA_QUIRK_BIT_STRING \ 177251386Ssmh "\020" \ 178251386Ssmh "\001NOCOMP" \ 179251386Ssmh "\002FIXED" \ 180251386Ssmh "\003VARIABLE" \ 181251386Ssmh "\0042FM" \ 182251386Ssmh "\0051FM" \ 183251386Ssmh "\006NODREAD" \ 184251386Ssmh "\007NO_MODESEL" \ 185251386Ssmh "\010NO_CPAGE" 186251386Ssmh 187191304Sed#define SAMODE(z) (dev2unit(z) & 0x3) 188191304Sed#define SADENSITY(z) ((dev2unit(z) >> 2) & 0x3) 189191304Sed#define SA_IS_CTRL(z) (dev2unit(z) & (1 << 4)) 19053283Smjacob 19153259Smjacob#define SA_NOT_CTLDEV 0 19253259Smjacob#define SA_CTLDEV 1 19353259Smjacob 19453259Smjacob#define SA_ATYPE_R 0 19553259Smjacob#define SA_ATYPE_NR 1 19653259Smjacob#define SA_ATYPE_ER 2 19753259Smjacob 198191304Sed#define SAMINOR(ctl, mode, access) \ 199191304Sed ((ctl << 4) | (mode << 2) | (access & 0x3)) 20053259Smjacob 20153259Smjacob#define SA_NUM_MODES 4 20253259Smjacobstruct sa_devs { 203130585Sphk struct cdev *ctl_dev; 20453259Smjacob struct sa_mode_devs { 205130585Sphk struct cdev *r_dev; 206130585Sphk struct cdev *nr_dev; 207130585Sphk struct cdev *er_dev; 20853259Smjacob } mode_devs[SA_NUM_MODES]; 20953259Smjacob}; 21053259Smjacob 21139213Sgibbsstruct sa_softc { 21239213Sgibbs sa_state state; 21339213Sgibbs sa_flags flags; 21439213Sgibbs sa_quirks quirks; 215255000Sken u_int si_flags; 21659249Sphk struct bio_queue_head bio_queue; 21746962Smjacob int queue_count; 218112006Sphk struct devstat *device_stats; 21953259Smjacob struct sa_devs devs; 22039213Sgibbs int blk_gran; 22139213Sgibbs int blk_mask; 22239213Sgibbs int blk_shift; 22339213Sgibbs u_int32_t max_blk; 22439213Sgibbs u_int32_t min_blk; 225255000Sken u_int32_t maxio; 22641674Smjacob u_int32_t comp_algorithm; 22741674Smjacob u_int32_t saved_comp_algorithm; 22839213Sgibbs u_int32_t media_blksize; 22941906Smjacob u_int32_t last_media_blksize; 23039213Sgibbs u_int32_t media_numblks; 23141674Smjacob u_int8_t media_density; 23239213Sgibbs u_int8_t speed; 23341674Smjacob u_int8_t scsi_rev; 23443636Smjacob u_int8_t dsreg; /* mtio mt_dsreg, redux */ 23539213Sgibbs int buffer_mode; 23639213Sgibbs int filemarks; 23739213Sgibbs union ccb saved_ccb; 23871268Smjacob int last_resid_was_io; 23946962Smjacob 24041948Smjacob /* 24143636Smjacob * Relative to BOT Location. 24243636Smjacob */ 24343636Smjacob daddr_t fileno; 24443636Smjacob daddr_t blkno; 24543636Smjacob 24643636Smjacob /* 24741948Smjacob * Latched Error Info 24841948Smjacob */ 24942009Smjacob struct { 25042009Smjacob struct scsi_sense_data _last_io_sense; 251226067Sken u_int64_t _last_io_resid; 25242009Smjacob u_int8_t _last_io_cdb[CAM_MAX_CDBLEN]; 25342009Smjacob struct scsi_sense_data _last_ctl_sense; 254226067Sken u_int64_t _last_ctl_resid; 25542009Smjacob u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN]; 25642009Smjacob#define last_io_sense errinfo._last_io_sense 25742009Smjacob#define last_io_resid errinfo._last_io_resid 25842009Smjacob#define last_io_cdb errinfo._last_io_cdb 25942009Smjacob#define last_ctl_sense errinfo._last_ctl_sense 26042009Smjacob#define last_ctl_resid errinfo._last_ctl_resid 26142009Smjacob#define last_ctl_cdb errinfo._last_ctl_cdb 26242009Smjacob } errinfo; 26343636Smjacob /* 26443636Smjacob * Misc other flags/state 26543636Smjacob */ 26643636Smjacob u_int32_t 267154360Smjacob : 29, 268154360Smjacob open_rdonly : 1, /* open read-only */ 269154360Smjacob open_pending_mount : 1, /* open pending mount */ 270154360Smjacob ctrl_mode : 1; /* control device open */ 27139213Sgibbs}; 27239213Sgibbs 27339213Sgibbsstruct sa_quirk_entry { 27442563Smjacob struct scsi_inquiry_pattern inq_pat; /* matching pattern */ 27542563Smjacob sa_quirks quirks; /* specific quirk type */ 27642563Smjacob u_int32_t prefblk; /* preferred blocksize when in fixed mode */ 27739213Sgibbs}; 27839213Sgibbs 27939213Sgibbsstatic struct sa_quirk_entry sa_quirk_table[] = 28039213Sgibbs{ 28139213Sgibbs { 28260235Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "OnStream", 28360235Smjacob "ADR*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_NODREAD | 28460235Smjacob SA_QUIRK_1FM|SA_QUIRK_NO_MODESEL, 32768 28560235Smjacob }, 28660235Smjacob { 28739213Sgibbs { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28877810Snon "Python 06408*", "*"}, SA_QUIRK_NODREAD, 0 28977581Snon }, 29077581Snon { 29177581Snon { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 29256981Smjacob "Python 25601*", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_NODREAD, 0 29341351Sjoerg }, 29441351Sjoerg { 29542130Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 29656981Smjacob "Python*", "*"}, SA_QUIRK_NODREAD, 0 29756981Smjacob }, 29856981Smjacob { 29956981Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 30043636Smjacob "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 30142130Smjacob }, 30242130Smjacob { 30342563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 30468500Smjacob "VIPER 2525 25462", "-011"}, 30568500Smjacob SA_QUIRK_NOCOMP|SA_QUIRK_1FM|SA_QUIRK_NODREAD, 0 30668500Smjacob }, 30768500Smjacob { 30868500Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 30946962Smjacob "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 31042563Smjacob }, 31171082Smjacob#if 0 31242563Smjacob { 31342533Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 31471082Smjacob "C15*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_NO_CPAGE, 0, 31571082Smjacob }, 31671082Smjacob#endif 317107943Strhodes { 318107943Strhodes { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 319107943Strhodes "C56*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 320107943Strhodes }, 32171082Smjacob { 32271082Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 32346962Smjacob "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 32446962Smjacob }, 32546962Smjacob { 32646962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 32744354Smjacob "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 32842533Smjacob }, 32942533Smjacob { 33042716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 33142716Smjacob "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 33242716Smjacob }, 33342716Smjacob { 33442716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", 33542716Smjacob "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 33642716Smjacob }, 33742716Smjacob { 33842716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA", 33942716Smjacob "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 34042716Smjacob }, 34151744Smjacob { /* jreynold@primenet.com */ 34251744Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 34351744Smjacob "STT8000N*", "*"}, SA_QUIRK_1FM, 0 34451744Smjacob }, 34551875Smjacob { /* mike@sentex.net */ 34651875Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 34751875Smjacob "STT20000*", "*"}, SA_QUIRK_1FM, 0 34851875Smjacob }, 34942716Smjacob { 350231321Seadler { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "SEAGATE", 351231321Seadler "DAT 06241-XXX", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 352231321Seadler }, 353231321Seadler { 35441351Sjoerg { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 35543636Smjacob " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 35642563Smjacob }, 35742563Smjacob { 35842563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 35947519Smjacob " TDC 3800", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 36047519Smjacob }, 36147519Smjacob { 36247519Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 36348192Smjacob " TDC 4100", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 36448192Smjacob }, 36548192Smjacob { 36648192Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 36743636Smjacob " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 36842563Smjacob }, 36942563Smjacob { 37046962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 37146962Smjacob " SLR*", "*"}, SA_QUIRK_1FM, 0 37246962Smjacob }, 37346962Smjacob { 37442563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 37543636Smjacob "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 37645752Smjacob }, 37745752Smjacob { 37845752Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 37945752Smjacob "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 38039213Sgibbs } 38139213Sgibbs}; 38239213Sgibbs 38339213Sgibbsstatic d_open_t saopen; 38439213Sgibbsstatic d_close_t saclose; 38539213Sgibbsstatic d_strategy_t sastrategy; 38639213Sgibbsstatic d_ioctl_t saioctl; 38739213Sgibbsstatic periph_init_t sainit; 38839213Sgibbsstatic periph_ctor_t saregister; 38940603Skenstatic periph_oninv_t saoninvalidate; 39039213Sgibbsstatic periph_dtor_t sacleanup; 39139213Sgibbsstatic periph_start_t sastart; 39239213Sgibbsstatic void saasync(void *callback_arg, u_int32_t code, 39339213Sgibbs struct cam_path *path, void *arg); 39439213Sgibbsstatic void sadone(struct cam_periph *periph, 39539213Sgibbs union ccb *start_ccb); 39639213Sgibbsstatic int saerror(union ccb *ccb, u_int32_t cam_flags, 39739213Sgibbs u_int32_t sense_flags); 39868114Smjacobstatic int samarkswanted(struct cam_periph *); 39939213Sgibbsstatic int sacheckeod(struct cam_periph *periph); 40039213Sgibbsstatic int sagetparams(struct cam_periph *periph, 40139213Sgibbs sa_params params_to_get, 40239213Sgibbs u_int32_t *blocksize, u_int8_t *density, 40339213Sgibbs u_int32_t *numblocks, int *buff_mode, 40439213Sgibbs u_int8_t *write_protect, u_int8_t *speed, 40539213Sgibbs int *comp_supported, int *comp_enabled, 40639213Sgibbs u_int32_t *comp_algorithm, 40746962Smjacob sa_comp_t *comp_page); 40839213Sgibbsstatic int sasetparams(struct cam_periph *periph, 40939213Sgibbs sa_params params_to_set, 41039213Sgibbs u_int32_t blocksize, u_int8_t density, 41142563Smjacob u_int32_t comp_algorithm, 41242563Smjacob u_int32_t sense_flags); 41339213Sgibbsstatic void saprevent(struct cam_periph *periph, int action); 41439213Sgibbsstatic int sarewind(struct cam_periph *periph); 41539213Sgibbsstatic int saspace(struct cam_periph *periph, int count, 41639213Sgibbs scsi_space_code code); 417130585Sphkstatic int samount(struct cam_periph *, int, struct cdev *); 41839213Sgibbsstatic int saretension(struct cam_periph *periph); 41939213Sgibbsstatic int sareservereleaseunit(struct cam_periph *periph, 42039213Sgibbs int reserve); 42139213Sgibbsstatic int saloadunload(struct cam_periph *periph, int load); 42239213Sgibbsstatic int saerase(struct cam_periph *periph, int longerase); 42339213Sgibbsstatic int sawritefilemarks(struct cam_periph *periph, 42439213Sgibbs int nmarks, int setmarks); 42541918Smjacobstatic int sardpos(struct cam_periph *periph, int, u_int32_t *); 42641918Smjacobstatic int sasetpos(struct cam_periph *periph, int, u_int32_t *); 42739213Sgibbs 42841918Smjacob 42939213Sgibbsstatic struct periph_driver sadriver = 43039213Sgibbs{ 43139213Sgibbs sainit, "sa", 43239213Sgibbs TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0 43339213Sgibbs}; 43439213Sgibbs 43572119SpeterPERIPHDRIVER_DECLARE(sa, sadriver); 43639213Sgibbs 43739213Sgibbs/* For 2.2-stable support */ 43839213Sgibbs#ifndef D_TAPE 43939213Sgibbs#define D_TAPE 0 44039213Sgibbs#endif 44139213Sgibbs 44239213Sgibbs 44347625Sphkstatic struct cdevsw sa_cdevsw = { 444126080Sphk .d_version = D_VERSION, 445111815Sphk .d_open = saopen, 446111815Sphk .d_close = saclose, 447111815Sphk .d_read = physread, 448111815Sphk .d_write = physwrite, 449111815Sphk .d_ioctl = saioctl, 450111815Sphk .d_strategy = sastrategy, 451111815Sphk .d_name = "sa", 452255000Sken .d_flags = D_TAPE, 45339213Sgibbs}; 45439213Sgibbs 45539213Sgibbsstatic int 456130585Sphksaopen(struct cdev *dev, int flags, int fmt, struct thread *td) 45739213Sgibbs{ 45839213Sgibbs struct cam_periph *periph; 45939213Sgibbs struct sa_softc *softc; 46039213Sgibbs int error; 46139213Sgibbs 462101940Snjl periph = (struct cam_periph *)dev->si_drv1; 463168752Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 464168752Sscottl return (ENXIO); 46553259Smjacob } 466168752Sscottl 467168752Sscottl cam_periph_lock(periph); 468168752Sscottl 46939213Sgibbs softc = (struct sa_softc *)periph->softc; 47039213Sgibbs 47146962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 472191304Sed ("saopen(%s): softc=0x%x\n", devtoname(dev), softc->flags)); 47339213Sgibbs 47443636Smjacob if (SA_IS_CTRL(dev)) { 47543636Smjacob softc->ctrl_mode = 1; 47653259Smjacob cam_periph_unlock(periph); 47743636Smjacob return (0); 47843636Smjacob } 47943636Smjacob 480168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 481168752Sscottl cam_periph_unlock(periph); 482168752Sscottl cam_periph_release(periph); 483168752Sscottl return (error); 484168752Sscottl } 485168752Sscottl 48653259Smjacob if (softc->flags & SA_FLAG_OPEN) { 48753259Smjacob error = EBUSY; 48853259Smjacob } else if (softc->flags & SA_FLAG_INVALID) { 48953259Smjacob error = ENXIO; 49053259Smjacob } else { 49153259Smjacob /* 492154360Smjacob * Preserve whether this is a read_only open. 493154360Smjacob */ 494154360Smjacob softc->open_rdonly = (flags & O_RDWR) == O_RDONLY; 495154360Smjacob 496154360Smjacob /* 49753259Smjacob * The function samount ensures media is loaded and ready. 49853259Smjacob * It also does a device RESERVE if the tape isn't yet mounted. 499154360Smjacob * 500154360Smjacob * If the mount fails and this was a non-blocking open, 501154360Smjacob * make this a 'open_pending_mount' action. 50253259Smjacob */ 50353259Smjacob error = samount(periph, flags, dev); 504154360Smjacob if (error && (flags & O_NONBLOCK)) { 505154360Smjacob softc->flags |= SA_FLAG_OPEN; 506154360Smjacob softc->open_pending_mount = 1; 507168752Sscottl cam_periph_unhold(periph); 508154360Smjacob cam_periph_unlock(periph); 509154360Smjacob return (0); 510154360Smjacob } 51139213Sgibbs } 51239213Sgibbs 51353259Smjacob if (error) { 514168752Sscottl cam_periph_unhold(periph); 515168752Sscottl cam_periph_unlock(periph); 51653259Smjacob cam_periph_release(periph); 517168752Sscottl return (error); 51839213Sgibbs } 519168752Sscottl 520168752Sscottl saprevent(periph, PR_PREVENT); 521168752Sscottl softc->flags |= SA_FLAG_OPEN; 522168752Sscottl 523168752Sscottl cam_periph_unhold(periph); 52439213Sgibbs cam_periph_unlock(periph); 52539213Sgibbs return (error); 52639213Sgibbs} 52739213Sgibbs 52839213Sgibbsstatic int 529130585Sphksaclose(struct cdev *dev, int flag, int fmt, struct thread *td) 53039213Sgibbs{ 53139213Sgibbs struct cam_periph *periph; 53239213Sgibbs struct sa_softc *softc; 533191304Sed int mode, error, writing, tmp; 53442009Smjacob int closedbits = SA_FLAG_OPEN; 53539213Sgibbs 53639213Sgibbs mode = SAMODE(dev); 537101940Snjl periph = (struct cam_periph *)dev->si_drv1; 53839213Sgibbs if (periph == NULL) 53939213Sgibbs return (ENXIO); 54039213Sgibbs 541168752Sscottl cam_periph_lock(periph); 542168752Sscottl 54339213Sgibbs softc = (struct sa_softc *)periph->softc; 54439213Sgibbs 54546962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 546191304Sed ("saclose(%s): softc=0x%x\n", devtoname(dev), softc->flags)); 54746962Smjacob 54846962Smjacob 549154360Smjacob softc->open_rdonly = 0; 55043636Smjacob if (SA_IS_CTRL(dev)) { 55143636Smjacob softc->ctrl_mode = 0; 552168752Sscottl cam_periph_unlock(periph); 55353259Smjacob cam_periph_release(periph); 55443636Smjacob return (0); 55543636Smjacob } 55643636Smjacob 557154360Smjacob if (softc->open_pending_mount) { 558154360Smjacob softc->flags &= ~SA_FLAG_OPEN; 559154360Smjacob softc->open_pending_mount = 0; 560168752Sscottl cam_periph_unlock(periph); 561154360Smjacob cam_periph_release(periph); 562154360Smjacob return (0); 563154360Smjacob } 564154360Smjacob 565168752Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 566168752Sscottl cam_periph_unlock(periph); 567168752Sscottl return (error); 568168752Sscottl } 569168752Sscottl 57041906Smjacob /* 57146962Smjacob * Were we writing the tape? 57241906Smjacob */ 57346962Smjacob writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0; 57446962Smjacob 57546962Smjacob /* 57646962Smjacob * See whether or not we need to write filemarks. If this 57746962Smjacob * fails, we probably have to assume we've lost tape 57846962Smjacob * position. 57946962Smjacob */ 58041906Smjacob error = sacheckeod(periph); 58141906Smjacob if (error) { 582164906Smjacob xpt_print(periph->path, 583164906Smjacob "failed to write terminating filemark(s)\n"); 58446962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 58541906Smjacob } 58639213Sgibbs 58741906Smjacob /* 58841906Smjacob * Whatever we end up doing, allow users to eject tapes from here on. 58941906Smjacob */ 59039213Sgibbs saprevent(periph, PR_ALLOW); 59139213Sgibbs 59241906Smjacob /* 59341906Smjacob * Decide how to end... 59441906Smjacob */ 59553522Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 59653522Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 59753522Smjacob } else switch (mode) { 59839213Sgibbs case SA_MODE_OFFLINE: 59946962Smjacob /* 60046962Smjacob * An 'offline' close is an unconditional release of 60146962Smjacob * frozen && mount conditions, irrespective of whether 60246962Smjacob * these operations succeeded. The reason for this is 60346962Smjacob * to allow at least some kind of programmatic way 60446962Smjacob * around our state getting all fouled up. If somebody 60546962Smjacob * issues an 'offline' command, that will be allowed 60646962Smjacob * to clear state. 60746962Smjacob */ 60846962Smjacob (void) sarewind(periph); 60946962Smjacob (void) saloadunload(periph, FALSE); 61046962Smjacob closedbits |= SA_FLAG_TAPE_MOUNTED|SA_FLAG_TAPE_FROZEN; 61139213Sgibbs break; 61241906Smjacob case SA_MODE_REWIND: 61346962Smjacob /* 61446962Smjacob * If the rewind fails, return an error- if anyone cares, 61546962Smjacob * but not overwriting any previous error. 61646962Smjacob * 61746962Smjacob * We don't clear the notion of mounted here, but we do 61846962Smjacob * clear the notion of frozen if we successfully rewound. 61946962Smjacob */ 62046962Smjacob tmp = sarewind(periph); 62146962Smjacob if (tmp) { 62246962Smjacob if (error != 0) 62346962Smjacob error = tmp; 62446962Smjacob } else { 62546962Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 62646962Smjacob } 62741906Smjacob break; 62839213Sgibbs case SA_MODE_NOREWIND: 62941906Smjacob /* 63041906Smjacob * If we're not rewinding/unloading the tape, find out 63141906Smjacob * whether we need to back up over one of two filemarks 63241906Smjacob * we wrote (if we wrote two filemarks) so that appends 63341906Smjacob * from this point on will be sane. 63441906Smjacob */ 63546962Smjacob if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) { 63646962Smjacob tmp = saspace(periph, -1, SS_FILEMARKS); 63746962Smjacob if (tmp) { 638164906Smjacob xpt_print(periph->path, "unable to backspace " 639164906Smjacob "over one of double filemarks at end of " 640164906Smjacob "tape\n"); 641164906Smjacob xpt_print(periph->path, "it is possible that " 642164906Smjacob "this device needs a SA_QUIRK_1FM quirk set" 643164906Smjacob "for it\n"); 64446962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 64541906Smjacob } 64641906Smjacob } 64739213Sgibbs break; 64846962Smjacob default: 649164906Smjacob xpt_print(periph->path, "unknown mode 0x%x in saclose\n", mode); 65046962Smjacob /* NOTREACHED */ 65146962Smjacob break; 65239213Sgibbs } 65339213Sgibbs 65441906Smjacob /* 65541948Smjacob * We wish to note here that there are no more filemarks to be written. 65641906Smjacob */ 65741906Smjacob softc->filemarks = 0; 65841948Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 65941906Smjacob 66041906Smjacob /* 66141906Smjacob * And we are no longer open for business. 66241906Smjacob */ 66342009Smjacob softc->flags &= ~closedbits; 66446962Smjacob 66546962Smjacob /* 66646962Smjacob * Inform users if tape state if frozen.... 66746962Smjacob */ 66846962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 669164906Smjacob xpt_print(periph->path, "tape is now frozen- use an OFFLINE, " 670164906Smjacob "REWIND or MTEOM command to clear this state.\n"); 67146962Smjacob } 67239213Sgibbs 67353259Smjacob /* release the device if it is no longer mounted */ 67453259Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) 67553259Smjacob sareservereleaseunit(periph, FALSE); 67639213Sgibbs 677168752Sscottl cam_periph_unhold(periph); 67839213Sgibbs cam_periph_unlock(periph); 67939213Sgibbs cam_periph_release(periph); 68039213Sgibbs 68146962Smjacob return (error); 68239213Sgibbs} 68339213Sgibbs 68439213Sgibbs/* 68539213Sgibbs * Actually translate the requested transfer into one the physical driver 68639213Sgibbs * can understand. The transfer is described by a buf and will include 68739213Sgibbs * only one physical transfer. 68839213Sgibbs */ 68939213Sgibbsstatic void 69059249Sphksastrategy(struct bio *bp) 69139213Sgibbs{ 69239213Sgibbs struct cam_periph *periph; 69339213Sgibbs struct sa_softc *softc; 69439213Sgibbs 69576362Sphk bp->bio_resid = bp->bio_bcount; 69659249Sphk if (SA_IS_CTRL(bp->bio_dev)) { 69776362Sphk biofinish(bp, NULL, EINVAL); 69876362Sphk return; 69943636Smjacob } 700101940Snjl periph = (struct cam_periph *)bp->bio_dev->si_drv1; 70139213Sgibbs if (periph == NULL) { 70276362Sphk biofinish(bp, NULL, ENXIO); 70376362Sphk return; 70439213Sgibbs } 705168752Sscottl cam_periph_lock(periph); 706168752Sscottl 70739213Sgibbs softc = (struct sa_softc *)periph->softc; 70839213Sgibbs 70940603Sken if (softc->flags & SA_FLAG_INVALID) { 710168752Sscottl cam_periph_unlock(periph); 71176362Sphk biofinish(bp, NULL, ENXIO); 71276362Sphk return; 71340603Sken } 71440603Sken 71546962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 716168752Sscottl cam_periph_unlock(periph); 71776362Sphk biofinish(bp, NULL, EPERM); 71876362Sphk return; 71946962Smjacob } 72046962Smjacob 721154360Smjacob /* 722154360Smjacob * This should actually never occur as the write(2) 723154360Smjacob * system call traps attempts to write to a read-only 724154360Smjacob * file descriptor. 725154360Smjacob */ 726154360Smjacob if (bp->bio_cmd == BIO_WRITE && softc->open_rdonly) { 727168752Sscottl cam_periph_unlock(periph); 728154360Smjacob biofinish(bp, NULL, EBADF); 729154360Smjacob return; 730154360Smjacob } 731154360Smjacob 732154360Smjacob if (softc->open_pending_mount) { 733154360Smjacob int error = samount(periph, 0, bp->bio_dev); 734154360Smjacob if (error) { 735168752Sscottl cam_periph_unlock(periph); 736154360Smjacob biofinish(bp, NULL, ENXIO); 737154360Smjacob return; 738154360Smjacob } 739154360Smjacob saprevent(periph, PR_PREVENT); 740154360Smjacob softc->open_pending_mount = 0; 741154360Smjacob } 742154360Smjacob 743154360Smjacob 74439213Sgibbs /* 745154360Smjacob * If it's a null transfer, return immediately 74639213Sgibbs */ 74776362Sphk if (bp->bio_bcount == 0) { 748168752Sscottl cam_periph_unlock(periph); 74976362Sphk biodone(bp); 75076362Sphk return; 75176362Sphk } 75239213Sgibbs 75339213Sgibbs /* valid request? */ 75439213Sgibbs if (softc->flags & SA_FLAG_FIXED) { 75539213Sgibbs /* 75639213Sgibbs * Fixed block device. The byte count must 75739213Sgibbs * be a multiple of our block size. 75839213Sgibbs */ 75942716Smjacob if (((softc->blk_mask != ~0) && 76059249Sphk ((bp->bio_bcount & softc->blk_mask) != 0)) || 76142716Smjacob ((softc->blk_mask == ~0) && 76259249Sphk ((bp->bio_bcount % softc->min_blk) != 0))) { 763164906Smjacob xpt_print(periph->path, "Invalid request. Fixed block " 764164906Smjacob "device requests must be a multiple of %d bytes\n", 765164906Smjacob softc->min_blk); 766168752Sscottl cam_periph_unlock(periph); 76776362Sphk biofinish(bp, NULL, EINVAL); 76876362Sphk return; 76939213Sgibbs } 77059249Sphk } else if ((bp->bio_bcount > softc->max_blk) || 77159249Sphk (bp->bio_bcount < softc->min_blk) || 77259249Sphk (bp->bio_bcount & softc->blk_mask) != 0) { 77339213Sgibbs 77439213Sgibbs xpt_print_path(periph->path); 775164906Smjacob printf("Invalid request. Variable block " 776164906Smjacob "device requests must be "); 77739213Sgibbs if (softc->blk_mask != 0) { 77842716Smjacob printf("a multiple of %d ", (0x1 << softc->blk_gran)); 77939213Sgibbs } 78042716Smjacob printf("between %d and %d bytes\n", softc->min_blk, 78142716Smjacob softc->max_blk); 782168752Sscottl cam_periph_unlock(periph); 78376362Sphk biofinish(bp, NULL, EINVAL); 78476362Sphk return; 78539213Sgibbs } 78639213Sgibbs 78739213Sgibbs /* 78842716Smjacob * Place it at the end of the queue. 78939213Sgibbs */ 79059249Sphk bioq_insert_tail(&softc->bio_queue, bp); 79146962Smjacob softc->queue_count++; 792115660Smjacob#if 0 793115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 794115660Smjacob ("sastrategy: queuing a %ld %s byte %s\n", bp->bio_bcount, 795115660Smjacob (softc->flags & SA_FLAG_FIXED)? "fixed" : "variable", 796115660Smjacob (bp->bio_cmd == BIO_READ)? "read" : "write")); 797115660Smjacob#endif 798115660Smjacob if (softc->queue_count > 1) { 799115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 800115660Smjacob ("sastrategy: queue count now %d\n", softc->queue_count)); 801115660Smjacob } 80239213Sgibbs 80339213Sgibbs /* 80439213Sgibbs * Schedule ourselves for performing the work. 80539213Sgibbs */ 806198382Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 807168752Sscottl cam_periph_unlock(periph); 80839213Sgibbs 80939213Sgibbs return; 81039213Sgibbs} 81139213Sgibbs 812154360Smjacob 813154360Smjacob#define PENDING_MOUNT_CHECK(softc, periph, dev) \ 814154360Smjacob if (softc->open_pending_mount) { \ 815154360Smjacob error = samount(periph, 0, dev); \ 816154360Smjacob if (error) { \ 817154360Smjacob break; \ 818154360Smjacob } \ 819154360Smjacob saprevent(periph, PR_PREVENT); \ 820154360Smjacob softc->open_pending_mount = 0; \ 821154360Smjacob } 822154360Smjacob 82339213Sgibbsstatic int 824130585Sphksaioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 82539213Sgibbs{ 82639213Sgibbs struct cam_periph *periph; 82739213Sgibbs struct sa_softc *softc; 82848520Speter scsi_space_code spaceop; 82943636Smjacob int didlockperiph = 0; 83039213Sgibbs int mode; 83153259Smjacob int error = 0; 83239213Sgibbs 83339213Sgibbs mode = SAMODE(dev); 83448520Speter error = 0; /* shut up gcc */ 83548520Speter spaceop = 0; /* shut up gcc */ 83639213Sgibbs 837101940Snjl periph = (struct cam_periph *)dev->si_drv1; 83839213Sgibbs if (periph == NULL) 83939213Sgibbs return (ENXIO); 84039213Sgibbs 841168752Sscottl cam_periph_lock(periph); 84239213Sgibbs softc = (struct sa_softc *)periph->softc; 84339213Sgibbs 84439213Sgibbs /* 84543636Smjacob * Check for control mode accesses. We allow MTIOCGET and 84643636Smjacob * MTIOCERRSTAT (but need to be the only one open in order 84743636Smjacob * to clear latched status), and MTSETBSIZE, MTSETDNSTY 84843636Smjacob * and MTCOMP (but need to be the only one accessing this 84943636Smjacob * device to run those). 85043636Smjacob */ 85143636Smjacob 85243636Smjacob if (SA_IS_CTRL(dev)) { 85343636Smjacob switch (cmd) { 85446962Smjacob case MTIOCGETEOTMODEL: 85543636Smjacob case MTIOCGET: 85643636Smjacob break; 85743636Smjacob case MTIOCERRSTAT: 85843636Smjacob /* 85943636Smjacob * If the periph isn't already locked, lock it 86043636Smjacob * so our MTIOCERRSTAT can reset latched error stats. 86143636Smjacob * 86243636Smjacob * If the periph is already locked, skip it because 86343636Smjacob * we're just getting status and it'll be up to the 86443636Smjacob * other thread that has this device open to do 86543636Smjacob * an MTIOCERRSTAT that would clear latched status. 86643636Smjacob */ 86743636Smjacob if ((periph->flags & CAM_PERIPH_LOCKED) == 0) { 868168752Sscottl error = cam_periph_hold(periph, PRIBIO|PCATCH); 869226067Sken if (error != 0) { 870226067Sken cam_periph_unlock(periph); 87143636Smjacob return (error); 872226067Sken } 87343636Smjacob didlockperiph = 1; 87443636Smjacob } 87543636Smjacob break; 87643636Smjacob 877145050Smjacob case MTIOCTOP: 878145050Smjacob { 879145050Smjacob struct mtop *mt = (struct mtop *) arg; 880145050Smjacob 881145050Smjacob /* 882145050Smjacob * Check to make sure it's an OP we can perform 883145050Smjacob * with no media inserted. 884145050Smjacob */ 885145050Smjacob switch (mt->mt_op) { 886145050Smjacob case MTSETBSIZ: 887145050Smjacob case MTSETDNSTY: 888145050Smjacob case MTCOMP: 889145050Smjacob mt = NULL; 890145050Smjacob /* FALLTHROUGH */ 891145050Smjacob default: 892145050Smjacob break; 893145050Smjacob } 894145050Smjacob if (mt != NULL) { 895145050Smjacob break; 896145050Smjacob } 897145050Smjacob /* FALLTHROUGH */ 898145050Smjacob } 89946962Smjacob case MTIOCSETEOTMODEL: 90043636Smjacob /* 90143636Smjacob * We need to acquire the peripheral here rather 90243636Smjacob * than at open time because we are sharing writable 90343636Smjacob * access to data structures. 90443636Smjacob */ 905168752Sscottl error = cam_periph_hold(periph, PRIBIO|PCATCH); 906226067Sken if (error != 0) { 907226067Sken cam_periph_unlock(periph); 90843636Smjacob return (error); 909226067Sken } 91043636Smjacob didlockperiph = 1; 91143636Smjacob break; 91243636Smjacob 91343636Smjacob default: 914226067Sken cam_periph_unlock(periph); 91543636Smjacob return (EINVAL); 91643636Smjacob } 91743636Smjacob } 91843636Smjacob 91943636Smjacob /* 92039213Sgibbs * Find the device that the user is talking about 92139213Sgibbs */ 92239213Sgibbs switch (cmd) { 92339213Sgibbs case MTIOCGET: 92439213Sgibbs { 92539213Sgibbs struct mtget *g = (struct mtget *)arg; 92639213Sgibbs 92753259Smjacob /* 92853259Smjacob * If this isn't the control mode device, actually go out 92953259Smjacob * and ask the drive again what it's set to. 93053259Smjacob */ 931154360Smjacob if (!SA_IS_CTRL(dev) && !softc->open_pending_mount) { 93253259Smjacob u_int8_t write_protect; 93353259Smjacob int comp_enabled, comp_supported; 93453259Smjacob error = sagetparams(periph, SA_PARAM_ALL, 93553259Smjacob &softc->media_blksize, &softc->media_density, 93653259Smjacob &softc->media_numblks, &softc->buffer_mode, 93753259Smjacob &write_protect, &softc->speed, &comp_supported, 93853259Smjacob &comp_enabled, &softc->comp_algorithm, NULL); 93953259Smjacob if (error) 94053259Smjacob break; 94153259Smjacob if (write_protect) 94253259Smjacob softc->flags |= SA_FLAG_TAPE_WP; 94353259Smjacob else 94453259Smjacob softc->flags &= ~SA_FLAG_TAPE_WP; 94553259Smjacob softc->flags &= ~(SA_FLAG_COMP_SUPP| 94653259Smjacob SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP); 94753259Smjacob if (comp_supported) { 94853259Smjacob if (softc->saved_comp_algorithm == 0) 94953259Smjacob softc->saved_comp_algorithm = 95053259Smjacob softc->comp_algorithm; 95153259Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 95253259Smjacob if (comp_enabled) 95353259Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 95453259Smjacob } else 95553259Smjacob softc->flags |= SA_FLAG_COMP_UNSUPP; 95653259Smjacob } 95739213Sgibbs bzero(g, sizeof(struct mtget)); 95841948Smjacob g->mt_type = MT_ISAR; 95939213Sgibbs if (softc->flags & SA_FLAG_COMP_UNSUPP) { 96039213Sgibbs g->mt_comp = MT_COMP_UNSUPP; 96139213Sgibbs g->mt_comp0 = MT_COMP_UNSUPP; 96239213Sgibbs g->mt_comp1 = MT_COMP_UNSUPP; 96339213Sgibbs g->mt_comp2 = MT_COMP_UNSUPP; 96439213Sgibbs g->mt_comp3 = MT_COMP_UNSUPP; 96539213Sgibbs } else { 96646962Smjacob if ((softc->flags & SA_FLAG_COMP_ENABLED) == 0) { 96746962Smjacob g->mt_comp = MT_COMP_DISABLED; 96846962Smjacob } else { 96946962Smjacob g->mt_comp = softc->comp_algorithm; 97046962Smjacob } 97139213Sgibbs g->mt_comp0 = softc->comp_algorithm; 97239213Sgibbs g->mt_comp1 = softc->comp_algorithm; 97339213Sgibbs g->mt_comp2 = softc->comp_algorithm; 97439213Sgibbs g->mt_comp3 = softc->comp_algorithm; 97539213Sgibbs } 97646962Smjacob g->mt_density = softc->media_density; 97739213Sgibbs g->mt_density0 = softc->media_density; 97839213Sgibbs g->mt_density1 = softc->media_density; 97939213Sgibbs g->mt_density2 = softc->media_density; 98039213Sgibbs g->mt_density3 = softc->media_density; 98146962Smjacob g->mt_blksiz = softc->media_blksize; 98239213Sgibbs g->mt_blksiz0 = softc->media_blksize; 98339213Sgibbs g->mt_blksiz1 = softc->media_blksize; 98439213Sgibbs g->mt_blksiz2 = softc->media_blksize; 98539213Sgibbs g->mt_blksiz3 = softc->media_blksize; 98643636Smjacob g->mt_fileno = softc->fileno; 98743636Smjacob g->mt_blkno = softc->blkno; 98843636Smjacob g->mt_dsreg = (short) softc->dsreg; 98971268Smjacob /* 99071268Smjacob * Yes, we know that this is likely to overflow 99171268Smjacob */ 99271268Smjacob if (softc->last_resid_was_io) { 99371268Smjacob if ((g->mt_resid = (short) softc->last_io_resid) != 0) { 99471268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 99571268Smjacob softc->last_io_resid = 0; 99671268Smjacob } 99771268Smjacob } 99871268Smjacob } else { 99971268Smjacob if ((g->mt_resid = (short)softc->last_ctl_resid) != 0) { 100071268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 100171268Smjacob softc->last_ctl_resid = 0; 100271268Smjacob } 100371268Smjacob } 100471268Smjacob } 100539213Sgibbs error = 0; 100639213Sgibbs break; 100739213Sgibbs } 100841948Smjacob case MTIOCERRSTAT: 100941948Smjacob { 101041948Smjacob struct scsi_tape_errors *sep = 101141948Smjacob &((union mterrstat *)arg)->scsi_errstat; 101241948Smjacob 101341948Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 101441948Smjacob ("saioctl: MTIOCERRSTAT\n")); 101541948Smjacob 101641948Smjacob bzero(sep, sizeof(*sep)); 101741948Smjacob sep->io_resid = softc->last_io_resid; 101841948Smjacob bcopy((caddr_t) &softc->last_io_sense, sep->io_sense, 101941948Smjacob sizeof (sep->io_sense)); 102042009Smjacob bcopy((caddr_t) &softc->last_io_cdb, sep->io_cdb, 102142009Smjacob sizeof (sep->io_cdb)); 102242009Smjacob sep->ctl_resid = softc->last_ctl_resid; 102341948Smjacob bcopy((caddr_t) &softc->last_ctl_sense, sep->ctl_sense, 102441948Smjacob sizeof (sep->ctl_sense)); 102542009Smjacob bcopy((caddr_t) &softc->last_ctl_cdb, sep->ctl_cdb, 102642009Smjacob sizeof (sep->ctl_cdb)); 102743636Smjacob 1028154360Smjacob if ((SA_IS_CTRL(dev) == 0 && softc->open_pending_mount) || 1029154360Smjacob didlockperiph) 103043636Smjacob bzero((caddr_t) &softc->errinfo, 103143636Smjacob sizeof (softc->errinfo)); 103241948Smjacob error = 0; 103341948Smjacob break; 103441948Smjacob } 103539213Sgibbs case MTIOCTOP: 103639213Sgibbs { 103739213Sgibbs struct mtop *mt; 103839213Sgibbs int count; 103939213Sgibbs 1040154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1041154360Smjacob 104239213Sgibbs mt = (struct mtop *)arg; 104339213Sgibbs 1044154360Smjacob 104539213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 104639213Sgibbs ("saioctl: op=0x%x count=0x%x\n", 104739213Sgibbs mt->mt_op, mt->mt_count)); 104839213Sgibbs 104939213Sgibbs count = mt->mt_count; 105039213Sgibbs switch (mt->mt_op) { 105141906Smjacob case MTWEOF: /* write an end-of-file marker */ 105268114Smjacob /* 105368114Smjacob * We don't need to clear the SA_FLAG_TAPE_WRITTEN 105468114Smjacob * flag because by keeping track of filemarks 105568114Smjacob * we have last written we know ehether or not 105668114Smjacob * we need to write more when we close the device. 105768114Smjacob */ 105841906Smjacob error = sawritefilemarks(periph, count, FALSE); 105939213Sgibbs break; 106042009Smjacob case MTWSS: /* write a setmark */ 106142009Smjacob error = sawritefilemarks(periph, count, TRUE); 106242009Smjacob break; 106339213Sgibbs case MTBSR: /* backward space record */ 106439213Sgibbs case MTFSR: /* forward space record */ 106539213Sgibbs case MTBSF: /* backward space file */ 106639213Sgibbs case MTFSF: /* forward space file */ 106742009Smjacob case MTBSS: /* backward space setmark */ 106842009Smjacob case MTFSS: /* forward space setmark */ 106939213Sgibbs case MTEOD: /* space to end of recorded medium */ 107039213Sgibbs { 107139213Sgibbs int nmarks; 107239213Sgibbs 107348520Speter spaceop = SS_FILEMARKS; 107439213Sgibbs nmarks = softc->filemarks; 107539213Sgibbs error = sacheckeod(periph); 107641906Smjacob if (error) { 1077164906Smjacob xpt_print(periph->path, 1078164906Smjacob "EOD check prior to spacing failed\n"); 107941906Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 108041906Smjacob break; 108141906Smjacob } 108239213Sgibbs nmarks -= softc->filemarks; 108342009Smjacob switch(mt->mt_op) { 108442009Smjacob case MTBSR: 108539213Sgibbs count = -count; 108642009Smjacob /* FALLTHROUGH */ 108742009Smjacob case MTFSR: 108839213Sgibbs spaceop = SS_BLOCKS; 108942009Smjacob break; 109042009Smjacob case MTBSF: 109142009Smjacob count = -count; 109242009Smjacob /* FALLTHROUGH */ 109342009Smjacob case MTFSF: 109442009Smjacob break; 109542009Smjacob case MTBSS: 109642009Smjacob count = -count; 109742009Smjacob /* FALLTHROUGH */ 109842009Smjacob case MTFSS: 109942009Smjacob spaceop = SS_SETMARKS; 110042009Smjacob break; 110142009Smjacob case MTEOD: 110239213Sgibbs spaceop = SS_EOD; 110339213Sgibbs count = 0; 110439213Sgibbs nmarks = 0; 110542009Smjacob break; 110642009Smjacob default: 110742009Smjacob error = EINVAL; 110842009Smjacob break; 110939213Sgibbs } 111042009Smjacob if (error) 111142009Smjacob break; 111239213Sgibbs 111339213Sgibbs nmarks = softc->filemarks; 111442009Smjacob /* 111542009Smjacob * XXX: Why are we checking again? 111642009Smjacob */ 111739213Sgibbs error = sacheckeod(periph); 111842009Smjacob if (error) 111942009Smjacob break; 112039213Sgibbs nmarks -= softc->filemarks; 112142009Smjacob error = saspace(periph, count - nmarks, spaceop); 112241906Smjacob /* 112341906Smjacob * At this point, clear that we've written the tape 112441906Smjacob * and that we've written any filemarks. We really 112541906Smjacob * don't know what the applications wishes to do next- 112641906Smjacob * the sacheckeod's will make sure we terminated the 112741906Smjacob * tape correctly if we'd been writing, but the next 112841906Smjacob * action the user application takes will set again 112941906Smjacob * whether we need to write filemarks. 113041906Smjacob */ 113146962Smjacob softc->flags &= 113246962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 113341906Smjacob softc->filemarks = 0; 113439213Sgibbs break; 113539213Sgibbs } 113639213Sgibbs case MTREW: /* rewind */ 1137154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 113841906Smjacob (void) sacheckeod(periph); 113939213Sgibbs error = sarewind(periph); 114041906Smjacob /* see above */ 114142009Smjacob softc->flags &= 114246962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 114382575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 114441906Smjacob softc->filemarks = 0; 114539213Sgibbs break; 114639213Sgibbs case MTERASE: /* erase */ 1147154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 114839213Sgibbs error = saerase(periph, count); 114946962Smjacob softc->flags &= 115046962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 115182575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 115239213Sgibbs break; 115339213Sgibbs case MTRETENS: /* re-tension tape */ 1154154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 115539213Sgibbs error = saretension(periph); 115646962Smjacob softc->flags &= 115746962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 115882575Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 115939213Sgibbs break; 116039213Sgibbs case MTOFFL: /* rewind and put the drive offline */ 116141906Smjacob 1162154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1163154360Smjacob 116441906Smjacob (void) sacheckeod(periph); 116541906Smjacob /* see above */ 116641906Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 116741906Smjacob softc->filemarks = 0; 116841906Smjacob 116946962Smjacob error = sarewind(periph); 117053522Smjacob /* clear the frozen flag anyway */ 117153522Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 117246962Smjacob 117339213Sgibbs /* 117453522Smjacob * Be sure to allow media removal before ejecting. 117539213Sgibbs */ 117646962Smjacob 117739213Sgibbs saprevent(periph, PR_ALLOW); 117853522Smjacob if (error == 0) { 117943636Smjacob error = saloadunload(periph, FALSE); 118053522Smjacob if (error == 0) { 118153522Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 118253522Smjacob } 118353522Smjacob } 118446962Smjacob break; 118539213Sgibbs 118639213Sgibbs case MTNOP: /* no operation, sets status only */ 118739213Sgibbs case MTCACHE: /* enable controller cache */ 118839213Sgibbs case MTNOCACHE: /* disable controller cache */ 118939213Sgibbs error = 0; 119039213Sgibbs break; 119146962Smjacob 119239213Sgibbs case MTSETBSIZ: /* Set block size for device */ 119339213Sgibbs 1194154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1195154360Smjacob 119639213Sgibbs error = sasetparams(periph, SA_PARAM_BLOCKSIZE, count, 119742563Smjacob 0, 0, 0); 119841674Smjacob if (error == 0) { 119941906Smjacob softc->last_media_blksize = 120041906Smjacob softc->media_blksize; 120141674Smjacob softc->media_blksize = count; 120241674Smjacob if (count) { 120341674Smjacob softc->flags |= SA_FLAG_FIXED; 120441674Smjacob if (powerof2(count)) { 120541674Smjacob softc->blk_shift = 120641674Smjacob ffs(count) - 1; 120741674Smjacob softc->blk_mask = count - 1; 120841674Smjacob } else { 120941674Smjacob softc->blk_mask = ~0; 121041674Smjacob softc->blk_shift = 0; 121141674Smjacob } 121241906Smjacob /* 121341906Smjacob * Make the user's desire 'persistent'. 121441906Smjacob */ 121541906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 121641906Smjacob softc->quirks |= SA_QUIRK_FIXED; 121741674Smjacob } else { 121841674Smjacob softc->flags &= ~SA_FLAG_FIXED; 121941674Smjacob if (softc->max_blk == 0) { 122041674Smjacob softc->max_blk = ~0; 122141674Smjacob } 122241674Smjacob softc->blk_shift = 0; 122341674Smjacob if (softc->blk_gran != 0) { 122441674Smjacob softc->blk_mask = 122541674Smjacob softc->blk_gran - 1; 122641674Smjacob } else { 122741674Smjacob softc->blk_mask = 0; 122841674Smjacob } 122941906Smjacob /* 123041906Smjacob * Make the user's desire 'persistent'. 123141906Smjacob */ 123241906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 123341906Smjacob softc->quirks &= ~SA_QUIRK_FIXED; 123441674Smjacob } 123541674Smjacob } 123639213Sgibbs break; 123739213Sgibbs case MTSETDNSTY: /* Set density for device and mode */ 1238154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 1239154360Smjacob 124039213Sgibbs if (count > UCHAR_MAX) { 124139213Sgibbs error = EINVAL; 124239213Sgibbs break; 124339213Sgibbs } else { 124439213Sgibbs error = sasetparams(periph, SA_PARAM_DENSITY, 124542563Smjacob 0, count, 0, 0); 124639213Sgibbs } 124739213Sgibbs break; 124839213Sgibbs case MTCOMP: /* enable compression */ 1249154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 125039213Sgibbs /* 125139213Sgibbs * Some devices don't support compression, and 125239213Sgibbs * don't like it if you ask them for the 125339213Sgibbs * compression page. 125439213Sgibbs */ 125543636Smjacob if ((softc->quirks & SA_QUIRK_NOCOMP) || 125643636Smjacob (softc->flags & SA_FLAG_COMP_UNSUPP)) { 125739213Sgibbs error = ENODEV; 125839213Sgibbs break; 125939213Sgibbs } 126039213Sgibbs error = sasetparams(periph, SA_PARAM_COMPRESSION, 126154099Smjacob 0, 0, count, SF_NO_PRINT); 126239213Sgibbs break; 126339213Sgibbs default: 126439213Sgibbs error = EINVAL; 126539213Sgibbs } 126639213Sgibbs break; 126739213Sgibbs } 126839213Sgibbs case MTIOCIEOT: 126939213Sgibbs case MTIOCEEOT: 127039213Sgibbs error = 0; 127139213Sgibbs break; 127241918Smjacob case MTIOCRDSPOS: 1273154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 127441918Smjacob error = sardpos(periph, 0, (u_int32_t *) arg); 127541918Smjacob break; 127641918Smjacob case MTIOCRDHPOS: 1277154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 127841918Smjacob error = sardpos(periph, 1, (u_int32_t *) arg); 127941918Smjacob break; 128041918Smjacob case MTIOCSLOCATE: 1281154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 128241918Smjacob error = sasetpos(periph, 0, (u_int32_t *) arg); 128341918Smjacob break; 128441918Smjacob case MTIOCHLOCATE: 1285154360Smjacob PENDING_MOUNT_CHECK(softc, periph, dev); 128641918Smjacob error = sasetpos(periph, 1, (u_int32_t *) arg); 128741918Smjacob break; 128846962Smjacob case MTIOCGETEOTMODEL: 128946962Smjacob error = 0; 129046962Smjacob if (softc->quirks & SA_QUIRK_1FM) 129146962Smjacob mode = 1; 129246962Smjacob else 129346962Smjacob mode = 2; 129446962Smjacob *((u_int32_t *) arg) = mode; 129546962Smjacob break; 129646962Smjacob case MTIOCSETEOTMODEL: 129746962Smjacob error = 0; 129846962Smjacob switch (*((u_int32_t *) arg)) { 129946962Smjacob case 1: 130046962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 130146962Smjacob softc->quirks |= SA_QUIRK_1FM; 130246962Smjacob break; 130346962Smjacob case 2: 130446962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 130546962Smjacob softc->quirks |= SA_QUIRK_2FM; 130646962Smjacob break; 130746962Smjacob default: 130846962Smjacob error = EINVAL; 130946962Smjacob break; 131046962Smjacob } 131146962Smjacob break; 131239213Sgibbs default: 131339213Sgibbs error = cam_periph_ioctl(periph, cmd, arg, saerror); 131439213Sgibbs break; 131539213Sgibbs } 131671268Smjacob 131771268Smjacob /* 131871268Smjacob * Check to see if we cleared a frozen state 131971268Smjacob */ 132071268Smjacob if (error == 0 && (softc->flags & SA_FLAG_TAPE_FROZEN)) { 132171268Smjacob switch(cmd) { 132271268Smjacob case MTIOCRDSPOS: 132371268Smjacob case MTIOCRDHPOS: 132471268Smjacob case MTIOCSLOCATE: 132571268Smjacob case MTIOCHLOCATE: 132671268Smjacob softc->fileno = (daddr_t) -1; 132771268Smjacob softc->blkno = (daddr_t) -1; 132871268Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 1329164906Smjacob xpt_print(periph->path, 1330164906Smjacob "tape state now unfrozen.\n"); 133171268Smjacob break; 133271268Smjacob default: 133371268Smjacob break; 133471268Smjacob } 133571268Smjacob } 133643636Smjacob if (didlockperiph) { 1337168752Sscottl cam_periph_unhold(periph); 133843636Smjacob } 1339168752Sscottl cam_periph_unlock(periph); 134039213Sgibbs return (error); 134139213Sgibbs} 134239213Sgibbs 134339213Sgibbsstatic void 134439213Sgibbssainit(void) 134539213Sgibbs{ 134639213Sgibbs cam_status status; 134739213Sgibbs 134839213Sgibbs /* 134939213Sgibbs * Install a global async callback. 135039213Sgibbs */ 1351169605Sscottl status = xpt_register_async(AC_FOUND_DEVICE, saasync, NULL, NULL); 135239213Sgibbs 135339213Sgibbs if (status != CAM_REQ_CMP) { 135439213Sgibbs printf("sa: Failed to attach master async callback " 135539213Sgibbs "due to status 0x%x!\n", status); 135639213Sgibbs } 135739213Sgibbs} 135839213Sgibbs 135939213Sgibbsstatic void 136040603Skensaoninvalidate(struct cam_periph *periph) 136140603Sken{ 136240603Sken struct sa_softc *softc; 136340603Sken 136440603Sken softc = (struct sa_softc *)periph->softc; 136540603Sken 136640603Sken /* 136740603Sken * De-register any async callbacks. 136840603Sken */ 1369169605Sscottl xpt_register_async(0, saasync, periph, periph->path); 137040603Sken 137140603Sken softc->flags |= SA_FLAG_INVALID; 137240603Sken 137340603Sken /* 137440603Sken * Return all queued I/O with ENXIO. 137540603Sken * XXX Handle any transactions queued to the card 137640603Sken * with XPT_ABORT_CCB. 137740603Sken */ 1378112946Sphk bioq_flush(&softc->bio_queue, NULL, ENXIO); 137946962Smjacob softc->queue_count = 0; 138040603Sken} 138140603Sken 138240603Skenstatic void 138339213Sgibbssacleanup(struct cam_periph *periph) 138439213Sgibbs{ 138540603Sken struct sa_softc *softc; 138653259Smjacob int i; 138740603Sken 138840603Sken softc = (struct sa_softc *)periph->softc; 138940603Sken 1390112006Sphk devstat_remove_entry(softc->device_stats); 1391187028Strasz cam_periph_unlock(periph); 139253259Smjacob destroy_dev(softc->devs.ctl_dev); 139353259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 139453259Smjacob destroy_dev(softc->devs.mode_devs[i].r_dev); 139553259Smjacob destroy_dev(softc->devs.mode_devs[i].nr_dev); 139653259Smjacob destroy_dev(softc->devs.mode_devs[i].er_dev); 139753259Smjacob } 1398187028Strasz cam_periph_lock(periph); 1399147723Savatar free(softc, M_SCSISA); 140039213Sgibbs} 140139213Sgibbs 140239213Sgibbsstatic void 140339213Sgibbssaasync(void *callback_arg, u_int32_t code, 140439213Sgibbs struct cam_path *path, void *arg) 140539213Sgibbs{ 140639213Sgibbs struct cam_periph *periph; 140739213Sgibbs 140839213Sgibbs periph = (struct cam_periph *)callback_arg; 140939213Sgibbs switch (code) { 141039213Sgibbs case AC_FOUND_DEVICE: 141139213Sgibbs { 141239213Sgibbs struct ccb_getdev *cgd; 141339213Sgibbs cam_status status; 141439213Sgibbs 141539213Sgibbs cgd = (struct ccb_getdev *)arg; 141679177Smjacob if (cgd == NULL) 141779177Smjacob break; 141839213Sgibbs 1419195534Sscottl if (cgd->protocol != PROTO_SCSI) 1420195534Sscottl break; 1421195534Sscottl 142256148Smjacob if (SID_TYPE(&cgd->inq_data) != T_SEQUENTIAL) 142339213Sgibbs break; 142439213Sgibbs 142539213Sgibbs /* 142639213Sgibbs * Allocate a peripheral instance for 142739213Sgibbs * this device and start the probe 142839213Sgibbs * process. 142939213Sgibbs */ 143040603Sken status = cam_periph_alloc(saregister, saoninvalidate, 143140603Sken sacleanup, sastart, 143239213Sgibbs "sa", CAM_PERIPH_BIO, cgd->ccb_h.path, 143339213Sgibbs saasync, AC_FOUND_DEVICE, cgd); 143439213Sgibbs 143539213Sgibbs if (status != CAM_REQ_CMP 143639213Sgibbs && status != CAM_REQ_INPROG) 143739213Sgibbs printf("saasync: Unable to probe new device " 143839213Sgibbs "due to status 0x%x\n", status); 143939213Sgibbs break; 144039213Sgibbs } 144139213Sgibbs default: 144247413Sgibbs cam_periph_async(periph, code, path, arg); 144339213Sgibbs break; 144439213Sgibbs } 144539213Sgibbs} 144639213Sgibbs 144739213Sgibbsstatic cam_status 144839213Sgibbssaregister(struct cam_periph *periph, void *arg) 144939213Sgibbs{ 145039213Sgibbs struct sa_softc *softc; 145139213Sgibbs struct ccb_getdev *cgd; 1452220644Smav struct ccb_pathinq cpi; 145339213Sgibbs caddr_t match; 145453259Smjacob int i; 145539213Sgibbs 145639213Sgibbs cgd = (struct ccb_getdev *)arg; 145739213Sgibbs if (cgd == NULL) { 145839213Sgibbs printf("saregister: no getdev CCB, can't register device\n"); 145954099Smjacob return (CAM_REQ_CMP_ERR); 146039213Sgibbs } 146139213Sgibbs 146267723Smjacob softc = (struct sa_softc *) 1463147723Savatar malloc(sizeof (*softc), M_SCSISA, M_NOWAIT | M_ZERO); 146439213Sgibbs if (softc == NULL) { 146539213Sgibbs printf("saregister: Unable to probe new device. " 146639213Sgibbs "Unable to allocate softc\n"); 146754099Smjacob return (CAM_REQ_CMP_ERR); 146839213Sgibbs } 146941674Smjacob softc->scsi_rev = SID_ANSI_REV(&cgd->inq_data); 147039213Sgibbs softc->state = SA_STATE_NORMAL; 147143636Smjacob softc->fileno = (daddr_t) -1; 147243636Smjacob softc->blkno = (daddr_t) -1; 147343636Smjacob 147459249Sphk bioq_init(&softc->bio_queue); 147539213Sgibbs periph->softc = softc; 147639213Sgibbs 147739213Sgibbs /* 147839213Sgibbs * See if this device has any quirks. 147939213Sgibbs */ 148039213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 148139213Sgibbs (caddr_t)sa_quirk_table, 148239213Sgibbs sizeof(sa_quirk_table)/sizeof(*sa_quirk_table), 148339213Sgibbs sizeof(*sa_quirk_table), scsi_inquiry_match); 148439213Sgibbs 148542563Smjacob if (match != NULL) { 148639213Sgibbs softc->quirks = ((struct sa_quirk_entry *)match)->quirks; 148742563Smjacob softc->last_media_blksize = 148842563Smjacob ((struct sa_quirk_entry *)match)->prefblk; 148942563Smjacob } else 149039213Sgibbs softc->quirks = SA_QUIRK_NONE; 149139213Sgibbs 1492220644Smav bzero(&cpi, sizeof(cpi)); 1493220644Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1494220644Smav cpi.ccb_h.func_code = XPT_PATH_INQ; 1495220644Smav xpt_action((union ccb *)&cpi); 1496220644Smav 149739213Sgibbs /* 1498220644Smav * The SA driver supports a blocksize, but we don't know the 149946962Smjacob * blocksize until we media is inserted. So, set a flag to 150039213Sgibbs * indicate that the blocksize is unavailable right now. 150139213Sgibbs */ 1502169605Sscottl cam_periph_unlock(periph); 1503112006Sphk softc->device_stats = devstat_new_entry("sa", periph->unit_number, 0, 150456148Smjacob DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) | 1505220644Smav XPORT_DEVSTAT_TYPE(cpi.transport), DEVSTAT_PRIORITY_TAPE); 150653259Smjacob 1507255000Sken /* 1508255000Sken * If maxio isn't set, we fall back to DFLTPHYS. If it is set, we 1509255000Sken * take it whether or not it's larger than MAXPHYS. physio will 1510255000Sken * break it down into pieces small enough to fit in a buffer. 1511255000Sken */ 1512255000Sken if (cpi.maxio == 0) 1513255000Sken softc->maxio = DFLTPHYS; 1514255000Sken else 1515255000Sken softc->maxio = cpi.maxio; 1516255000Sken 1517255000Sken /* 1518255000Sken * If the SIM supports unmapped I/O, let physio know that we can 1519255000Sken * handle unmapped buffers. 1520255000Sken */ 1521255000Sken if (cpi.hba_misc & PIM_UNMAPPED) 1522255000Sken softc->si_flags = SI_UNMAPPED; 1523255000Sken 152453259Smjacob softc->devs.ctl_dev = make_dev(&sa_cdevsw, SAMINOR(SA_CTLDEV, 1525191304Sed 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; 1528255000Sken softc->devs.ctl_dev->si_iosize_max = softc->maxio; 1529255000Sken softc->devs.ctl_dev->si_flags |= softc->si_flags; 153053259Smjacob 153153259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 153253283Smjacob 153353259Smjacob softc->devs.mode_devs[i].r_dev = make_dev(&sa_cdevsw, 1534191304Sed SAMINOR(SA_NOT_CTLDEV, i, SA_ATYPE_R), 153572804Smjacob UID_ROOT, GID_OPERATOR, 0660, "%s%d.%d", 153653259Smjacob periph->periph_name, periph->unit_number, i); 1537101940Snjl softc->devs.mode_devs[i].r_dev->si_drv1 = periph; 1538255000Sken softc->devs.mode_devs[i].r_dev->si_iosize_max = softc->maxio; 1539255000Sken softc->devs.mode_devs[i].r_dev->si_flags |= softc->si_flags; 154053283Smjacob 154153259Smjacob softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw, 1542191304Sed SAMINOR(SA_NOT_CTLDEV, i, SA_ATYPE_NR), 154372804Smjacob UID_ROOT, GID_OPERATOR, 0660, "n%s%d.%d", 154453259Smjacob periph->periph_name, periph->unit_number, i); 1545101940Snjl softc->devs.mode_devs[i].nr_dev->si_drv1 = periph; 1546255000Sken softc->devs.mode_devs[i].nr_dev->si_iosize_max = softc->maxio; 1547255000Sken softc->devs.mode_devs[i].nr_dev->si_flags |= softc->si_flags; 154853259Smjacob 154953283Smjacob softc->devs.mode_devs[i].er_dev = make_dev(&sa_cdevsw, 1550191304Sed SAMINOR(SA_NOT_CTLDEV, i, SA_ATYPE_ER), 155172804Smjacob UID_ROOT, GID_OPERATOR, 0660, "e%s%d.%d", 155253259Smjacob periph->periph_name, periph->unit_number, i); 1553101940Snjl softc->devs.mode_devs[i].er_dev->si_drv1 = periph; 1554255000Sken softc->devs.mode_devs[i].er_dev->si_iosize_max = softc->maxio; 1555255000Sken softc->devs.mode_devs[i].er_dev->si_flags |= softc->si_flags; 155665838Smjacob 155765838Smjacob /* 155865838Smjacob * Make the (well known) aliases for the first mode. 155965838Smjacob */ 156065838Smjacob if (i == 0) { 1561130585Sphk struct cdev *alias; 1562101940Snjl 1563101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].r_dev, 156472804Smjacob "%s%d", periph->periph_name, periph->unit_number); 1565101940Snjl alias->si_drv1 = periph; 1566255000Sken alias->si_iosize_max = softc->maxio; 1567255000Sken alias->si_flags |= softc->si_flags; 1568255000Sken 1569101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].nr_dev, 157072804Smjacob "n%s%d", periph->periph_name, periph->unit_number); 1571101940Snjl alias->si_drv1 = periph; 1572255000Sken alias->si_iosize_max = softc->maxio; 1573255000Sken alias->si_flags |= softc->si_flags; 1574255000Sken 1575101940Snjl alias = make_dev_alias(softc->devs.mode_devs[i].er_dev, 157672804Smjacob "e%s%d", periph->periph_name, periph->unit_number); 1577101940Snjl alias->si_drv1 = periph; 1578255000Sken alias->si_iosize_max = softc->maxio; 1579255000Sken alias->si_flags |= softc->si_flags; 158065838Smjacob } 158153259Smjacob } 1582168872Sscottl cam_periph_lock(periph); 158353259Smjacob 158439213Sgibbs /* 158539213Sgibbs * Add an async callback so that we get 158639213Sgibbs * notified if this device goes away. 158739213Sgibbs */ 1588169605Sscottl xpt_register_async(AC_LOST_DEVICE, saasync, periph, periph->path); 158939213Sgibbs 159039213Sgibbs xpt_announce_periph(periph, NULL); 1591251386Ssmh xpt_announce_quirks(periph, softc->quirks, SA_QUIRK_BIT_STRING); 159239213Sgibbs 159354099Smjacob return (CAM_REQ_CMP); 159439213Sgibbs} 159539213Sgibbs 159639213Sgibbsstatic void 159739213Sgibbssastart(struct cam_periph *periph, union ccb *start_ccb) 159839213Sgibbs{ 159939213Sgibbs struct sa_softc *softc; 160039213Sgibbs 160139213Sgibbs softc = (struct sa_softc *)periph->softc; 160239213Sgibbs 1603115660Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sastart\n")); 160471082Smjacob 160539213Sgibbs 160639213Sgibbs switch (softc->state) { 160739213Sgibbs case SA_STATE_NORMAL: 160839213Sgibbs { 160939213Sgibbs /* Pull a buffer from the queue and get going on it */ 161059249Sphk struct bio *bp; 161139213Sgibbs 161239213Sgibbs /* 161339213Sgibbs * See if there is a buf with work for us to do.. 161439213Sgibbs */ 161559249Sphk bp = bioq_first(&softc->bio_queue); 161639213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 161739213Sgibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 161839213Sgibbs ("queuing for immediate ccb\n")); 161971082Smjacob Set_CCB_Type(start_ccb, SA_CCB_WAITING); 162039213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 162139213Sgibbs periph_links.sle); 162239213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 162339213Sgibbs wakeup(&periph->ccb_list); 162439213Sgibbs } else if (bp == NULL) { 162539213Sgibbs xpt_release_ccb(start_ccb); 162639213Sgibbs } else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) { 162759249Sphk struct bio *done_bp; 162882575Smjacobagain: 162946962Smjacob softc->queue_count--; 163059249Sphk bioq_remove(&softc->bio_queue, bp); 163159249Sphk bp->bio_resid = bp->bio_bcount; 163282575Smjacob done_bp = bp; 163339213Sgibbs if ((softc->flags & SA_FLAG_EOM_PENDING) != 0) { 163482575Smjacob /* 163582575Smjacob * We now just clear errors in this case 163682575Smjacob * and let the residual be the notifier. 163782575Smjacob */ 163882575Smjacob bp->bio_error = 0; 163982575Smjacob } else if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) { 164082575Smjacob /* 164182575Smjacob * This can only happen if we're reading 164282575Smjacob * in fixed length mode. In this case, 164382575Smjacob * we dump the rest of the list the 164482575Smjacob * same way. 164582575Smjacob */ 164682575Smjacob bp->bio_error = 0; 164782575Smjacob if (bioq_first(&softc->bio_queue) != NULL) { 164882575Smjacob biodone(done_bp); 164982575Smjacob goto again; 165082575Smjacob } 165182575Smjacob } else if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) { 165259249Sphk bp->bio_error = EIO; 165382575Smjacob bp->bio_flags |= BIO_ERROR; 165441948Smjacob } 165559249Sphk bp = bioq_first(&softc->bio_queue); 165644354Smjacob /* 165744354Smjacob * Only if we have no other buffers queued up 165844354Smjacob * do we clear the pending error flag. 165944354Smjacob */ 166044354Smjacob if (bp == NULL) 166144354Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 166244354Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 166346962Smjacob ("sastart- ERR_PENDING now 0x%x, bp is %sNULL, " 166446962Smjacob "%d more buffers queued up\n", 166544354Smjacob (softc->flags & SA_FLAG_ERR_PENDING), 166646962Smjacob (bp != NULL)? "not " : " ", softc->queue_count)); 166744354Smjacob xpt_release_ccb(start_ccb); 166841948Smjacob biodone(done_bp); 166939213Sgibbs } else { 167039213Sgibbs u_int32_t length; 167139213Sgibbs 167259249Sphk bioq_remove(&softc->bio_queue, bp); 167346962Smjacob softc->queue_count--; 167439213Sgibbs 167539213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) { 167639213Sgibbs if (softc->blk_shift != 0) { 167739213Sgibbs length = 167859249Sphk bp->bio_bcount >> softc->blk_shift; 167943636Smjacob } else if (softc->media_blksize != 0) { 168071082Smjacob length = bp->bio_bcount / 168171082Smjacob softc->media_blksize; 168243636Smjacob } else { 168359249Sphk bp->bio_error = EIO; 1684164906Smjacob xpt_print(periph->path, "zero blocksize" 1685164906Smjacob " for FIXED length writes?\n"); 168643636Smjacob biodone(bp); 168743636Smjacob break; 168839213Sgibbs } 1689115660Smjacob#if 0 1690115660Smjacob CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 1691115660Smjacob ("issuing a %d fixed record %s\n", 1692115660Smjacob length, (bp->bio_cmd == BIO_READ)? "read" : 1693115660Smjacob "write")); 1694115660Smjacob#endif 169539213Sgibbs } else { 169659249Sphk length = bp->bio_bcount; 1697115660Smjacob#if 0 169841906Smjacob CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 1699115660Smjacob ("issuing a %d variable byte %s\n", 1700115660Smjacob length, (bp->bio_cmd == BIO_READ)? "read" : 1701115660Smjacob "write")); 1702115660Smjacob#endif 170339213Sgibbs } 1704112260Sphk devstat_start_transaction_bio(softc->device_stats, bp); 170539213Sgibbs /* 170641906Smjacob * Some people have theorized that we should 170739213Sgibbs * suppress illegal length indication if we are 170839213Sgibbs * running in variable block mode so that we don't 170939213Sgibbs * have to request sense every time our requested 171039213Sgibbs * block size is larger than the written block. 171139213Sgibbs * The residual information from the ccb allows 171239213Sgibbs * us to identify this situation anyway. The only 171339213Sgibbs * problem with this is that we will not get 171439213Sgibbs * information about blocks that are larger than 171539213Sgibbs * our read buffer unless we set the block size 171639213Sgibbs * in the mode page to something other than 0. 171741906Smjacob * 171841906Smjacob * I believe that this is a non-issue. If user apps 171941906Smjacob * don't adjust their read size to match our record 172041906Smjacob * size, that's just life. Anyway, the typical usage 172141906Smjacob * would be to issue, e.g., 64KB reads and occasionally 172241906Smjacob * have to do deal with 512 byte or 1KB intermediate 172341906Smjacob * records. 172439213Sgibbs */ 172559249Sphk softc->dsreg = (bp->bio_cmd == BIO_READ)? 172643636Smjacob MTIO_DSREG_RD : MTIO_DSREG_WR; 172746962Smjacob scsi_sa_read_write(&start_ccb->csio, 0, sadone, 1728255000Sken MSG_SIMPLE_Q_TAG, (bp->bio_cmd == BIO_READ ? 1729255000Sken SCSI_RW_READ : SCSI_RW_WRITE) | 1730255000Sken ((bp->bio_flags & BIO_UNMAPPED) != 0 ? 1731255000Sken SCSI_RW_BIO : 0), FALSE, 1732255000Sken (softc->flags & SA_FLAG_FIXED) != 0, length, 1733255000Sken (bp->bio_flags & BIO_UNMAPPED) != 0 ? (void *)bp : 1734255000Sken bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE, 173579100Smjacob IO_TIMEOUT); 173671082Smjacob start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED; 173771082Smjacob Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO); 173839213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 173959249Sphk bp = bioq_first(&softc->bio_queue); 174039213Sgibbs xpt_action(start_ccb); 174139213Sgibbs } 174239213Sgibbs 174339213Sgibbs if (bp != NULL) { 174439213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 1745198382Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 174639213Sgibbs } 174739213Sgibbs break; 174839213Sgibbs } 174946962Smjacob case SA_STATE_ABNORMAL: 175046962Smjacob default: 175146962Smjacob panic("state 0x%x in sastart", softc->state); 175246962Smjacob break; 175339213Sgibbs } 175439213Sgibbs} 175539213Sgibbs 175639213Sgibbs 175739213Sgibbsstatic void 175839213Sgibbssadone(struct cam_periph *periph, union ccb *done_ccb) 175939213Sgibbs{ 176039213Sgibbs struct sa_softc *softc; 176139213Sgibbs struct ccb_scsiio *csio; 176239213Sgibbs 176339213Sgibbs softc = (struct sa_softc *)periph->softc; 176439213Sgibbs csio = &done_ccb->csio; 176571082Smjacob switch (CCB_Type(csio)) { 176639213Sgibbs case SA_CCB_BUFFER_IO: 176739213Sgibbs { 176859249Sphk struct bio *bp; 176939213Sgibbs int error; 177039213Sgibbs 177143636Smjacob softc->dsreg = MTIO_DSREG_REST; 177259249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 177339213Sgibbs error = 0; 177439213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 177539213Sgibbs if ((error = saerror(done_ccb, 0, 0)) == ERESTART) { 177639213Sgibbs /* 177741948Smjacob * A retry was scheduled, so just return. 177839213Sgibbs */ 177939213Sgibbs return; 178039213Sgibbs } 178139213Sgibbs } 178239213Sgibbs 178339213Sgibbs if (error == EIO) { 178439213Sgibbs 178539213Sgibbs /* 178653522Smjacob * Catastrophic error. Mark the tape as frozen 178753522Smjacob * (we no longer know tape position). 178853522Smjacob * 178944354Smjacob * Return all queued I/O with EIO, and unfreeze 179039213Sgibbs * our queue so that future transactions that 179139213Sgibbs * attempt to fix this problem can get to the 179239213Sgibbs * device. 179339213Sgibbs * 179439213Sgibbs */ 179539213Sgibbs 179653522Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 1797112946Sphk bioq_flush(&softc->bio_queue, NULL, EIO); 179839213Sgibbs } 179939213Sgibbs if (error != 0) { 180059249Sphk bp->bio_resid = bp->bio_bcount; 180159249Sphk bp->bio_error = error; 180259249Sphk bp->bio_flags |= BIO_ERROR; 180343636Smjacob /* 180443636Smjacob * In the error case, position is updated in saerror. 180543636Smjacob */ 180639213Sgibbs } else { 180759249Sphk bp->bio_resid = csio->resid; 180859249Sphk bp->bio_error = 0; 180939213Sgibbs if (csio->resid != 0) { 181059249Sphk bp->bio_flags |= BIO_ERROR; 181139213Sgibbs } 181259249Sphk if (bp->bio_cmd == BIO_WRITE) { 181339213Sgibbs softc->flags |= SA_FLAG_TAPE_WRITTEN; 181439213Sgibbs softc->filemarks = 0; 181539213Sgibbs } 181671082Smjacob if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) && 181771082Smjacob (softc->blkno != (daddr_t) -1)) { 181843636Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 181943636Smjacob u_int32_t l; 182043636Smjacob if (softc->blk_shift != 0) { 182159249Sphk l = bp->bio_bcount >> 182243636Smjacob softc->blk_shift; 182343636Smjacob } else { 182459249Sphk l = bp->bio_bcount / 182543636Smjacob softc->media_blksize; 182643636Smjacob } 182743636Smjacob softc->blkno += (daddr_t) l; 182843636Smjacob } else { 182943636Smjacob softc->blkno++; 183043636Smjacob } 183143636Smjacob } 183239213Sgibbs } 183346962Smjacob /* 183446962Smjacob * If we had an error (immediate or pending), 183546962Smjacob * release the device queue now. 183646962Smjacob */ 183746962Smjacob if (error || (softc->flags & SA_FLAG_ERR_PENDING)) 183846962Smjacob cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0); 183959249Sphk if (error || bp->bio_resid) { 184041674Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 184141674Smjacob ("error %d resid %ld count %ld\n", error, 184259249Sphk bp->bio_resid, bp->bio_bcount)); 184341674Smjacob } 1844112006Sphk biofinish(bp, softc->device_stats, 0); 184539213Sgibbs break; 184639213Sgibbs } 184739213Sgibbs case SA_CCB_WAITING: 184839213Sgibbs { 184939213Sgibbs /* Caller will release the CCB */ 185039213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 185139213Sgibbs return; 185239213Sgibbs } 185339213Sgibbs } 185439213Sgibbs xpt_release_ccb(done_ccb); 185539213Sgibbs} 185639213Sgibbs 185741906Smjacob/* 185841906Smjacob * Mount the tape (make sure it's ready for I/O). 185941906Smjacob */ 186039213Sgibbsstatic int 1861130585Sphksamount(struct cam_periph *periph, int oflags, struct cdev *dev) 186239213Sgibbs{ 186339213Sgibbs struct sa_softc *softc; 186439213Sgibbs union ccb *ccb; 186539213Sgibbs int error; 186639213Sgibbs 186741906Smjacob /* 186841906Smjacob * oflags can be checked for 'kind' of open (read-only check) - later 186941906Smjacob * dev can be checked for a control-mode or compression open - later 187041906Smjacob */ 187141906Smjacob UNUSED_PARAMETER(oflags); 187241906Smjacob UNUSED_PARAMETER(dev); 187341906Smjacob 187441906Smjacob 187539213Sgibbs softc = (struct sa_softc *)periph->softc; 187639213Sgibbs 187739213Sgibbs /* 187853259Smjacob * This should determine if something has happend since the last 187953259Smjacob * open/mount that would invalidate the mount. We do *not* want 188053259Smjacob * to retry this command- we just want the status. But we only 188153259Smjacob * do this if we're mounted already- if we're not mounted, 188253259Smjacob * we don't care about the unit read state and can instead use 188353259Smjacob * this opportunity to attempt to reserve the tape unit. 188439213Sgibbs */ 188553259Smjacob 188653259Smjacob if (softc->flags & SA_FLAG_TAPE_MOUNTED) { 188753259Smjacob ccb = cam_periph_getccb(periph, 1); 188853259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 188979100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 189054099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1891112006Sphk softc->device_stats); 189253259Smjacob if (error == ENXIO) { 189353259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 189453259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 189579100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 189654099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1897112006Sphk softc->device_stats); 189853259Smjacob } else if (error) { 189954099Smjacob /* 190054099Smjacob * We don't need to freeze the tape because we 190154099Smjacob * will now attempt to rewind/load it. 190254099Smjacob */ 190353259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 1904144430Ssam if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 1905164906Smjacob xpt_print(periph->path, 1906164906Smjacob "error %d on TUR in samount\n", error); 190754099Smjacob } 190853259Smjacob } 190953259Smjacob } else { 191053259Smjacob error = sareservereleaseunit(periph, TRUE); 191153259Smjacob if (error) { 191253259Smjacob return (error); 191353259Smjacob } 191453259Smjacob ccb = cam_periph_getccb(periph, 1); 191554105Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 191679100Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT); 191754105Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1918112006Sphk softc->device_stats); 191953259Smjacob } 192039213Sgibbs 192139213Sgibbs if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 192253259Smjacob struct scsi_read_block_limits_data *rblim = NULL; 192353259Smjacob int comp_enabled, comp_supported; 192441906Smjacob u_int8_t write_protect, guessing = 0; 192539213Sgibbs 192639213Sgibbs /* 192739213Sgibbs * Clear out old state. 192839213Sgibbs */ 192939213Sgibbs softc->flags &= ~(SA_FLAG_TAPE_WP|SA_FLAG_TAPE_WRITTEN| 193039213Sgibbs SA_FLAG_ERR_PENDING|SA_FLAG_COMP_ENABLED| 193146962Smjacob SA_FLAG_COMP_SUPP|SA_FLAG_COMP_UNSUPP); 193239213Sgibbs softc->filemarks = 0; 193339213Sgibbs 193439213Sgibbs /* 193543636Smjacob * *Very* first off, make sure we're loaded to BOT. 193639213Sgibbs */ 193743636Smjacob scsi_load_unload(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 193854099Smjacob FALSE, FALSE, 1, SSD_FULL_SIZE, REWIND_TIMEOUT); 193954099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1940112006Sphk softc->device_stats); 194153259Smjacob 194243636Smjacob /* 194344354Smjacob * In case this doesn't work, do a REWIND instead 194443636Smjacob */ 194544354Smjacob if (error) { 194653259Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 194753259Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 194854099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1949112006Sphk softc->device_stats); 195043636Smjacob } 195143636Smjacob if (error) { 195243636Smjacob xpt_release_ccb(ccb); 195343636Smjacob goto exit; 195443636Smjacob } 195543636Smjacob 195643636Smjacob /* 195753259Smjacob * Do a dummy test read to force access to the 195853259Smjacob * media so that the drive will really know what's 195954099Smjacob * there. We actually don't really care what the 196054099Smjacob * blocksize on tape is and don't expect to really 196154099Smjacob * read a full record. 196243636Smjacob */ 196339213Sgibbs rblim = (struct scsi_read_block_limits_data *) 1964170830Sscottl malloc(8192, M_SCSISA, M_NOWAIT); 196553259Smjacob if (rblim == NULL) { 1966164906Smjacob xpt_print(periph->path, "no memory for test read\n"); 196753259Smjacob xpt_release_ccb(ccb); 196853259Smjacob error = ENOMEM; 196953259Smjacob goto exit; 197053259Smjacob } 197156981Smjacob 197256981Smjacob if ((softc->quirks & SA_QUIRK_NODREAD) == 0) { 197356981Smjacob scsi_sa_read_write(&ccb->csio, 0, sadone, 197456981Smjacob MSG_SIMPLE_Q_TAG, 1, FALSE, 0, 8192, 197556981Smjacob (void *) rblim, 8192, SSD_FULL_SIZE, 197679100Smjacob IO_TIMEOUT); 197756981Smjacob (void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 1978112006Sphk softc->device_stats); 197956981Smjacob scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 198056981Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 198174840Sken error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, 198274840Sken SF_NO_PRINT | SF_RETRY_UA, 1983112006Sphk softc->device_stats); 198456981Smjacob if (error) { 1985164906Smjacob xpt_print(periph->path, 1986164906Smjacob "unable to rewind after test read\n"); 198756981Smjacob xpt_release_ccb(ccb); 198856981Smjacob goto exit; 198956981Smjacob } 199053259Smjacob } 199139213Sgibbs 199253259Smjacob /* 199353259Smjacob * Next off, determine block limits. 199453259Smjacob */ 199553259Smjacob scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 199679100Smjacob rblim, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 199739213Sgibbs 199874840Sken error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO, 1999112006Sphk SF_NO_PRINT | SF_RETRY_UA, softc->device_stats); 200074840Sken 200139213Sgibbs xpt_release_ccb(ccb); 200239213Sgibbs 200341674Smjacob if (error != 0) { 200441674Smjacob /* 200541674Smjacob * If it's less than SCSI-2, READ BLOCK LIMITS is not 200641674Smjacob * a MANDATORY command. Anyway- it doesn't matter- 200741674Smjacob * we can proceed anyway. 200841674Smjacob */ 200941674Smjacob softc->blk_gran = 0; 201041674Smjacob softc->max_blk = ~0; 201141674Smjacob softc->min_blk = 0; 201241674Smjacob } else { 201374840Sken if (softc->scsi_rev >= SCSI_REV_SPC) { 201441674Smjacob softc->blk_gran = RBL_GRAN(rblim); 201541674Smjacob } else { 201641674Smjacob softc->blk_gran = 0; 201741674Smjacob } 201841674Smjacob /* 201941674Smjacob * We take max_blk == min_blk to mean a default to 202041674Smjacob * fixed mode- but note that whatever we get out of 202141674Smjacob * sagetparams below will actually determine whether 202241674Smjacob * we are actually *in* fixed mode. 202341674Smjacob */ 202441674Smjacob softc->max_blk = scsi_3btoul(rblim->maximum); 202541674Smjacob softc->min_blk = scsi_2btoul(rblim->minimum); 202641674Smjacob 202741674Smjacob 202841674Smjacob } 202941674Smjacob /* 203041674Smjacob * Next, perform a mode sense to determine 203141674Smjacob * current density, blocksize, compression etc. 203241674Smjacob */ 203341674Smjacob error = sagetparams(periph, SA_PARAM_ALL, 203441674Smjacob &softc->media_blksize, 203541674Smjacob &softc->media_density, 203641674Smjacob &softc->media_numblks, 203741674Smjacob &softc->buffer_mode, &write_protect, 203841674Smjacob &softc->speed, &comp_supported, 203941674Smjacob &comp_enabled, &softc->comp_algorithm, 204041674Smjacob NULL); 204141674Smjacob 204241674Smjacob if (error != 0) { 204341674Smjacob /* 204441674Smjacob * We could work a little harder here. We could 204541674Smjacob * adjust our attempts to get information. It 204641674Smjacob * might be an ancient tape drive. If someone 204741674Smjacob * nudges us, we'll do that. 204841674Smjacob */ 204939213Sgibbs goto exit; 205041674Smjacob } 205139213Sgibbs 205241906Smjacob /* 205341906Smjacob * If no quirk has determined that this is a device that is 205441906Smjacob * preferred to be in fixed or variable mode, now is the time 205541906Smjacob * to find out. 205641906Smjacob */ 205741906Smjacob if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) { 205841906Smjacob guessing = 1; 205943636Smjacob /* 206043636Smjacob * This could be expensive to find out. Luckily we 206143636Smjacob * only need to do this once. If we start out in 206243636Smjacob * 'default' mode, try and set ourselves to one 206343636Smjacob * of the densities that would determine a wad 206443636Smjacob * of other stuff. Go from highest to lowest. 206543636Smjacob */ 206643636Smjacob if (softc->media_density == SCSI_DEFAULT_DENSITY) { 206743636Smjacob int i; 206843636Smjacob static u_int8_t ctry[] = { 206943636Smjacob SCSI_DENSITY_HALFINCH_PE, 207043636Smjacob SCSI_DENSITY_HALFINCH_6250C, 207143636Smjacob SCSI_DENSITY_HALFINCH_6250, 207243636Smjacob SCSI_DENSITY_HALFINCH_1600, 207343636Smjacob SCSI_DENSITY_HALFINCH_800, 207446962Smjacob SCSI_DENSITY_QIC_4GB, 207546962Smjacob SCSI_DENSITY_QIC_2GB, 207643636Smjacob SCSI_DENSITY_QIC_525_320, 207743636Smjacob SCSI_DENSITY_QIC_150, 207843636Smjacob SCSI_DENSITY_QIC_120, 207943636Smjacob SCSI_DENSITY_QIC_24, 208043636Smjacob SCSI_DENSITY_QIC_11_9TRK, 208143636Smjacob SCSI_DENSITY_QIC_11_4TRK, 208246962Smjacob SCSI_DENSITY_QIC_1320, 208346962Smjacob SCSI_DENSITY_QIC_3080, 208443636Smjacob 0 208543636Smjacob }; 208643636Smjacob for (i = 0; ctry[i]; i++) { 208743636Smjacob error = sasetparams(periph, 208843636Smjacob SA_PARAM_DENSITY, 0, ctry[i], 208943636Smjacob 0, SF_NO_PRINT); 209043636Smjacob if (error == 0) { 209143636Smjacob softc->media_density = ctry[i]; 209243636Smjacob break; 209343636Smjacob } 209443636Smjacob } 209543636Smjacob } 209641906Smjacob switch (softc->media_density) { 209741906Smjacob case SCSI_DENSITY_QIC_11_4TRK: 209841906Smjacob case SCSI_DENSITY_QIC_11_9TRK: 209941906Smjacob case SCSI_DENSITY_QIC_24: 210041906Smjacob case SCSI_DENSITY_QIC_120: 210141906Smjacob case SCSI_DENSITY_QIC_150: 210265861Smjacob case SCSI_DENSITY_QIC_525_320: 210343636Smjacob case SCSI_DENSITY_QIC_1320: 210443636Smjacob case SCSI_DENSITY_QIC_3080: 210546962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 210643636Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 210741906Smjacob softc->last_media_blksize = 512; 210841906Smjacob break; 210946962Smjacob case SCSI_DENSITY_QIC_4GB: 211046962Smjacob case SCSI_DENSITY_QIC_2GB: 211146962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 211246962Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 211346962Smjacob softc->last_media_blksize = 1024; 211446962Smjacob break; 211541906Smjacob default: 211641906Smjacob softc->last_media_blksize = 211741906Smjacob softc->media_blksize; 211841906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 211941906Smjacob break; 212041906Smjacob } 212141906Smjacob } 212242563Smjacob 212341906Smjacob /* 212441906Smjacob * If no quirk has determined that this is a device that needs 212541906Smjacob * to have 2 Filemarks at EOD, now is the time to find out. 212641906Smjacob */ 212742563Smjacob 212842735Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) { 212941906Smjacob switch (softc->media_density) { 213041906Smjacob case SCSI_DENSITY_HALFINCH_800: 213141906Smjacob case SCSI_DENSITY_HALFINCH_1600: 213241906Smjacob case SCSI_DENSITY_HALFINCH_6250: 213341906Smjacob case SCSI_DENSITY_HALFINCH_6250C: 213441906Smjacob case SCSI_DENSITY_HALFINCH_PE: 213546962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 213641906Smjacob softc->quirks |= SA_QUIRK_2FM; 213741906Smjacob break; 213841906Smjacob default: 213941906Smjacob break; 214041906Smjacob } 214141906Smjacob } 214241906Smjacob 214341906Smjacob /* 214441906Smjacob * Now validate that some info we got makes sense. 214541906Smjacob */ 214641674Smjacob if ((softc->max_blk < softc->media_blksize) || 214741674Smjacob (softc->min_blk > softc->media_blksize && 214841674Smjacob softc->media_blksize)) { 2149164906Smjacob xpt_print(periph->path, 2150164906Smjacob "BLOCK LIMITS (%d..%d) could not match current " 215141674Smjacob "block settings (%d)- adjusting\n", softc->min_blk, 215241674Smjacob softc->max_blk, softc->media_blksize); 215341674Smjacob softc->max_blk = softc->min_blk = 215441674Smjacob softc->media_blksize; 215541674Smjacob } 215641906Smjacob 215741674Smjacob /* 215841906Smjacob * Now put ourselves into the right frame of mind based 215941906Smjacob * upon quirks... 216041906Smjacob */ 216141906Smjacobtryagain: 216242563Smjacob /* 216342563Smjacob * If we want to be in FIXED mode and our current blocksize 216442563Smjacob * is not equal to our last blocksize (if nonzero), try and 216542563Smjacob * set ourselves to this last blocksize (as the 'preferred' 216642563Smjacob * block size). The initial quirkmatch at registry sets the 216742563Smjacob * initial 'last' blocksize. If, for whatever reason, this 216842563Smjacob * 'last' blocksize is zero, set the blocksize to 512, 216942563Smjacob * or min_blk if that's larger. 217042563Smjacob */ 217141906Smjacob if ((softc->quirks & SA_QUIRK_FIXED) && 217260235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0 && 217342563Smjacob (softc->media_blksize != softc->last_media_blksize)) { 217441906Smjacob softc->media_blksize = softc->last_media_blksize; 217541906Smjacob if (softc->media_blksize == 0) { 217642563Smjacob softc->media_blksize = 512; 217741906Smjacob if (softc->media_blksize < softc->min_blk) { 217841906Smjacob softc->media_blksize = softc->min_blk; 217941906Smjacob } 218041906Smjacob } 218141906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 218242563Smjacob softc->media_blksize, 0, 0, SF_NO_PRINT); 218341906Smjacob if (error) { 2184164906Smjacob xpt_print(periph->path, 2185164906Smjacob "unable to set fixed blocksize to %d\n", 2186164906Smjacob softc->media_blksize); 218741906Smjacob goto exit; 218841906Smjacob } 218941906Smjacob } 219041906Smjacob 219141906Smjacob if ((softc->quirks & SA_QUIRK_VARIABLE) && 219241906Smjacob (softc->media_blksize != 0)) { 219341906Smjacob softc->last_media_blksize = softc->media_blksize; 219441906Smjacob softc->media_blksize = 0; 219541906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 219642563Smjacob 0, 0, 0, SF_NO_PRINT); 219741906Smjacob if (error) { 219841906Smjacob /* 219941906Smjacob * If this fails and we were guessing, just 220041906Smjacob * assume that we got it wrong and go try 220142563Smjacob * fixed block mode. Don't even check against 220242563Smjacob * density code at this point. 220341906Smjacob */ 220442563Smjacob if (guessing) { 220541906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 220641906Smjacob softc->quirks |= SA_QUIRK_FIXED; 220741906Smjacob if (softc->last_media_blksize == 0) 220841906Smjacob softc->last_media_blksize = 512; 220941906Smjacob goto tryagain; 221041906Smjacob } 2211164906Smjacob xpt_print(periph->path, 2212164906Smjacob "unable to set variable blocksize\n"); 221341906Smjacob goto exit; 221441906Smjacob } 221541906Smjacob } 221641906Smjacob 221741906Smjacob /* 221841674Smjacob * Now that we have the current block size, 221941674Smjacob * set up some parameters for sastart's usage. 222041674Smjacob */ 222141674Smjacob if (softc->media_blksize) { 222239213Sgibbs softc->flags |= SA_FLAG_FIXED; 222341674Smjacob if (powerof2(softc->media_blksize)) { 222441674Smjacob softc->blk_shift = 222541674Smjacob ffs(softc->media_blksize) - 1; 222641674Smjacob softc->blk_mask = softc->media_blksize - 1; 222739213Sgibbs } else { 222839213Sgibbs softc->blk_mask = ~0; 222939213Sgibbs softc->blk_shift = 0; 223039213Sgibbs } 223139213Sgibbs } else { 223239213Sgibbs /* 223341674Smjacob * The SCSI-3 spec allows 0 to mean "unspecified". 223441674Smjacob * The SCSI-1 spec allows 0 to mean 'infinite'. 223541674Smjacob * 223641674Smjacob * Either works here. 223739213Sgibbs */ 223839213Sgibbs if (softc->max_blk == 0) { 223939213Sgibbs softc->max_blk = ~0; 224039213Sgibbs } 224139213Sgibbs softc->blk_shift = 0; 224239213Sgibbs if (softc->blk_gran != 0) { 224339213Sgibbs softc->blk_mask = softc->blk_gran - 1; 224439213Sgibbs } else { 224539213Sgibbs softc->blk_mask = 0; 224639213Sgibbs } 224739213Sgibbs } 224839213Sgibbs 224939213Sgibbs if (write_protect) 225039213Sgibbs softc->flags |= SA_FLAG_TAPE_WP; 225139213Sgibbs 225239213Sgibbs if (comp_supported) { 225343636Smjacob if (softc->saved_comp_algorithm == 0) 225443636Smjacob softc->saved_comp_algorithm = 225543636Smjacob softc->comp_algorithm; 225646962Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 225746962Smjacob if (comp_enabled) 225846962Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 225939213Sgibbs } else 226039213Sgibbs softc->flags |= SA_FLAG_COMP_UNSUPP; 226139213Sgibbs 226260235Smjacob if ((softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) && 226360235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0) { 226441906Smjacob error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0, 226542563Smjacob 0, 0, SF_NO_PRINT); 226683473Smjacob if (error == 0) { 226741906Smjacob softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF; 226883473Smjacob } else { 2269164906Smjacob xpt_print(periph->path, 2270164906Smjacob "unable to set buffered mode\n"); 227183473Smjacob } 227260235Smjacob error = 0; /* not an error */ 227341906Smjacob } 227439213Sgibbs 227539213Sgibbs 227644354Smjacob if (error == 0) { 227741906Smjacob softc->flags |= SA_FLAG_TAPE_MOUNTED; 227844354Smjacob } 227939213Sgibbsexit: 228039213Sgibbs if (rblim != NULL) 2281169562Sscottl free(rblim, M_SCSISA); 228239213Sgibbs 228343636Smjacob if (error != 0) { 228443636Smjacob softc->dsreg = MTIO_DSREG_NIL; 228544354Smjacob } else { 228644354Smjacob softc->fileno = softc->blkno = 0; 228743636Smjacob softc->dsreg = MTIO_DSREG_REST; 228844354Smjacob } 228951875Smjacob#ifdef SA_1FM_AT_EOD 229051875Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) 229151875Smjacob softc->quirks |= SA_QUIRK_1FM; 229251875Smjacob#else 229346962Smjacob if ((softc->quirks & SA_QUIRK_1FM) == 0) 229443636Smjacob softc->quirks |= SA_QUIRK_2FM; 229543636Smjacob#endif 229639213Sgibbs } else 229739213Sgibbs xpt_release_ccb(ccb); 229839213Sgibbs 229953259Smjacob /* 230053259Smjacob * If we return an error, we're not mounted any more, 230153259Smjacob * so release any device reservation. 230253259Smjacob */ 230353259Smjacob if (error != 0) { 230453259Smjacob (void) sareservereleaseunit(periph, FALSE); 230582575Smjacob } else { 230682575Smjacob /* 230782575Smjacob * Clear I/O residual. 230882575Smjacob */ 230982575Smjacob softc->last_io_resid = 0; 231082575Smjacob softc->last_ctl_resid = 0; 231153259Smjacob } 231254099Smjacob return (error); 231339213Sgibbs} 231439213Sgibbs 231568114Smjacob/* 231668114Smjacob * How many filemarks do we need to write if we were to terminate the 231768114Smjacob * tape session right now? Note that this can be a negative number 231868114Smjacob */ 231968114Smjacob 232039213Sgibbsstatic int 232168114Smjacobsamarkswanted(struct cam_periph *periph) 232239213Sgibbs{ 232339213Sgibbs int markswanted; 232439213Sgibbs struct sa_softc *softc; 232539213Sgibbs 232639213Sgibbs softc = (struct sa_softc *)periph->softc; 232739213Sgibbs markswanted = 0; 232839213Sgibbs if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) { 232939213Sgibbs markswanted++; 233046962Smjacob if (softc->quirks & SA_QUIRK_2FM) 233139213Sgibbs markswanted++; 233239213Sgibbs } 233368114Smjacob markswanted -= softc->filemarks; 233468114Smjacob return (markswanted); 233568114Smjacob} 233639213Sgibbs 233768114Smjacobstatic int 233868114Smjacobsacheckeod(struct cam_periph *periph) 233968114Smjacob{ 234068114Smjacob int error; 234168114Smjacob int markswanted; 234268114Smjacob 234368114Smjacob markswanted = samarkswanted(periph); 234468114Smjacob 234568114Smjacob if (markswanted > 0) { 234641906Smjacob error = sawritefilemarks(periph, markswanted, FALSE); 234739213Sgibbs } else { 234839213Sgibbs error = 0; 234939213Sgibbs } 235039213Sgibbs return (error); 235139213Sgibbs} 235239213Sgibbs 235339213Sgibbsstatic int 235446962Smjacobsaerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) 235539213Sgibbs{ 235646962Smjacob static const char *toobig = 235798449Srobert "%d-byte tape record bigger than supplied buffer\n"; 235839213Sgibbs struct cam_periph *periph; 235939213Sgibbs struct sa_softc *softc; 236039213Sgibbs struct ccb_scsiio *csio; 236139213Sgibbs struct scsi_sense_data *sense; 2362226067Sken uint64_t resid = 0; 2363226067Sken int64_t info = 0; 236482575Smjacob cam_status status; 2365226067Sken int error_code, sense_key, asc, ascq, error, aqvalid, stream_valid; 2366226067Sken int sense_len; 2367226067Sken uint8_t stream_bits; 236839213Sgibbs 236939213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 237039213Sgibbs softc = (struct sa_softc *)periph->softc; 237139213Sgibbs csio = &ccb->csio; 237239213Sgibbs sense = &csio->sense_data; 2373226067Sken sense_len = csio->sense_len - csio->sense_resid; 2374226067Sken scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key, 2375226067Sken &asc, &ascq, /*show_errors*/ 1); 2376226067Sken if (asc != -1 && ascq != -1) 2377226067Sken aqvalid = 1; 2378226067Sken else 2379226067Sken aqvalid = 0; 2380226067Sken if (scsi_get_stream_info(sense, sense_len, NULL, &stream_bits) == 0) 2381226067Sken stream_valid = 1; 2382226067Sken else 2383226067Sken stream_valid = 0; 238439213Sgibbs error = 0; 238546962Smjacob 238682575Smjacob status = csio->ccb_h.status & CAM_STATUS_MASK; 238782575Smjacob 238846962Smjacob /* 238982575Smjacob * Calculate/latch up, any residuals... We do this in a funny 2-step 239082575Smjacob * so we can print stuff here if we have CAM_DEBUG enabled for this 239182575Smjacob * unit. 239246962Smjacob */ 239382575Smjacob if (status == CAM_SCSI_STATUS_ERROR) { 2394226067Sken if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &resid, 2395226067Sken &info) == 0) { 239639213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) 239739213Sgibbs resid *= softc->media_blksize; 239839213Sgibbs } else { 239939213Sgibbs resid = csio->dxfer_len; 240039213Sgibbs info = resid; 240141674Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 240241674Smjacob if (softc->media_blksize) 240341674Smjacob info /= softc->media_blksize; 240441674Smjacob } 240539213Sgibbs } 240671082Smjacob if (CCB_Type(csio) == SA_CCB_BUFFER_IO) { 240741948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense, 240841948Smjacob sizeof (struct scsi_sense_data)); 240942009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb, 241042009Smjacob (int) csio->cdb_len); 241141948Smjacob softc->last_io_resid = resid; 241271268Smjacob softc->last_resid_was_io = 1; 241341948Smjacob } else { 241441948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_ctl_sense, 241541948Smjacob sizeof (struct scsi_sense_data)); 241642009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_ctl_cdb, 241742009Smjacob (int) csio->cdb_len); 241841948Smjacob softc->last_ctl_resid = resid; 241971268Smjacob softc->last_resid_was_io = 0; 242041948Smjacob } 242182575Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x " 2422226067Sken "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %jd " 242382575Smjacob "dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff, 242482575Smjacob sense_key, asc, ascq, status, 2425226067Sken (stream_valid) ? stream_bits : 0, (intmax_t)resid, 2426226067Sken csio->dxfer_len)); 242753259Smjacob } else { 242882575Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 242982575Smjacob ("Cam Status 0x%x\n", status)); 243041948Smjacob } 243141948Smjacob 243282575Smjacob switch (status) { 243382575Smjacob case CAM_REQ_CMP: 243482575Smjacob return (0); 243582575Smjacob case CAM_SCSI_STATUS_ERROR: 243682575Smjacob /* 243782575Smjacob * If a read/write command, we handle it here. 243882575Smjacob */ 243982575Smjacob if (CCB_Type(csio) != SA_CCB_WAITING) { 244082575Smjacob break; 244182575Smjacob } 244282575Smjacob /* 244382575Smjacob * If this was just EOM/EOP, Filemark, Setmark or ILI detected 244482575Smjacob * on a non read/write command, we assume it's not an error 244582575Smjacob * and propagate the residule and return. 244682575Smjacob */ 244782575Smjacob if ((aqvalid && asc == 0 && ascq > 0 && ascq <= 5) || 244882575Smjacob (aqvalid == 0 && sense_key == SSD_KEY_NO_SENSE)) { 244982575Smjacob csio->resid = resid; 245082575Smjacob QFRLS(ccb); 245182575Smjacob return (0); 245282575Smjacob } 245382575Smjacob /* 245482575Smjacob * Otherwise, we let the common code handle this. 245582575Smjacob */ 245646962Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 245741948Smjacob 245846962Smjacob /* 245982575Smjacob * XXX: To Be Fixed 246082575Smjacob * We cannot depend upon CAM honoring retry counts for these. 246146962Smjacob */ 246282575Smjacob case CAM_SCSI_BUS_RESET: 246382575Smjacob case CAM_BDR_SENT: 246482575Smjacob if (ccb->ccb_h.retry_count <= 0) { 246582575Smjacob return (EIO); 246682575Smjacob } 246782575Smjacob /* FALLTHROUGH */ 246882575Smjacob default: 246982575Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 247046962Smjacob } 247146962Smjacob 247246962Smjacob /* 247346962Smjacob * Handle filemark, end of tape, mismatched record sizes.... 247446962Smjacob * From this point out, we're only handling read/write cases. 247546962Smjacob * Handle writes && reads differently. 247646962Smjacob */ 247782575Smjacob 247846962Smjacob if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) { 247982575Smjacob if (sense_key == SSD_KEY_VOLUME_OVERFLOW) { 248039213Sgibbs csio->resid = resid; 248182575Smjacob error = ENOSPC; 2482226067Sken } else if ((stream_valid != 0) && (stream_bits & SSD_EOM)) { 248382575Smjacob softc->flags |= SA_FLAG_EOM_PENDING; 248482575Smjacob /* 248582575Smjacob * Grotesque as it seems, the few times 248682575Smjacob * I've actually seen a non-zero resid, 248782575Smjacob * the tape drive actually lied and had 2488124645Sjohan * written all the data!. 248982575Smjacob */ 249082575Smjacob csio->resid = 0; 249139213Sgibbs } 249246962Smjacob } else { 249382575Smjacob csio->resid = resid; 249446962Smjacob if (sense_key == SSD_KEY_BLANK_CHECK) { 249582575Smjacob if (softc->quirks & SA_QUIRK_1FM) { 249682575Smjacob error = 0; 249746962Smjacob softc->flags |= SA_FLAG_EOM_PENDING; 249846962Smjacob } else { 249946962Smjacob error = EIO; 250046962Smjacob } 2501226067Sken } else if ((stream_valid != 0) && (stream_bits & SSD_FILEMARK)){ 250282575Smjacob if (softc->flags & SA_FLAG_FIXED) { 250346962Smjacob error = -1; 250439213Sgibbs softc->flags |= SA_FLAG_EOF_PENDING; 250546962Smjacob } 250646962Smjacob /* 250746962Smjacob * Unconditionally, if we detected a filemark on a read, 250846962Smjacob * mark that we've run moved a file ahead. 250946962Smjacob */ 251043636Smjacob if (softc->fileno != (daddr_t) -1) { 251143636Smjacob softc->fileno++; 251243636Smjacob softc->blkno = 0; 251371082Smjacob csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED; 251443636Smjacob } 251539213Sgibbs } 251646962Smjacob } 251782575Smjacob 251846962Smjacob /* 251946962Smjacob * Incorrect Length usually applies to read, but can apply to writes. 252046962Smjacob */ 2521226067Sken if (error == 0 && (stream_valid != 0) && (stream_bits & SSD_ILI)) { 252246962Smjacob if (info < 0) { 2523164906Smjacob xpt_print(csio->ccb_h.path, toobig, 2524164906Smjacob csio->dxfer_len - info); 252546962Smjacob csio->resid = csio->dxfer_len; 252646962Smjacob error = EIO; 252746962Smjacob } else { 252846962Smjacob csio->resid = resid; 252982575Smjacob if (softc->flags & SA_FLAG_FIXED) { 253082575Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 253146962Smjacob } 253246962Smjacob /* 253346962Smjacob * Bump the block number if we hadn't seen a filemark. 253446962Smjacob * Do this independent of errors (we've moved anyway). 253546962Smjacob */ 2536226067Sken if ((stream_valid == 0) || 2537226067Sken (stream_bits & SSD_FILEMARK) == 0) { 253846962Smjacob if (softc->blkno != (daddr_t) -1) { 253946962Smjacob softc->blkno++; 254071082Smjacob csio->ccb_h.ccb_pflags |= 254171082Smjacob SA_POSITION_UPDATED; 254239213Sgibbs } 254339213Sgibbs } 254439213Sgibbs } 254539213Sgibbs } 254682575Smjacob 254782575Smjacob if (error <= 0) { 254882575Smjacob /* 254982575Smjacob * Unfreeze the queue if frozen as we're not returning anything 255082575Smjacob * to our waiters that would indicate an I/O error has occurred 255182575Smjacob * (yet). 255282575Smjacob */ 255382575Smjacob QFRLS(ccb); 255482575Smjacob error = 0; 255580575Smjacob } 255682575Smjacob return (error); 255739213Sgibbs} 255839213Sgibbs 255939213Sgibbsstatic int 256039213Sgibbssagetparams(struct cam_periph *periph, sa_params params_to_get, 256139213Sgibbs u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks, 256239213Sgibbs int *buff_mode, u_int8_t *write_protect, u_int8_t *speed, 256339213Sgibbs int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm, 256446962Smjacob sa_comp_t *tcs) 256539213Sgibbs{ 256639213Sgibbs union ccb *ccb; 256739213Sgibbs void *mode_buffer; 256839213Sgibbs struct scsi_mode_header_6 *mode_hdr; 256939213Sgibbs struct scsi_mode_blk_desc *mode_blk; 257039213Sgibbs int mode_buffer_len; 257139213Sgibbs struct sa_softc *softc; 257246962Smjacob u_int8_t cpage; 257339213Sgibbs int error; 257439213Sgibbs cam_status status; 257539213Sgibbs 257639213Sgibbs softc = (struct sa_softc *)periph->softc; 257746962Smjacob ccb = cam_periph_getccb(periph, 1); 257871082Smjacob if (softc->quirks & SA_QUIRK_NO_CPAGE) 257971082Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 258071082Smjacob else 258171082Smjacob cpage = SA_DATA_COMPRESSION_PAGE; 258239213Sgibbs 258339213Sgibbsretry: 258439213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 258539213Sgibbs 258639213Sgibbs if (params_to_get & SA_PARAM_COMPRESSION) { 258739213Sgibbs if (softc->quirks & SA_QUIRK_NOCOMP) { 258839213Sgibbs *comp_supported = FALSE; 258939213Sgibbs params_to_get &= ~SA_PARAM_COMPRESSION; 259039213Sgibbs } else 259146962Smjacob mode_buffer_len += sizeof (sa_comp_t); 259239213Sgibbs } 259354099Smjacob 2594170829Sscottl /* XXX Fix M_NOWAIT */ 2595170829Sscottl mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_NOWAIT | M_ZERO); 2596170829Sscottl if (mode_buffer == NULL) { 2597170829Sscottl xpt_release_ccb(ccb); 2598170829Sscottl return (ENOMEM); 2599170829Sscottl } 260039213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 260139213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 260239213Sgibbs 260342716Smjacob /* it is safe to retry this */ 260442716Smjacob scsi_mode_sense(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 260542716Smjacob SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ? 260646962Smjacob cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len, 260779100Smjacob SSD_FULL_SIZE, SCSIOP_TIMEOUT); 260839213Sgibbs 260954099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 2610112006Sphk softc->device_stats); 261139213Sgibbs 261239213Sgibbs status = ccb->ccb_h.status & CAM_STATUS_MASK; 261339213Sgibbs 261442716Smjacob if (error == EINVAL && (params_to_get & SA_PARAM_COMPRESSION) != 0) { 261539213Sgibbs /* 261646962Smjacob * Hmm. Let's see if we can try another page... 261746962Smjacob * If we've already done that, give up on compression 261846962Smjacob * for this device and remember this for the future 261946962Smjacob * and attempt the request without asking for compression 262046962Smjacob * info. 262139213Sgibbs */ 262246962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 262346962Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 262446962Smjacob goto retry; 262546962Smjacob } 262639213Sgibbs softc->quirks |= SA_QUIRK_NOCOMP; 2627169562Sscottl free(mode_buffer, M_SCSISA); 262839213Sgibbs goto retry; 262946962Smjacob } else if (status == CAM_SCSI_STATUS_ERROR) { 263046962Smjacob /* Tell the user about the fatal error. */ 263146962Smjacob scsi_sense_print(&ccb->csio); 263246962Smjacob goto sagetparamsexit; 263346962Smjacob } 263439213Sgibbs 263546962Smjacob /* 263646962Smjacob * If the user only wants the compression information, and 263746962Smjacob * the device doesn't send back the block descriptor, it's 263846962Smjacob * no big deal. If the user wants more than just 263946962Smjacob * compression, though, and the device doesn't pass back the 264046962Smjacob * block descriptor, we need to send another mode sense to 264146962Smjacob * get the block descriptor. 264246962Smjacob */ 264346962Smjacob if ((mode_hdr->blk_desc_len == 0) && 264446962Smjacob (params_to_get & SA_PARAM_COMPRESSION) && 264546962Smjacob (params_to_get & ~(SA_PARAM_COMPRESSION))) { 264639213Sgibbs 264739213Sgibbs /* 264846962Smjacob * Decrease the mode buffer length by the size of 264946962Smjacob * the compression page, to make sure the data 265046962Smjacob * there doesn't get overwritten. 265139213Sgibbs */ 265246962Smjacob mode_buffer_len -= sizeof (sa_comp_t); 265339213Sgibbs 265446962Smjacob /* 265546962Smjacob * Now move the compression page that we presumably 265646962Smjacob * got back down the memory chunk a little bit so 265746962Smjacob * it doesn't get spammed. 265846962Smjacob */ 265954099Smjacob bcopy(&mode_hdr[0], &mode_hdr[1], sizeof (sa_comp_t)); 266054099Smjacob bzero(&mode_hdr[0], sizeof (mode_hdr[0])); 266139213Sgibbs 266246962Smjacob /* 266346962Smjacob * Now, we issue another mode sense and just ask 266446962Smjacob * for the block descriptor, etc. 266546962Smjacob */ 266639213Sgibbs 266746962Smjacob scsi_mode_sense(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 266846962Smjacob SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE, 266979100Smjacob mode_buffer, mode_buffer_len, SSD_FULL_SIZE, 267079100Smjacob SCSIOP_TIMEOUT); 267139213Sgibbs 267254099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 2673112006Sphk softc->device_stats); 267439213Sgibbs 267546962Smjacob if (error != 0) 267646962Smjacob goto sagetparamsexit; 267746962Smjacob } 267839213Sgibbs 267946962Smjacob if (params_to_get & SA_PARAM_BLOCKSIZE) 268046962Smjacob *blocksize = scsi_3btoul(mode_blk->blklen); 268139213Sgibbs 268246962Smjacob if (params_to_get & SA_PARAM_NUMBLOCKS) 268346962Smjacob *numblocks = scsi_3btoul(mode_blk->nblocks); 268439213Sgibbs 268546962Smjacob if (params_to_get & SA_PARAM_BUFF_MODE) 268646962Smjacob *buff_mode = mode_hdr->dev_spec & SMH_SA_BUF_MODE_MASK; 268739213Sgibbs 268846962Smjacob if (params_to_get & SA_PARAM_DENSITY) 268946962Smjacob *density = mode_blk->density; 269039213Sgibbs 269146962Smjacob if (params_to_get & SA_PARAM_WP) 269246962Smjacob *write_protect = (mode_hdr->dev_spec & SMH_SA_WP)? TRUE : FALSE; 269339213Sgibbs 269446962Smjacob if (params_to_get & SA_PARAM_SPEED) 269546962Smjacob *speed = mode_hdr->dev_spec & SMH_SA_SPEED_MASK; 269639213Sgibbs 269746962Smjacob if (params_to_get & SA_PARAM_COMPRESSION) { 269854099Smjacob sa_comp_t *ntcs = (sa_comp_t *) &mode_blk[1]; 269946962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 270046962Smjacob struct scsi_data_compression_page *cp = &ntcs->dcomp; 270146962Smjacob *comp_supported = 270246962Smjacob (cp->dce_and_dcc & SA_DCP_DCC)? TRUE : FALSE; 270346962Smjacob *comp_enabled = 270446962Smjacob (cp->dce_and_dcc & SA_DCP_DCE)? TRUE : FALSE; 270546962Smjacob *comp_algorithm = scsi_4btoul(cp->comp_algorithm); 270646962Smjacob } else { 270746962Smjacob struct scsi_dev_conf_page *cp = &ntcs->dconf; 270846962Smjacob /* 270946962Smjacob * We don't really know whether this device supports 2710218909Sbrucec * Data Compression if the algorithm field is 271146962Smjacob * zero. Just say we do. 271246962Smjacob */ 271346962Smjacob *comp_supported = TRUE; 271446962Smjacob *comp_enabled = 271546962Smjacob (cp->sel_comp_alg != SA_COMP_NONE)? TRUE : FALSE; 271646962Smjacob *comp_algorithm = cp->sel_comp_alg; 271741906Smjacob } 271846962Smjacob if (tcs != NULL) 271954099Smjacob bcopy(ntcs, tcs, sizeof (sa_comp_t)); 272039213Sgibbs } 272139213Sgibbs 272246962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 272346962Smjacob int idx; 272446962Smjacob char *xyz = mode_buffer; 272546962Smjacob xpt_print_path(periph->path); 272646962Smjacob printf("Mode Sense Data="); 272746962Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 272846962Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 272946962Smjacob printf("\n"); 273046962Smjacob } 273146962Smjacob 273239213Sgibbssagetparamsexit: 273339213Sgibbs 273439213Sgibbs xpt_release_ccb(ccb); 2735169562Sscottl free(mode_buffer, M_SCSISA); 273654099Smjacob return (error); 273739213Sgibbs} 273839213Sgibbs 273939213Sgibbs/* 274039213Sgibbs * The purpose of this function is to set one of four different parameters 274139213Sgibbs * for a tape drive: 274239213Sgibbs * - blocksize 274339213Sgibbs * - density 274439213Sgibbs * - compression / compression algorithm 274539213Sgibbs * - buffering mode 274639213Sgibbs * 274739213Sgibbs * The assumption is that this will be called from saioctl(), and therefore 274839213Sgibbs * from a process context. Thus the waiting malloc calls below. If that 274939213Sgibbs * assumption ever changes, the malloc calls should be changed to be 275039213Sgibbs * NOWAIT mallocs. 275139213Sgibbs * 275239213Sgibbs * Any or all of the four parameters may be set when this function is 275339213Sgibbs * called. It should handle setting more than one parameter at once. 275439213Sgibbs */ 275539213Sgibbsstatic int 275639213Sgibbssasetparams(struct cam_periph *periph, sa_params params_to_set, 275746962Smjacob u_int32_t blocksize, u_int8_t density, u_int32_t calg, 275842563Smjacob u_int32_t sense_flags) 275939213Sgibbs{ 276039213Sgibbs struct sa_softc *softc; 276139213Sgibbs u_int32_t current_blocksize; 276246962Smjacob u_int32_t current_calg; 276339213Sgibbs u_int8_t current_density; 276439213Sgibbs u_int8_t current_speed; 276539213Sgibbs int comp_enabled, comp_supported; 276639213Sgibbs void *mode_buffer; 276739213Sgibbs int mode_buffer_len; 276839213Sgibbs struct scsi_mode_header_6 *mode_hdr; 276939213Sgibbs struct scsi_mode_blk_desc *mode_blk; 277046962Smjacob sa_comp_t *ccomp, *cpage; 277139213Sgibbs int buff_mode; 277246962Smjacob union ccb *ccb = NULL; 277339213Sgibbs int error; 277439213Sgibbs 277539213Sgibbs softc = (struct sa_softc *)periph->softc; 277639213Sgibbs 2777170830Sscottl ccomp = malloc(sizeof (sa_comp_t), M_SCSISA, M_NOWAIT); 2778170830Sscottl if (ccomp == NULL) 2779170830Sscottl return (ENOMEM); 278039213Sgibbs 278139213Sgibbs /* 278239213Sgibbs * Since it doesn't make sense to set the number of blocks, or 278339213Sgibbs * write protection, we won't try to get the current value. We 278439213Sgibbs * always want to get the blocksize, so we can set it back to the 278539213Sgibbs * proper value. 278639213Sgibbs */ 278746962Smjacob error = sagetparams(periph, 278846962Smjacob params_to_set | SA_PARAM_BLOCKSIZE | SA_PARAM_SPEED, 278946962Smjacob ¤t_blocksize, ¤t_density, NULL, &buff_mode, NULL, 279046962Smjacob ¤t_speed, &comp_supported, &comp_enabled, 279146962Smjacob ¤t_calg, ccomp); 279239213Sgibbs 279339213Sgibbs if (error != 0) { 2794169562Sscottl free(ccomp, M_SCSISA); 279554099Smjacob return (error); 279639213Sgibbs } 279739213Sgibbs 279839213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 279939213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 280046962Smjacob mode_buffer_len += sizeof (sa_comp_t); 280139213Sgibbs 2802170830Sscottl mode_buffer = malloc(mode_buffer_len, M_SCSISA, M_NOWAIT | M_ZERO); 2803170830Sscottl if (mode_buffer == NULL) { 2804170830Sscottl free(ccomp, M_SCSISA); 2805170830Sscottl return (ENOMEM); 2806170830Sscottl } 280739213Sgibbs 280839213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 280939213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 281039213Sgibbs 281153259Smjacob ccb = cam_periph_getccb(periph, 1); 281253259Smjacob 281353259Smjacobretry: 281453259Smjacob 281539213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) { 281653259Smjacob if (mode_blk) { 281753259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 281853259Smjacob } else { 281953259Smjacob cpage = (sa_comp_t *)&mode_hdr[1]; 282053259Smjacob } 282146962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 282254099Smjacob cpage->hdr.pagecode &= ~0x80; 282339213Sgibbs } else 282446962Smjacob cpage = NULL; 282539213Sgibbs 282639213Sgibbs /* 282739213Sgibbs * If the caller wants us to set the blocksize, use the one they 282839213Sgibbs * pass in. Otherwise, use the blocksize we got back from the 282939213Sgibbs * mode select above. 283039213Sgibbs */ 283153259Smjacob if (mode_blk) { 283253259Smjacob if (params_to_set & SA_PARAM_BLOCKSIZE) 283353259Smjacob scsi_ulto3b(blocksize, mode_blk->blklen); 283453259Smjacob else 283553259Smjacob scsi_ulto3b(current_blocksize, mode_blk->blklen); 283639213Sgibbs 283753259Smjacob /* 283853259Smjacob * Set density if requested, else preserve old density. 283953259Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 284053259Smjacob * devices, else density we've latched up in our softc. 284153259Smjacob */ 284253259Smjacob if (params_to_set & SA_PARAM_DENSITY) { 284353259Smjacob mode_blk->density = density; 284453259Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 284553259Smjacob mode_blk->density = SCSI_SAME_DENSITY; 284653259Smjacob } else { 284753259Smjacob mode_blk->density = softc->media_density; 284853259Smjacob } 284941674Smjacob } 285039213Sgibbs 285139213Sgibbs /* 285239213Sgibbs * For mode selects, these two fields must be zero. 285339213Sgibbs */ 285439213Sgibbs mode_hdr->data_length = 0; 285539213Sgibbs mode_hdr->medium_type = 0; 285639213Sgibbs 285739213Sgibbs /* set the speed to the current value */ 285839213Sgibbs mode_hdr->dev_spec = current_speed; 285939213Sgibbs 2860120019Smjacob /* if set, set single-initiator buffering mode */ 2861120019Smjacob if (softc->buffer_mode == SMH_SA_BUF_MODE_SIBUF) { 2862120019Smjacob mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF; 2863120019Smjacob } 286439213Sgibbs 286553259Smjacob if (mode_blk) 286653259Smjacob mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc); 286753259Smjacob else 286853259Smjacob mode_hdr->blk_desc_len = 0; 286939213Sgibbs 287039213Sgibbs /* 287139213Sgibbs * First, if the user wants us to set the compression algorithm or 287239213Sgibbs * just turn compression on, check to make sure that this drive 287339213Sgibbs * supports compression. 287439213Sgibbs */ 287546962Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 287639213Sgibbs /* 287739213Sgibbs * If the compression algorithm is 0, disable compression. 287839213Sgibbs * If the compression algorithm is non-zero, enable 287939213Sgibbs * compression and set the compression type to the 288039213Sgibbs * specified compression algorithm, unless the algorithm is 288139213Sgibbs * MT_COMP_ENABLE. In that case, we look at the 288239213Sgibbs * compression algorithm that is currently set and if it is 288339213Sgibbs * non-zero, we leave it as-is. If it is zero, and we have 288439213Sgibbs * saved a compression algorithm from a time when 288539213Sgibbs * compression was enabled before, set the compression to 288639213Sgibbs * the saved value. 288739213Sgibbs */ 288854099Smjacob switch (ccomp->hdr.pagecode & ~0x80) { 2889115660Smjacob case SA_DEVICE_CONFIGURATION_PAGE: 2890115660Smjacob { 2891115660Smjacob struct scsi_dev_conf_page *dcp = &cpage->dconf; 2892115660Smjacob if (calg == 0) { 2893115660Smjacob dcp->sel_comp_alg = SA_COMP_NONE; 2894115660Smjacob break; 2895115660Smjacob } 2896115660Smjacob if (calg != MT_COMP_ENABLE) { 2897115660Smjacob dcp->sel_comp_alg = calg; 2898115660Smjacob } else if (dcp->sel_comp_alg == SA_COMP_NONE && 2899115660Smjacob softc->saved_comp_algorithm != 0) { 2900115660Smjacob dcp->sel_comp_alg = softc->saved_comp_algorithm; 2901115660Smjacob } 2902115660Smjacob break; 2903115660Smjacob } 290446962Smjacob case SA_DATA_COMPRESSION_PAGE: 290546962Smjacob if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) { 290646962Smjacob struct scsi_data_compression_page *dcp = &cpage->dcomp; 290746962Smjacob if (calg == 0) { 290854099Smjacob /* 290954099Smjacob * Disable compression, but leave the 291054099Smjacob * decompression and the capability bit 291154099Smjacob * alone. 291254099Smjacob */ 291354099Smjacob dcp->dce_and_dcc = SA_DCP_DCC; 291454099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 291546962Smjacob break; 291646962Smjacob } 291753259Smjacob /* enable compression && decompression */ 291854099Smjacob dcp->dce_and_dcc = SA_DCP_DCE | SA_DCP_DCC; 291954099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 292053259Smjacob /* 292153259Smjacob * If there, use compression algorithm from caller. 292253259Smjacob * Otherwise, if there's a saved compression algorithm 292353259Smjacob * and there is no current algorithm, use the saved 292453259Smjacob * algorithm. Else parrot back what we got and hope 292553259Smjacob * for the best. 292653259Smjacob */ 292746962Smjacob if (calg != MT_COMP_ENABLE) { 292846962Smjacob scsi_ulto4b(calg, dcp->comp_algorithm); 292953259Smjacob scsi_ulto4b(calg, dcp->decomp_algorithm); 293046962Smjacob } else if (scsi_4btoul(dcp->comp_algorithm) == 0 && 293146962Smjacob softc->saved_comp_algorithm != 0) { 293239213Sgibbs scsi_ulto4b(softc->saved_comp_algorithm, 293346962Smjacob dcp->comp_algorithm); 293453259Smjacob scsi_ulto4b(softc->saved_comp_algorithm, 293553259Smjacob dcp->decomp_algorithm); 293639213Sgibbs } 293746962Smjacob break; 293839213Sgibbs } 2939115660Smjacob /* 2940115660Smjacob * Compression does not appear to be supported- 2941115660Smjacob * at least via the DATA COMPRESSION page. It 2942115660Smjacob * would be too much to ask us to believe that 2943115660Smjacob * the page itself is supported, but incorrectly 2944115660Smjacob * reports an ability to manipulate data compression, 2945115660Smjacob * so we'll assume that this device doesn't support 2946115660Smjacob * compression. We can just fall through for that. 2947115660Smjacob */ 2948115660Smjacob /* FALLTHROUGH */ 294946962Smjacob default: 295046962Smjacob /* 295154099Smjacob * The drive doesn't seem to support compression, 295246962Smjacob * so turn off the set compression bit. 295346962Smjacob */ 295446962Smjacob params_to_set &= ~SA_PARAM_COMPRESSION; 2955164906Smjacob xpt_print(periph->path, 2956164906Smjacob "device does not seem to support compression\n"); 295754099Smjacob 295846962Smjacob /* 295946962Smjacob * If that was the only thing the user wanted us to set, 296046962Smjacob * clean up allocated resources and return with 296146962Smjacob * 'operation not supported'. 296246962Smjacob */ 296346962Smjacob if (params_to_set == SA_PARAM_NONE) { 2964169562Sscottl free(mode_buffer, M_SCSISA); 296554099Smjacob xpt_release_ccb(ccb); 296654099Smjacob return (ENODEV); 296746962Smjacob } 296846962Smjacob 296946962Smjacob /* 297046962Smjacob * That wasn't the only thing the user wanted us to set. 297146962Smjacob * So, decrease the stated mode buffer length by the 297246962Smjacob * size of the compression mode page. 297346962Smjacob */ 297446962Smjacob mode_buffer_len -= sizeof(sa_comp_t); 297546962Smjacob } 297639213Sgibbs } 297739213Sgibbs 297846962Smjacob /* It is safe to retry this operation */ 297946962Smjacob scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 298046962Smjacob (params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE, 298179100Smjacob FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 298241674Smjacob 298346962Smjacob error = cam_periph_runccb(ccb, saerror, 0, 2984112006Sphk sense_flags, softc->device_stats); 298539213Sgibbs 298646962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 298741906Smjacob int idx; 298841674Smjacob char *xyz = mode_buffer; 298941674Smjacob xpt_print_path(periph->path); 299042009Smjacob printf("Err%d, Mode Select Data=", error); 299141906Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 299242009Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 299341674Smjacob printf("\n"); 299441674Smjacob } 299541674Smjacob 299639213Sgibbs 299753259Smjacob if (error) { 299839213Sgibbs /* 299953259Smjacob * If we can, try without setting density/blocksize. 300053259Smjacob */ 300153259Smjacob if (mode_blk) { 300253259Smjacob if ((params_to_set & 300353259Smjacob (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) { 300453259Smjacob mode_blk = NULL; 300553259Smjacob goto retry; 300653259Smjacob } 300753259Smjacob } else { 300853259Smjacob mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 300953259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 301053259Smjacob } 301153259Smjacob 301253259Smjacob /* 301339213Sgibbs * If we were setting the blocksize, and that failed, we 301439213Sgibbs * want to set it to its original value. If we weren't 301539213Sgibbs * setting the blocksize, we don't want to change it. 301639213Sgibbs */ 301739213Sgibbs scsi_ulto3b(current_blocksize, mode_blk->blklen); 301839213Sgibbs 301939213Sgibbs /* 302041674Smjacob * Set density if requested, else preserve old density. 302141674Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 302241674Smjacob * devices, else density we've latched up in our softc. 302339213Sgibbs */ 302441674Smjacob if (params_to_set & SA_PARAM_DENSITY) { 302539213Sgibbs mode_blk->density = current_density; 302641674Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 302741674Smjacob mode_blk->density = SCSI_SAME_DENSITY; 302841674Smjacob } else { 302941674Smjacob mode_blk->density = softc->media_density; 303041674Smjacob } 303139213Sgibbs 303239213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 303346962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 303439213Sgibbs 303539213Sgibbs /* 303639213Sgibbs * The retry count is the only CCB field that might have been 303739213Sgibbs * changed that we care about, so reset it back to 1. 303839213Sgibbs */ 303939213Sgibbs ccb->ccb_h.retry_count = 1; 304054099Smjacob cam_periph_runccb(ccb, saerror, 0, sense_flags, 3041112006Sphk softc->device_stats); 304239213Sgibbs } 304339213Sgibbs 304453259Smjacob xpt_release_ccb(ccb); 304553259Smjacob 304646962Smjacob if (ccomp != NULL) 3047169562Sscottl free(ccomp, M_SCSISA); 304839213Sgibbs 304941948Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 305041948Smjacob if (error) { 305141948Smjacob softc->flags &= ~SA_FLAG_COMP_ENABLED; 305246962Smjacob /* 305346962Smjacob * Even if we get an error setting compression, 305446962Smjacob * do not say that we don't support it. We could 305546962Smjacob * have been wrong, or it may be media specific. 305646962Smjacob * softc->flags &= ~SA_FLAG_COMP_SUPP; 305746962Smjacob */ 305841948Smjacob softc->saved_comp_algorithm = softc->comp_algorithm; 305941948Smjacob softc->comp_algorithm = 0; 306041948Smjacob } else { 306141948Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 306246962Smjacob softc->comp_algorithm = calg; 306341948Smjacob } 306441948Smjacob } 306541948Smjacob 3066169562Sscottl free(mode_buffer, M_SCSISA); 306754099Smjacob return (error); 306839213Sgibbs} 306939213Sgibbs 307039213Sgibbsstatic void 307139213Sgibbssaprevent(struct cam_periph *periph, int action) 307239213Sgibbs{ 307339213Sgibbs struct sa_softc *softc; 307439213Sgibbs union ccb *ccb; 307542735Smjacob int error, sf; 307639213Sgibbs 307739213Sgibbs softc = (struct sa_softc *)periph->softc; 307839213Sgibbs 307942735Smjacob if ((action == PR_ALLOW) && (softc->flags & SA_FLAG_TAPE_LOCKED) == 0) 308039213Sgibbs return; 308142735Smjacob if ((action == PR_PREVENT) && (softc->flags & SA_FLAG_TAPE_LOCKED) != 0) 308242735Smjacob return; 308339213Sgibbs 308456981Smjacob /* 308556981Smjacob * We can be quiet about illegal requests. 308656981Smjacob */ 308756981Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 308842735Smjacob sf = 0; 308956981Smjacob } else 309042735Smjacob sf = SF_QUIET_IR; 309142735Smjacob 309242716Smjacob ccb = cam_periph_getccb(periph, 1); 309339213Sgibbs 309442716Smjacob /* It is safe to retry this operation */ 309542716Smjacob scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action, 309679100Smjacob SSD_FULL_SIZE, SCSIOP_TIMEOUT); 309739213Sgibbs 3098112006Sphk error = cam_periph_runccb(ccb, saerror, 0, sf, softc->device_stats); 309939213Sgibbs if (error == 0) { 310039213Sgibbs if (action == PR_ALLOW) 310139213Sgibbs softc->flags &= ~SA_FLAG_TAPE_LOCKED; 310239213Sgibbs else 310339213Sgibbs softc->flags |= SA_FLAG_TAPE_LOCKED; 310439213Sgibbs } 310539213Sgibbs 310639213Sgibbs xpt_release_ccb(ccb); 310739213Sgibbs} 310839213Sgibbs 310939213Sgibbsstatic int 311039213Sgibbssarewind(struct cam_periph *periph) 311139213Sgibbs{ 311239213Sgibbs union ccb *ccb; 311339213Sgibbs struct sa_softc *softc; 311439213Sgibbs int error; 311539213Sgibbs 311639213Sgibbs softc = (struct sa_softc *)periph->softc; 311739213Sgibbs 311846962Smjacob ccb = cam_periph_getccb(periph, 1); 311939213Sgibbs 312042716Smjacob /* It is safe to retry this operation */ 312146962Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 312253259Smjacob SSD_FULL_SIZE, REWIND_TIMEOUT); 312339213Sgibbs 312443636Smjacob softc->dsreg = MTIO_DSREG_REW; 3125112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 312643636Smjacob softc->dsreg = MTIO_DSREG_REST; 312739213Sgibbs 312839213Sgibbs xpt_release_ccb(ccb); 312943636Smjacob if (error == 0) 313043636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 313143636Smjacob else 313243636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 313339213Sgibbs return (error); 313439213Sgibbs} 313539213Sgibbs 313639213Sgibbsstatic int 313739213Sgibbssaspace(struct cam_periph *periph, int count, scsi_space_code code) 313839213Sgibbs{ 313939213Sgibbs union ccb *ccb; 314039213Sgibbs struct sa_softc *softc; 314139213Sgibbs int error; 314239213Sgibbs 314339213Sgibbs softc = (struct sa_softc *)periph->softc; 314439213Sgibbs 314546962Smjacob ccb = cam_periph_getccb(periph, 1); 314639213Sgibbs 314742716Smjacob /* This cannot be retried */ 314839213Sgibbs 314942716Smjacob scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count, 315053259Smjacob SSD_FULL_SIZE, SPACE_TIMEOUT); 315139213Sgibbs 315271087Smjacob /* 315371087Smjacob * Clear residual because we will be using it. 315471087Smjacob */ 315571087Smjacob softc->last_ctl_resid = 0; 315671087Smjacob 315743636Smjacob softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD; 3158112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 315943636Smjacob softc->dsreg = MTIO_DSREG_REST; 316042716Smjacob 316139213Sgibbs xpt_release_ccb(ccb); 316243636Smjacob 316342716Smjacob /* 316443636Smjacob * If a spacing operation has failed, we need to invalidate 316543636Smjacob * this mount. 316643636Smjacob * 316743636Smjacob * If the spacing operation was setmarks or to end of recorded data, 316843636Smjacob * we no longer know our relative position. 316943636Smjacob * 317071087Smjacob * If the spacing operations was spacing files in reverse, we 317171087Smjacob * take account of the residual, but still check against less 317271087Smjacob * than zero- if we've gone negative, we must have hit BOT. 317371087Smjacob * 317471087Smjacob * If the spacing operations was spacing records in reverse and 317571087Smjacob * we have a residual, we've either hit BOT or hit a filemark. 317671087Smjacob * In the former case, we know our new record number (0). In 317771087Smjacob * the latter case, we have absolutely no idea what the real 317871087Smjacob * record number is- we've stopped between the end of the last 317971087Smjacob * record in the previous file and the filemark that stopped 318071087Smjacob * our spacing backwards. 318142716Smjacob */ 318243636Smjacob if (error) { 318343636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 318443636Smjacob } else if (code == SS_SETMARKS || code == SS_EOD) { 318543636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 318643636Smjacob } else if (code == SS_FILEMARKS && softc->fileno != (daddr_t) -1) { 318771087Smjacob softc->fileno += (count - softc->last_ctl_resid); 318871087Smjacob if (softc->fileno < 0) /* we must of hit BOT */ 318971087Smjacob softc->fileno = 0; 319043636Smjacob softc->blkno = 0; 319143636Smjacob } else if (code == SS_BLOCKS && softc->blkno != (daddr_t) -1) { 319271087Smjacob softc->blkno += (count - softc->last_ctl_resid); 319371087Smjacob if (count < 0) { 319471087Smjacob if (softc->last_ctl_resid || softc->blkno < 0) { 319571087Smjacob if (softc->fileno == 0) { 319671087Smjacob softc->blkno = 0; 319771087Smjacob } else { 319871087Smjacob softc->blkno = (daddr_t) -1; 319971087Smjacob } 320071087Smjacob } 320171087Smjacob } 320243636Smjacob } 320339213Sgibbs return (error); 320439213Sgibbs} 320539213Sgibbs 320639213Sgibbsstatic int 320739213Sgibbssawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks) 320839213Sgibbs{ 320939213Sgibbs union ccb *ccb; 321039213Sgibbs struct sa_softc *softc; 321171087Smjacob int error, nwm = 0; 321239213Sgibbs 321339213Sgibbs softc = (struct sa_softc *)periph->softc; 3214154360Smjacob if (softc->open_rdonly) 3215154360Smjacob return (EBADF); 321639213Sgibbs 321746962Smjacob ccb = cam_periph_getccb(periph, 1); 321871087Smjacob /* 321971087Smjacob * Clear residual because we will be using it. 322071087Smjacob */ 322171087Smjacob softc->last_ctl_resid = 0; 322239213Sgibbs 322343636Smjacob softc->dsreg = MTIO_DSREG_FMK; 322442716Smjacob /* this *must* not be retried */ 322542716Smjacob scsi_write_filemarks(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, 322679100Smjacob FALSE, setmarks, nmarks, SSD_FULL_SIZE, IO_TIMEOUT); 322743636Smjacob softc->dsreg = MTIO_DSREG_REST; 322839213Sgibbs 322943636Smjacob 3230112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 323139213Sgibbs 323241918Smjacob if (error == 0 && nmarks) { 323341918Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 323471087Smjacob nwm = nmarks - softc->last_ctl_resid; 323571087Smjacob softc->filemarks += nwm; 323639213Sgibbs } 323771087Smjacob 323841918Smjacob xpt_release_ccb(ccb); 323943636Smjacob 324043636Smjacob /* 324143636Smjacob * Update relative positions (if we're doing that). 324243636Smjacob */ 324343636Smjacob if (error) { 324443636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 324543636Smjacob } else if (softc->fileno != (daddr_t) -1) { 324671087Smjacob softc->fileno += nwm; 324743636Smjacob softc->blkno = 0; 324843636Smjacob } 324941918Smjacob return (error); 325041918Smjacob} 325139213Sgibbs 325241918Smjacobstatic int 325341918Smjacobsardpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 325441918Smjacob{ 325541918Smjacob struct scsi_tape_position_data loc; 325641918Smjacob union ccb *ccb; 325746962Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 325841918Smjacob int error; 325941918Smjacob 326041918Smjacob /* 326171082Smjacob * We try and flush any buffered writes here if we were writing 326271082Smjacob * and we're trying to get hardware block position. It eats 326371082Smjacob * up performance substantially, but I'm wary of drive firmware. 326446962Smjacob * 326571082Smjacob * I think that *logical* block position is probably okay- 326671082Smjacob * but hardware block position might have to wait for data 326771082Smjacob * to hit media to be valid. Caveat Emptor. 326841918Smjacob */ 326941918Smjacob 327071082Smjacob if (hard && (softc->flags & SA_FLAG_TAPE_WRITTEN)) { 327146962Smjacob error = sawritefilemarks(periph, 0, 0); 327246962Smjacob if (error && error != EACCES) 327346962Smjacob return (error); 327446962Smjacob } 327541918Smjacob 327666678Smjacob ccb = cam_periph_getccb(periph, 1); 327741918Smjacob scsi_read_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 327879100Smjacob hard, &loc, SSD_FULL_SIZE, SCSIOP_TIMEOUT); 327943636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 3280112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 328143636Smjacob softc->dsreg = MTIO_DSREG_REST; 328241918Smjacob 328341918Smjacob if (error == 0) { 328441918Smjacob if (loc.flags & SA_RPOS_UNCERTAIN) { 328541918Smjacob error = EINVAL; /* nothing is certain */ 328641918Smjacob } else { 328741918Smjacob *blkptr = scsi_4btoul(loc.firstblk); 328841918Smjacob } 328941918Smjacob } 329041918Smjacob 329139213Sgibbs xpt_release_ccb(ccb); 329239213Sgibbs return (error); 329339213Sgibbs} 329439213Sgibbs 329539213Sgibbsstatic int 329641918Smjacobsasetpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 329741918Smjacob{ 329841918Smjacob union ccb *ccb; 329941918Smjacob struct sa_softc *softc; 330041918Smjacob int error; 330141918Smjacob 330241918Smjacob /* 330346962Smjacob * We used to try and flush any buffered writes here. 330446962Smjacob * Now we push this onto user applications to either 330546962Smjacob * flush the pending writes themselves (via a zero count 330646962Smjacob * WRITE FILEMARKS command) or they can trust their tape 330746962Smjacob * drive to do this correctly for them. 330846962Smjacob */ 330941918Smjacob 331041918Smjacob softc = (struct sa_softc *)periph->softc; 331146962Smjacob ccb = cam_periph_getccb(periph, 1); 331241918Smjacob 331343636Smjacob 331441918Smjacob scsi_set_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 331579100Smjacob hard, *blkptr, SSD_FULL_SIZE, SPACE_TIMEOUT); 331643636Smjacob 331779100Smjacob 331843636Smjacob softc->dsreg = MTIO_DSREG_POS; 3319112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 332043636Smjacob softc->dsreg = MTIO_DSREG_REST; 332141918Smjacob xpt_release_ccb(ccb); 332241918Smjacob /* 332346962Smjacob * Note relative file && block number position as now unknown. 332441918Smjacob */ 332543636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 332641918Smjacob return (error); 332741918Smjacob} 332841918Smjacob 332941918Smjacobstatic int 333039213Sgibbssaretension(struct cam_periph *periph) 333139213Sgibbs{ 333239213Sgibbs union ccb *ccb; 333339213Sgibbs struct sa_softc *softc; 333439213Sgibbs int error; 333539213Sgibbs 333639213Sgibbs softc = (struct sa_softc *)periph->softc; 333739213Sgibbs 333846962Smjacob ccb = cam_periph_getccb(periph, 1); 333939213Sgibbs 334042716Smjacob /* It is safe to retry this operation */ 334142716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 334253259Smjacob FALSE, TRUE, TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT); 334339213Sgibbs 334443636Smjacob softc->dsreg = MTIO_DSREG_TEN; 3345112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 334643636Smjacob softc->dsreg = MTIO_DSREG_REST; 334739213Sgibbs 334839213Sgibbs xpt_release_ccb(ccb); 334943636Smjacob if (error == 0) 335043636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 335143636Smjacob else 335243636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 335354099Smjacob return (error); 335439213Sgibbs} 335539213Sgibbs 335639213Sgibbsstatic int 335739213Sgibbssareservereleaseunit(struct cam_periph *periph, int reserve) 335839213Sgibbs{ 335939213Sgibbs union ccb *ccb; 336039213Sgibbs struct sa_softc *softc; 336154099Smjacob int error; 336239213Sgibbs 336342009Smjacob softc = (struct sa_softc *)periph->softc; 336442716Smjacob ccb = cam_periph_getccb(periph, 1); 336539213Sgibbs 336642716Smjacob /* It is safe to retry this operation */ 336754099Smjacob scsi_reserve_release_unit(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 336879100Smjacob FALSE, 0, SSD_FULL_SIZE, SCSIOP_TIMEOUT, reserve); 336943636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 337054099Smjacob error = cam_periph_runccb(ccb, saerror, 0, 3371112006Sphk SF_RETRY_UA | SF_NO_PRINT, softc->device_stats); 337243636Smjacob softc->dsreg = MTIO_DSREG_REST; 337339213Sgibbs xpt_release_ccb(ccb); 337439213Sgibbs 337541674Smjacob /* 337641674Smjacob * If the error was Illegal Request, then the device doesn't support 337741674Smjacob * RESERVE/RELEASE. This is not an error. 337841674Smjacob */ 337942009Smjacob if (error == EINVAL) { 338041674Smjacob error = 0; 338142009Smjacob } 338241674Smjacob 338339213Sgibbs return (error); 338439213Sgibbs} 338539213Sgibbs 338639213Sgibbsstatic int 338739213Sgibbssaloadunload(struct cam_periph *periph, int load) 338839213Sgibbs{ 338939213Sgibbs union ccb *ccb; 339039213Sgibbs struct sa_softc *softc; 339139213Sgibbs int error; 339239213Sgibbs 339339213Sgibbs softc = (struct sa_softc *)periph->softc; 339439213Sgibbs 339546962Smjacob ccb = cam_periph_getccb(periph, 1); 339639213Sgibbs 339742716Smjacob /* It is safe to retry this operation */ 339842716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 339954099Smjacob FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT); 340039213Sgibbs 340143636Smjacob softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL; 3402112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 340343636Smjacob softc->dsreg = MTIO_DSREG_REST; 340439213Sgibbs xpt_release_ccb(ccb); 340543636Smjacob 340643636Smjacob if (error || load == 0) 340743636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 340843636Smjacob else if (error == 0) 340943636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 341039213Sgibbs return (error); 341139213Sgibbs} 341239213Sgibbs 341339213Sgibbsstatic int 341439213Sgibbssaerase(struct cam_periph *periph, int longerase) 341539213Sgibbs{ 341639213Sgibbs 341739213Sgibbs union ccb *ccb; 341839213Sgibbs struct sa_softc *softc; 341939213Sgibbs int error; 342039213Sgibbs 342139213Sgibbs softc = (struct sa_softc *)periph->softc; 3422154360Smjacob if (softc->open_rdonly) 3423154360Smjacob return (EBADF); 342439213Sgibbs 342546962Smjacob ccb = cam_periph_getccb(periph, 1); 342639213Sgibbs 342743636Smjacob scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase, 342853259Smjacob SSD_FULL_SIZE, ERASE_TIMEOUT); 342939213Sgibbs 343043636Smjacob softc->dsreg = MTIO_DSREG_ZER; 3431112006Sphk error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats); 343243636Smjacob softc->dsreg = MTIO_DSREG_REST; 343339213Sgibbs 343439213Sgibbs xpt_release_ccb(ccb); 343539213Sgibbs return (error); 343639213Sgibbs} 343739213Sgibbs 343855205Speter#endif /* _KERNEL */ 343939213Sgibbs 344039213Sgibbs/* 344139213Sgibbs * Read tape block limits command. 344239213Sgibbs */ 344339213Sgibbsvoid 344439213Sgibbsscsi_read_block_limits(struct ccb_scsiio *csio, u_int32_t retries, 344539213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 344639213Sgibbs u_int8_t tag_action, 344739213Sgibbs struct scsi_read_block_limits_data *rlimit_buf, 344839213Sgibbs u_int8_t sense_len, u_int32_t timeout) 344939213Sgibbs{ 345039213Sgibbs struct scsi_read_block_limits *scsi_cmd; 345139213Sgibbs 345246962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 345346962Smjacob (u_int8_t *)rlimit_buf, sizeof(*rlimit_buf), sense_len, 345446962Smjacob sizeof(*scsi_cmd), timeout); 345539213Sgibbs 345639213Sgibbs scsi_cmd = (struct scsi_read_block_limits *)&csio->cdb_io.cdb_bytes; 345739213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 345839213Sgibbs scsi_cmd->opcode = READ_BLOCK_LIMITS; 345939213Sgibbs} 346039213Sgibbs 346139213Sgibbsvoid 346239213Sgibbsscsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries, 346339213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 346439213Sgibbs u_int8_t tag_action, int readop, int sli, 346539213Sgibbs int fixed, u_int32_t length, u_int8_t *data_ptr, 346639213Sgibbs u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout) 346739213Sgibbs{ 346839213Sgibbs struct scsi_sa_rw *scsi_cmd; 3469255000Sken int read; 347039213Sgibbs 3471255000Sken read = (readop & SCSI_RW_DIRMASK) == SCSI_RW_READ; 3472255000Sken 347339213Sgibbs scsi_cmd = (struct scsi_sa_rw *)&csio->cdb_io.cdb_bytes; 3474255000Sken scsi_cmd->opcode = read ? SA_READ : SA_WRITE; 347539213Sgibbs scsi_cmd->sli_fixed = 0; 3476255000Sken if (sli && read) 347739213Sgibbs scsi_cmd->sli_fixed |= SAR_SLI; 347839213Sgibbs if (fixed) 347939213Sgibbs scsi_cmd->sli_fixed |= SARW_FIXED; 348039213Sgibbs scsi_ulto3b(length, scsi_cmd->length); 348139213Sgibbs scsi_cmd->control = 0; 348239213Sgibbs 3483255000Sken cam_fill_csio(csio, retries, cbfcnp, (read ? CAM_DIR_IN : CAM_DIR_OUT) | 3484255000Sken ((readop & SCSI_RW_BIO) != 0 ? CAM_DATA_BIO : 0), 348546962Smjacob tag_action, data_ptr, dxfer_len, sense_len, 348646962Smjacob sizeof(*scsi_cmd), timeout); 348739213Sgibbs} 348839213Sgibbs 348939213Sgibbsvoid 349039213Sgibbsscsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries, 349139213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 349239213Sgibbs u_int8_t tag_action, int immediate, int eot, 349339213Sgibbs int reten, int load, u_int8_t sense_len, 349439213Sgibbs u_int32_t timeout) 349539213Sgibbs{ 349639213Sgibbs struct scsi_load_unload *scsi_cmd; 349739213Sgibbs 349839213Sgibbs scsi_cmd = (struct scsi_load_unload *)&csio->cdb_io.cdb_bytes; 349939213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 350039213Sgibbs scsi_cmd->opcode = LOAD_UNLOAD; 350139213Sgibbs if (immediate) 350239213Sgibbs scsi_cmd->immediate = SLU_IMMED; 350339213Sgibbs if (eot) 350439213Sgibbs scsi_cmd->eot_reten_load |= SLU_EOT; 350539213Sgibbs if (reten) 350639213Sgibbs scsi_cmd->eot_reten_load |= SLU_RETEN; 350739213Sgibbs if (load) 350839213Sgibbs scsi_cmd->eot_reten_load |= SLU_LOAD; 350939213Sgibbs 351046962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 351146962Smjacob NULL, 0, sense_len, sizeof(*scsi_cmd), timeout); 351239213Sgibbs} 351339213Sgibbs 351439213Sgibbsvoid 351539213Sgibbsscsi_rewind(struct ccb_scsiio *csio, u_int32_t retries, 351639213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 351739213Sgibbs u_int8_t tag_action, int immediate, u_int8_t sense_len, 351839213Sgibbs u_int32_t timeout) 351939213Sgibbs{ 352039213Sgibbs struct scsi_rewind *scsi_cmd; 352139213Sgibbs 352239213Sgibbs scsi_cmd = (struct scsi_rewind *)&csio->cdb_io.cdb_bytes; 352339213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 352439213Sgibbs scsi_cmd->opcode = REWIND; 352539213Sgibbs if (immediate) 352639213Sgibbs scsi_cmd->immediate = SREW_IMMED; 352739213Sgibbs 352846962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 352946962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 353039213Sgibbs} 353139213Sgibbs 353239213Sgibbsvoid 353339213Sgibbsscsi_space(struct ccb_scsiio *csio, u_int32_t retries, 353439213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 353539213Sgibbs u_int8_t tag_action, scsi_space_code code, 353639213Sgibbs u_int32_t count, u_int8_t sense_len, u_int32_t timeout) 353739213Sgibbs{ 353839213Sgibbs struct scsi_space *scsi_cmd; 353939213Sgibbs 354039213Sgibbs scsi_cmd = (struct scsi_space *)&csio->cdb_io.cdb_bytes; 354139213Sgibbs scsi_cmd->opcode = SPACE; 354239213Sgibbs scsi_cmd->code = code; 354339213Sgibbs scsi_ulto3b(count, scsi_cmd->count); 354439213Sgibbs scsi_cmd->control = 0; 354539213Sgibbs 354646962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 354746962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 354839213Sgibbs} 354939213Sgibbs 355039213Sgibbsvoid 355139213Sgibbsscsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries, 355239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 355339213Sgibbs u_int8_t tag_action, int immediate, int setmark, 355439213Sgibbs u_int32_t num_marks, u_int8_t sense_len, 355539213Sgibbs u_int32_t timeout) 355639213Sgibbs{ 355739213Sgibbs struct scsi_write_filemarks *scsi_cmd; 355839213Sgibbs 355939213Sgibbs scsi_cmd = (struct scsi_write_filemarks *)&csio->cdb_io.cdb_bytes; 356039213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 356139213Sgibbs scsi_cmd->opcode = WRITE_FILEMARKS; 356239213Sgibbs if (immediate) 356339213Sgibbs scsi_cmd->byte2 |= SWFMRK_IMMED; 356439213Sgibbs if (setmark) 356539213Sgibbs scsi_cmd->byte2 |= SWFMRK_WSMK; 356639213Sgibbs 356739213Sgibbs scsi_ulto3b(num_marks, scsi_cmd->num_marks); 356839213Sgibbs 356946962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 357046962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 357139213Sgibbs} 357239213Sgibbs 357339213Sgibbs/* 357439213Sgibbs * The reserve and release unit commands differ only by their opcodes. 357539213Sgibbs */ 357639213Sgibbsvoid 357739213Sgibbsscsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries, 357839213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 357939213Sgibbs u_int8_t tag_action, int third_party, 358039213Sgibbs int third_party_id, u_int8_t sense_len, 358139213Sgibbs u_int32_t timeout, int reserve) 358239213Sgibbs{ 358339213Sgibbs struct scsi_reserve_release_unit *scsi_cmd; 358439213Sgibbs 358539213Sgibbs scsi_cmd = (struct scsi_reserve_release_unit *)&csio->cdb_io.cdb_bytes; 358639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 358739213Sgibbs 358839213Sgibbs if (reserve) 358939213Sgibbs scsi_cmd->opcode = RESERVE_UNIT; 359039213Sgibbs else 359139213Sgibbs scsi_cmd->opcode = RELEASE_UNIT; 359239213Sgibbs 359339213Sgibbs if (third_party) { 359439213Sgibbs scsi_cmd->lun_thirdparty |= SRRU_3RD_PARTY; 359539213Sgibbs scsi_cmd->lun_thirdparty |= 359639213Sgibbs ((third_party_id << SRRU_3RD_SHAMT) & SRRU_3RD_MASK); 359739213Sgibbs } 359839213Sgibbs 359946962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 360046962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 360139213Sgibbs} 360239213Sgibbs 360339213Sgibbsvoid 360439213Sgibbsscsi_erase(struct ccb_scsiio *csio, u_int32_t retries, 360539213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 360639213Sgibbs u_int8_t tag_action, int immediate, int long_erase, 360739213Sgibbs u_int8_t sense_len, u_int32_t timeout) 360839213Sgibbs{ 360939213Sgibbs struct scsi_erase *scsi_cmd; 361039213Sgibbs 361139213Sgibbs scsi_cmd = (struct scsi_erase *)&csio->cdb_io.cdb_bytes; 361239213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 361339213Sgibbs 361439213Sgibbs scsi_cmd->opcode = ERASE; 361539213Sgibbs 361639213Sgibbs if (immediate) 361739213Sgibbs scsi_cmd->lun_imm_long |= SE_IMMED; 361839213Sgibbs 361939213Sgibbs if (long_erase) 362039213Sgibbs scsi_cmd->lun_imm_long |= SE_LONG; 362139213Sgibbs 362246962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 362346962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 362439213Sgibbs} 362541918Smjacob 362641918Smjacob/* 362741918Smjacob * Read Tape Position command. 362841918Smjacob */ 362941918Smjacobvoid 363041918Smjacobscsi_read_position(struct ccb_scsiio *csio, u_int32_t retries, 363141918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 363241918Smjacob u_int8_t tag_action, int hardsoft, 363341918Smjacob struct scsi_tape_position_data *sbp, 363441918Smjacob u_int8_t sense_len, u_int32_t timeout) 363541918Smjacob{ 363641918Smjacob struct scsi_tape_read_position *scmd; 363741918Smjacob 363841918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 363941918Smjacob (u_int8_t *)sbp, sizeof (*sbp), sense_len, sizeof(*scmd), timeout); 364041918Smjacob scmd = (struct scsi_tape_read_position *)&csio->cdb_io.cdb_bytes; 364141918Smjacob bzero(scmd, sizeof(*scmd)); 364241918Smjacob scmd->opcode = READ_POSITION; 364341918Smjacob scmd->byte1 = hardsoft; 364441918Smjacob} 364541918Smjacob 364641918Smjacob/* 364741918Smjacob * Set Tape Position command. 364841918Smjacob */ 364941918Smjacobvoid 365041918Smjacobscsi_set_position(struct ccb_scsiio *csio, u_int32_t retries, 365141918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 365241918Smjacob u_int8_t tag_action, int hardsoft, u_int32_t blkno, 365341918Smjacob u_int8_t sense_len, u_int32_t timeout) 365441918Smjacob{ 365541918Smjacob struct scsi_tape_locate *scmd; 365641918Smjacob 365741918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 365841918Smjacob (u_int8_t *)NULL, 0, sense_len, sizeof(*scmd), timeout); 365941918Smjacob scmd = (struct scsi_tape_locate *)&csio->cdb_io.cdb_bytes; 366041918Smjacob bzero(scmd, sizeof(*scmd)); 366141918Smjacob scmd->opcode = LOCATE; 366241918Smjacob if (hardsoft) 366341918Smjacob scmd->byte1 |= SA_SPOS_BT; 366441918Smjacob scsi_ulto4b(blkno, scmd->blkaddr); 366541918Smjacob} 3666