scsi_sa.c revision 71268
139213Sgibbs/* 250477Speter * $FreeBSD: head/sys/cam/scsi/scsi_sa.c 71268 2001-01-19 21:08:15Z mjacob $ 346962Smjacob * 439213Sgibbs * Implementation of SCSI Sequential Access Peripheral driver for CAM. 539213Sgibbs * 658251Smjacob * Copyright (c) 1999, 2000 Matthew Jacob 739213Sgibbs * All rights reserved. 839213Sgibbs * 939213Sgibbs * Redistribution and use in source and binary forms, with or without 1039213Sgibbs * modification, are permitted provided that the following conditions 1139213Sgibbs * are met: 1239213Sgibbs * 1. Redistributions of source code must retain the above copyright 1339213Sgibbs * notice, this list of conditions, and the following disclaimer, 1439213Sgibbs * without modification, immediately at the beginning of the file. 1539213Sgibbs * 2. The name of the author may not be used to endorse or promote products 1639213Sgibbs * derived from this software without specific prior written permission. 1739213Sgibbs * 1839213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1939213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2039213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2139213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2239213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2339213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2439213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2539213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2639213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2739213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2839213Sgibbs * SUCH DAMAGE. 2939213Sgibbs * 3039213Sgibbs */ 3139213Sgibbs 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> 3960041Sphk#include <sys/bio.h> 4039213Sgibbs#include <sys/malloc.h> 4139213Sgibbs#include <sys/mtio.h> 4265061Speter#ifdef _KERNEL 4339213Sgibbs#include <sys/conf.h> 4465061Speter#endif 4539213Sgibbs#include <sys/devicestat.h> 4639213Sgibbs#include <machine/limits.h> 4739213Sgibbs 4855205Speter#ifndef _KERNEL 4939213Sgibbs#include <stdio.h> 5039213Sgibbs#include <string.h> 5139213Sgibbs#endif 5239213Sgibbs 5339213Sgibbs#include <cam/cam.h> 5439213Sgibbs#include <cam/cam_ccb.h> 5539213Sgibbs#include <cam/cam_extend.h> 5639213Sgibbs#include <cam/cam_periph.h> 5739213Sgibbs#include <cam/cam_xpt_periph.h> 5839213Sgibbs#include <cam/cam_debug.h> 5939213Sgibbs 6039213Sgibbs#include <cam/scsi/scsi_all.h> 6139213Sgibbs#include <cam/scsi/scsi_message.h> 6239213Sgibbs#include <cam/scsi/scsi_sa.h> 6339213Sgibbs 6455205Speter#ifdef _KERNEL 6539213Sgibbs 6639884Sken#include <opt_sa.h> 6739884Sken 6839884Sken#ifndef SA_SPACE_TIMEOUT 6939884Sken#define SA_SPACE_TIMEOUT 1 * 60 7039884Sken#endif 7139884Sken#ifndef SA_REWIND_TIMEOUT 7239884Sken#define SA_REWIND_TIMEOUT 2 * 60 7339884Sken#endif 7439884Sken#ifndef SA_ERASE_TIMEOUT 7539884Sken#define SA_ERASE_TIMEOUT 4 * 60 7639884Sken#endif 7753259Smjacob 7854099Smjacob#define REWIND_TIMEOUT (SA_REWIND_TIMEOUT * 60 * 1000) 7954099Smjacob#define ERASE_TIMEOUT (SA_ERASE_TIMEOUT * 60 * 1000) 8054099Smjacob#define SPACE_TIMEOUT (SA_SPACE_TIMEOUT * 60 * 1000) 8153259Smjacob 8243636Smjacob/* 8351875Smjacob * Additional options that can be set for config: SA_1FM_AT_EOT 8443636Smjacob */ 8553259Smjacob 8641906Smjacob#ifndef UNUSED_PARAMETER 8741906Smjacob#define UNUSED_PARAMETER(x) x = x 8841906Smjacob#endif 8941906Smjacob 9053259Smjacob#define QFRLS(ccb) \ 9153259Smjacob if (((ccb)->ccb_h.status & CAM_DEV_QFRZN) != 0) \ 9253259Smjacob cam_release_devq((ccb)->ccb_h.path, 0, 0, 0, FALSE) 9353259Smjacob 9453259Smjacob/* 9553259Smjacob * Driver states 9653259Smjacob */ 9753259Smjacob 9853259Smjacob 9939213Sgibbstypedef enum { 10046962Smjacob SA_STATE_NORMAL, SA_STATE_ABNORMAL 10139213Sgibbs} sa_state; 10239213Sgibbs 10371082Smjacob#define ccb_pflags ppriv_field0 10471082Smjacob#define ccb_bp ppriv_ptr1 10539213Sgibbs 10671082Smjacob#define SA_CCB_BUFFER_IO 0x0 10771082Smjacob#define SA_CCB_WAITING 0x1 10871082Smjacob#define SA_CCB_TYPEMASK 0x1 10971082Smjacob#define SA_POSITION_UPDATED 0x2 11039213Sgibbs 11171082Smjacob#define Set_CCB_Type(x, type) \ 11271082Smjacob x->ccb_h.ccb_pflags &= ~SA_CCB_TYPEMASK; \ 11371082Smjacob x->ccb_h.ccb_pflags |= type 11471082Smjacob 11571082Smjacob#define CCB_Type(x) (x->ccb_h.ccb_pflags & SA_CCB_TYPEMASK) 11671082Smjacob 11771082Smjacob 11871082Smjacob 11939213Sgibbstypedef enum { 12039213Sgibbs SA_FLAG_OPEN = 0x0001, 12139213Sgibbs SA_FLAG_FIXED = 0x0002, 12239213Sgibbs SA_FLAG_TAPE_LOCKED = 0x0004, 12339213Sgibbs SA_FLAG_TAPE_MOUNTED = 0x0008, 12439213Sgibbs SA_FLAG_TAPE_WP = 0x0010, 12539213Sgibbs SA_FLAG_TAPE_WRITTEN = 0x0020, 12641906Smjacob SA_FLAG_EOM_PENDING = 0x0040, 12741906Smjacob SA_FLAG_EIO_PENDING = 0x0080, 12841906Smjacob SA_FLAG_EOF_PENDING = 0x0100, 12939213Sgibbs SA_FLAG_ERR_PENDING = (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING| 13039213Sgibbs SA_FLAG_EOF_PENDING), 13141906Smjacob SA_FLAG_INVALID = 0x0200, 13241906Smjacob SA_FLAG_COMP_ENABLED = 0x0400, 13346962Smjacob SA_FLAG_COMP_SUPP = 0x0800, 13446962Smjacob SA_FLAG_COMP_UNSUPP = 0x1000, 13546962Smjacob SA_FLAG_TAPE_FROZEN = 0x2000 13639213Sgibbs} sa_flags; 13739213Sgibbs 13839213Sgibbstypedef enum { 13939213Sgibbs SA_MODE_REWIND = 0x00, 14039213Sgibbs SA_MODE_NOREWIND = 0x01, 14139213Sgibbs SA_MODE_OFFLINE = 0x02 14239213Sgibbs} sa_mode; 14339213Sgibbs 14439213Sgibbstypedef enum { 14539213Sgibbs SA_PARAM_NONE = 0x00, 14639213Sgibbs SA_PARAM_BLOCKSIZE = 0x01, 14739213Sgibbs SA_PARAM_DENSITY = 0x02, 14839213Sgibbs SA_PARAM_COMPRESSION = 0x04, 14939213Sgibbs SA_PARAM_BUFF_MODE = 0x08, 15039213Sgibbs SA_PARAM_NUMBLOCKS = 0x10, 15139213Sgibbs SA_PARAM_WP = 0x20, 15239213Sgibbs SA_PARAM_SPEED = 0x40, 15339213Sgibbs SA_PARAM_ALL = 0x7f 15439213Sgibbs} sa_params; 15539213Sgibbs 15639213Sgibbstypedef enum { 15739213Sgibbs SA_QUIRK_NONE = 0x00, 15860235Smjacob SA_QUIRK_NOCOMP = 0x01, /* Can't deal with compression at all */ 15960235Smjacob SA_QUIRK_FIXED = 0x02, /* Force fixed mode */ 16060235Smjacob SA_QUIRK_VARIABLE = 0x04, /* Force variable mode */ 16143636Smjacob SA_QUIRK_2FM = 0x08, /* Needs Two File Marks at EOD */ 16256981Smjacob SA_QUIRK_1FM = 0x10, /* No more than 1 File Mark at EOD */ 16360235Smjacob SA_QUIRK_NODREAD = 0x20, /* Don't try and dummy read density */ 16471082Smjacob SA_QUIRK_NO_MODESEL = 0x40, /* Don't do mode select at all */ 16571082Smjacob SA_QUIRK_NO_CPAGE = 0x80 /* Don't use DEVICE COMPRESSION page */ 16639213Sgibbs} sa_quirks; 16739213Sgibbs 16853283Smjacob/* units are bits 4-7, 16-21 (1024 units) */ 16953283Smjacob#define SAUNIT(DEV) \ 17053283Smjacob (((minor(DEV) & 0xF0) >> 4) | ((minor(DEV) & 0x3f0000) >> 16)) 17153283Smjacob 17253283Smjacob#define SAMODE(z) ((minor(z) & 0x3)) 17353283Smjacob#define SADENSITY(z) (((minor(z) >> 2) & 0x3)) 17453283Smjacob#define SA_IS_CTRL(z) (minor(z) & (1 << 29)) 17553283Smjacob 17653259Smjacob#define SA_NOT_CTLDEV 0 17753259Smjacob#define SA_CTLDEV 1 17853259Smjacob 17953259Smjacob#define SA_ATYPE_R 0 18053259Smjacob#define SA_ATYPE_NR 1 18153259Smjacob#define SA_ATYPE_ER 2 18253259Smjacob 18353259Smjacob#define SAMINOR(ctl, unit, mode, access) \ 18453283Smjacob ((ctl << 29) | ((unit & 0x3f0) << 16) | ((unit & 0xf) << 4) | \ 18553283Smjacob (mode << 0x2) | (access & 0x3)) 18653259Smjacob 18753259Smjacob#define SA_NUM_MODES 4 18853259Smjacobstruct sa_devs { 18953259Smjacob dev_t ctl_dev; 19053259Smjacob struct sa_mode_devs { 19153259Smjacob dev_t r_dev; 19253259Smjacob dev_t nr_dev; 19353259Smjacob dev_t er_dev; 19453259Smjacob } mode_devs[SA_NUM_MODES]; 19553259Smjacob}; 19653259Smjacob 19739213Sgibbsstruct sa_softc { 19839213Sgibbs sa_state state; 19939213Sgibbs sa_flags flags; 20039213Sgibbs sa_quirks quirks; 20159249Sphk struct bio_queue_head bio_queue; 20246962Smjacob int queue_count; 20339213Sgibbs struct devstat device_stats; 20453259Smjacob struct sa_devs devs; 20539213Sgibbs int blk_gran; 20639213Sgibbs int blk_mask; 20739213Sgibbs int blk_shift; 20839213Sgibbs u_int32_t max_blk; 20939213Sgibbs u_int32_t min_blk; 21041674Smjacob u_int32_t comp_algorithm; 21141674Smjacob u_int32_t saved_comp_algorithm; 21239213Sgibbs u_int32_t media_blksize; 21341906Smjacob u_int32_t last_media_blksize; 21439213Sgibbs u_int32_t media_numblks; 21541674Smjacob u_int8_t media_density; 21639213Sgibbs u_int8_t speed; 21741674Smjacob u_int8_t scsi_rev; 21843636Smjacob u_int8_t dsreg; /* mtio mt_dsreg, redux */ 21939213Sgibbs int buffer_mode; 22039213Sgibbs int filemarks; 22139213Sgibbs union ccb saved_ccb; 22271268Smjacob int last_resid_was_io; 22346962Smjacob 22441948Smjacob /* 22543636Smjacob * Relative to BOT Location. 22643636Smjacob */ 22743636Smjacob daddr_t fileno; 22843636Smjacob daddr_t blkno; 22943636Smjacob 23043636Smjacob /* 23141948Smjacob * Latched Error Info 23241948Smjacob */ 23342009Smjacob struct { 23442009Smjacob struct scsi_sense_data _last_io_sense; 23542009Smjacob u_int32_t _last_io_resid; 23642009Smjacob u_int8_t _last_io_cdb[CAM_MAX_CDBLEN]; 23742009Smjacob struct scsi_sense_data _last_ctl_sense; 23842009Smjacob u_int32_t _last_ctl_resid; 23942009Smjacob u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN]; 24042009Smjacob#define last_io_sense errinfo._last_io_sense 24142009Smjacob#define last_io_resid errinfo._last_io_resid 24242009Smjacob#define last_io_cdb errinfo._last_io_cdb 24342009Smjacob#define last_ctl_sense errinfo._last_ctl_sense 24442009Smjacob#define last_ctl_resid errinfo._last_ctl_resid 24542009Smjacob#define last_ctl_cdb errinfo._last_ctl_cdb 24642009Smjacob } errinfo; 24743636Smjacob /* 24843636Smjacob * Misc other flags/state 24943636Smjacob */ 25043636Smjacob u_int32_t 25143636Smjacob : 31, 25243636Smjacob ctrl_mode : 1; /* control device open */ 25339213Sgibbs}; 25439213Sgibbs 25539213Sgibbsstruct sa_quirk_entry { 25642563Smjacob struct scsi_inquiry_pattern inq_pat; /* matching pattern */ 25742563Smjacob sa_quirks quirks; /* specific quirk type */ 25842563Smjacob u_int32_t prefblk; /* preferred blocksize when in fixed mode */ 25939213Sgibbs}; 26039213Sgibbs 26139213Sgibbsstatic struct sa_quirk_entry sa_quirk_table[] = 26239213Sgibbs{ 26339213Sgibbs { 26460235Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "OnStream", 26560235Smjacob "ADR*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_NODREAD | 26660235Smjacob SA_QUIRK_1FM|SA_QUIRK_NO_MODESEL, 32768 26760235Smjacob }, 26860235Smjacob { 26939213Sgibbs { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 27056981Smjacob "Python 25601*", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_NODREAD, 0 27141351Sjoerg }, 27241351Sjoerg { 27342130Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 27456981Smjacob "Python*", "*"}, SA_QUIRK_NODREAD, 0 27556981Smjacob }, 27656981Smjacob { 27756981Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 27843636Smjacob "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 27942130Smjacob }, 28042130Smjacob { 28142563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28268500Smjacob "VIPER 2525 25462", "-011"}, 28368500Smjacob SA_QUIRK_NOCOMP|SA_QUIRK_1FM|SA_QUIRK_NODREAD, 0 28468500Smjacob }, 28568500Smjacob { 28668500Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", 28746962Smjacob "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 28842563Smjacob }, 28971082Smjacob#if 0 29042563Smjacob { 29142533Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 29271082Smjacob "C15*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_NO_CPAGE, 0, 29371082Smjacob }, 29471082Smjacob#endif 29571082Smjacob { 29671082Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 29746962Smjacob "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 29846962Smjacob }, 29946962Smjacob { 30046962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 30144354Smjacob "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 30242533Smjacob }, 30342533Smjacob { 30442716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", 30542716Smjacob "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 30642716Smjacob }, 30742716Smjacob { 30842716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", 30942716Smjacob "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 31042716Smjacob }, 31142716Smjacob { 31242716Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA", 31342716Smjacob "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 31442716Smjacob }, 31551744Smjacob { /* jreynold@primenet.com */ 31651744Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 31751744Smjacob "STT8000N*", "*"}, SA_QUIRK_1FM, 0 31851744Smjacob }, 31951875Smjacob { /* mike@sentex.net */ 32051875Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate", 32151875Smjacob "STT20000*", "*"}, SA_QUIRK_1FM, 0 32251875Smjacob }, 32342716Smjacob { 32441351Sjoerg { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 32543636Smjacob " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 32642563Smjacob }, 32742563Smjacob { 32842563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 32947519Smjacob " TDC 3800", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 33047519Smjacob }, 33147519Smjacob { 33247519Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 33348192Smjacob " TDC 4100", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 33448192Smjacob }, 33548192Smjacob { 33648192Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 33743636Smjacob " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 33842563Smjacob }, 33942563Smjacob { 34046962Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 34146962Smjacob " SLR*", "*"}, SA_QUIRK_1FM, 0 34246962Smjacob }, 34346962Smjacob { 34442563Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 34543636Smjacob "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 34645752Smjacob }, 34745752Smjacob { 34845752Smjacob { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", 34945752Smjacob "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 35039213Sgibbs } 35139213Sgibbs}; 35239213Sgibbs 35339213Sgibbsstatic d_open_t saopen; 35439213Sgibbsstatic d_close_t saclose; 35539213Sgibbsstatic d_strategy_t sastrategy; 35639213Sgibbsstatic d_ioctl_t saioctl; 35739213Sgibbsstatic periph_init_t sainit; 35839213Sgibbsstatic periph_ctor_t saregister; 35940603Skenstatic periph_oninv_t saoninvalidate; 36039213Sgibbsstatic periph_dtor_t sacleanup; 36139213Sgibbsstatic periph_start_t sastart; 36239213Sgibbsstatic void saasync(void *callback_arg, u_int32_t code, 36339213Sgibbs struct cam_path *path, void *arg); 36439213Sgibbsstatic void sadone(struct cam_periph *periph, 36539213Sgibbs union ccb *start_ccb); 36639213Sgibbsstatic int saerror(union ccb *ccb, u_int32_t cam_flags, 36739213Sgibbs u_int32_t sense_flags); 36868114Smjacobstatic int samarkswanted(struct cam_periph *); 36939213Sgibbsstatic int sacheckeod(struct cam_periph *periph); 37039213Sgibbsstatic int sagetparams(struct cam_periph *periph, 37139213Sgibbs sa_params params_to_get, 37239213Sgibbs u_int32_t *blocksize, u_int8_t *density, 37339213Sgibbs u_int32_t *numblocks, int *buff_mode, 37439213Sgibbs u_int8_t *write_protect, u_int8_t *speed, 37539213Sgibbs int *comp_supported, int *comp_enabled, 37639213Sgibbs u_int32_t *comp_algorithm, 37746962Smjacob sa_comp_t *comp_page); 37839213Sgibbsstatic int sasetparams(struct cam_periph *periph, 37939213Sgibbs sa_params params_to_set, 38039213Sgibbs u_int32_t blocksize, u_int8_t density, 38142563Smjacob u_int32_t comp_algorithm, 38242563Smjacob u_int32_t sense_flags); 38339213Sgibbsstatic void saprevent(struct cam_periph *periph, int action); 38439213Sgibbsstatic int sarewind(struct cam_periph *periph); 38539213Sgibbsstatic int saspace(struct cam_periph *periph, int count, 38639213Sgibbs scsi_space_code code); 38741906Smjacobstatic int samount(struct cam_periph *, int, dev_t); 38839213Sgibbsstatic int saretension(struct cam_periph *periph); 38939213Sgibbsstatic int sareservereleaseunit(struct cam_periph *periph, 39039213Sgibbs int reserve); 39139213Sgibbsstatic int saloadunload(struct cam_periph *periph, int load); 39239213Sgibbsstatic int saerase(struct cam_periph *periph, int longerase); 39339213Sgibbsstatic int sawritefilemarks(struct cam_periph *periph, 39439213Sgibbs int nmarks, int setmarks); 39541918Smjacobstatic int sardpos(struct cam_periph *periph, int, u_int32_t *); 39641918Smjacobstatic int sasetpos(struct cam_periph *periph, int, u_int32_t *); 39739213Sgibbs 39841918Smjacob 39939213Sgibbsstatic struct periph_driver sadriver = 40039213Sgibbs{ 40139213Sgibbs sainit, "sa", 40239213Sgibbs TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0 40339213Sgibbs}; 40439213Sgibbs 40539213SgibbsDATA_SET(periphdriver_set, sadriver); 40639213Sgibbs 40739213Sgibbs/* For 2.2-stable support */ 40839213Sgibbs#ifndef D_TAPE 40939213Sgibbs#define D_TAPE 0 41039213Sgibbs#endif 41139213Sgibbs 41239213Sgibbs#define SA_CDEV_MAJOR 14 41339213Sgibbs 41447625Sphkstatic struct cdevsw sa_cdevsw = { 41547625Sphk /* open */ saopen, 41647625Sphk /* close */ saclose, 41747625Sphk /* read */ physread, 41847625Sphk /* write */ physwrite, 41947625Sphk /* ioctl */ saioctl, 42047625Sphk /* poll */ nopoll, 42147625Sphk /* mmap */ nommap, 42247625Sphk /* strategy */ sastrategy, 42347625Sphk /* name */ "sa", 42447625Sphk /* maj */ SA_CDEV_MAJOR, 42547625Sphk /* dump */ nodump, 42647625Sphk /* psize */ nopsize, 42747625Sphk /* flags */ D_TAPE, 42851092Sphk /* bmaj */ -1 42939213Sgibbs}; 43039213Sgibbs 43139213Sgibbsstatic struct extend_array *saperiphs; 43239213Sgibbs 43339213Sgibbsstatic int 43439213Sgibbssaopen(dev_t dev, int flags, int fmt, struct proc *p) 43539213Sgibbs{ 43639213Sgibbs struct cam_periph *periph; 43739213Sgibbs struct sa_softc *softc; 43839213Sgibbs int unit; 43939213Sgibbs int mode; 44039213Sgibbs int density; 44139213Sgibbs int error; 44240603Sken int s; 44339213Sgibbs 44439213Sgibbs unit = SAUNIT(dev); 44539213Sgibbs mode = SAMODE(dev); 44639213Sgibbs density = SADENSITY(dev); 44739213Sgibbs 44853259Smjacob s = splsoftcam(); 44939213Sgibbs periph = cam_extend_get(saperiphs, unit); 45053259Smjacob if (periph == NULL) { 45153259Smjacob (void) splx(s); 45239213Sgibbs return (ENXIO); 45353259Smjacob } 45439213Sgibbs softc = (struct sa_softc *)periph->softc; 45553259Smjacob if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 45653259Smjacob splx(s); 45753259Smjacob return (error); 45853259Smjacob } 45953259Smjacob splx(s); 46039213Sgibbs 46146962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 46246962Smjacob ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); 46339213Sgibbs 46453259Smjacob if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 46553259Smjacob cam_periph_unlock(periph); 46654099Smjacob return (ENXIO); 46753259Smjacob } 46843636Smjacob if (SA_IS_CTRL(dev)) { 46943636Smjacob softc->ctrl_mode = 1; 47053259Smjacob cam_periph_unlock(periph); 47143636Smjacob return (0); 47243636Smjacob } 47343636Smjacob 47439213Sgibbs 47553259Smjacob if (softc->flags & SA_FLAG_OPEN) { 47653259Smjacob error = EBUSY; 47753259Smjacob } else if (softc->flags & SA_FLAG_INVALID) { 47853259Smjacob error = ENXIO; 47953259Smjacob } else { 48053259Smjacob /* 48153259Smjacob * The function samount ensures media is loaded and ready. 48253259Smjacob * It also does a device RESERVE if the tape isn't yet mounted. 48353259Smjacob */ 48453259Smjacob error = samount(periph, flags, dev); 48539213Sgibbs } 48639213Sgibbs 48753259Smjacob if (error) { 48853259Smjacob cam_periph_release(periph); 48953259Smjacob } else { 49039213Sgibbs saprevent(periph, PR_PREVENT); 49139213Sgibbs softc->flags |= SA_FLAG_OPEN; 49239213Sgibbs } 49339213Sgibbs cam_periph_unlock(periph); 49439213Sgibbs return (error); 49539213Sgibbs} 49639213Sgibbs 49739213Sgibbsstatic int 49839213Sgibbssaclose(dev_t dev, int flag, int fmt, struct proc *p) 49939213Sgibbs{ 50039213Sgibbs struct cam_periph *periph; 50139213Sgibbs struct sa_softc *softc; 50246962Smjacob int unit, mode, error, writing, tmp; 50342009Smjacob int closedbits = SA_FLAG_OPEN; 50439213Sgibbs 50539213Sgibbs unit = SAUNIT(dev); 50639213Sgibbs mode = SAMODE(dev); 50739213Sgibbs periph = cam_extend_get(saperiphs, unit); 50839213Sgibbs if (periph == NULL) 50939213Sgibbs return (ENXIO); 51039213Sgibbs 51139213Sgibbs softc = (struct sa_softc *)periph->softc; 51239213Sgibbs 51346962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, 51446962Smjacob ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); 51546962Smjacob 51646962Smjacob 51753259Smjacob if ((error = cam_periph_lock(periph, PRIBIO)) != 0) { 51853259Smjacob return (error); 51953259Smjacob } 52053259Smjacob 52143636Smjacob if (SA_IS_CTRL(dev)) { 52243636Smjacob softc->ctrl_mode = 0; 52353259Smjacob cam_periph_release(periph); 52453259Smjacob cam_periph_unlock(periph); 52543636Smjacob return (0); 52643636Smjacob } 52743636Smjacob 52841906Smjacob /* 52946962Smjacob * Were we writing the tape? 53041906Smjacob */ 53146962Smjacob writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0; 53246962Smjacob 53346962Smjacob /* 53446962Smjacob * See whether or not we need to write filemarks. If this 53546962Smjacob * fails, we probably have to assume we've lost tape 53646962Smjacob * position. 53746962Smjacob */ 53841906Smjacob error = sacheckeod(periph); 53941906Smjacob if (error) { 54041906Smjacob xpt_print_path(periph->path); 54146962Smjacob printf("failed to write terminating filemark(s)\n"); 54246962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 54341906Smjacob } 54439213Sgibbs 54541906Smjacob /* 54641906Smjacob * Whatever we end up doing, allow users to eject tapes from here on. 54741906Smjacob */ 54839213Sgibbs saprevent(periph, PR_ALLOW); 54939213Sgibbs 55041906Smjacob /* 55141906Smjacob * Decide how to end... 55241906Smjacob */ 55353522Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 55453522Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 55553522Smjacob } else switch (mode) { 55639213Sgibbs case SA_MODE_OFFLINE: 55746962Smjacob /* 55846962Smjacob * An 'offline' close is an unconditional release of 55946962Smjacob * frozen && mount conditions, irrespective of whether 56046962Smjacob * these operations succeeded. The reason for this is 56146962Smjacob * to allow at least some kind of programmatic way 56246962Smjacob * around our state getting all fouled up. If somebody 56346962Smjacob * issues an 'offline' command, that will be allowed 56446962Smjacob * to clear state. 56546962Smjacob */ 56646962Smjacob (void) sarewind(periph); 56746962Smjacob (void) saloadunload(periph, FALSE); 56846962Smjacob closedbits |= SA_FLAG_TAPE_MOUNTED|SA_FLAG_TAPE_FROZEN; 56939213Sgibbs break; 57041906Smjacob case SA_MODE_REWIND: 57146962Smjacob /* 57246962Smjacob * If the rewind fails, return an error- if anyone cares, 57346962Smjacob * but not overwriting any previous error. 57446962Smjacob * 57546962Smjacob * We don't clear the notion of mounted here, but we do 57646962Smjacob * clear the notion of frozen if we successfully rewound. 57746962Smjacob */ 57846962Smjacob tmp = sarewind(periph); 57946962Smjacob if (tmp) { 58046962Smjacob if (error != 0) 58146962Smjacob error = tmp; 58246962Smjacob } else { 58346962Smjacob closedbits |= SA_FLAG_TAPE_FROZEN; 58446962Smjacob } 58541906Smjacob break; 58639213Sgibbs case SA_MODE_NOREWIND: 58741906Smjacob /* 58841906Smjacob * If we're not rewinding/unloading the tape, find out 58941906Smjacob * whether we need to back up over one of two filemarks 59041906Smjacob * we wrote (if we wrote two filemarks) so that appends 59141906Smjacob * from this point on will be sane. 59241906Smjacob */ 59346962Smjacob if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) { 59446962Smjacob tmp = saspace(periph, -1, SS_FILEMARKS); 59546962Smjacob if (tmp) { 59641906Smjacob xpt_print_path(periph->path); 59741906Smjacob printf("unable to backspace over one of double" 59846962Smjacob " filemarks at end of tape\n"); 59946962Smjacob xpt_print_path(periph->path); 60051744Smjacob printf("it is possible that this device" 60146962Smjacob " needs a SA_QUIRK_1FM quirk set for it\n"); 60246962Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 60341906Smjacob } 60441906Smjacob } 60539213Sgibbs break; 60646962Smjacob default: 60746962Smjacob xpt_print_path(periph->path); 60846962Smjacob panic("unknown mode 0x%x in saclose\n", mode); 60946962Smjacob /* NOTREACHED */ 61046962Smjacob break; 61139213Sgibbs } 61239213Sgibbs 61341906Smjacob /* 61441948Smjacob * We wish to note here that there are no more filemarks to be written. 61541906Smjacob */ 61641906Smjacob softc->filemarks = 0; 61741948Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 61841906Smjacob 61941906Smjacob /* 62041906Smjacob * And we are no longer open for business. 62141906Smjacob */ 62242009Smjacob softc->flags &= ~closedbits; 62346962Smjacob 62446962Smjacob /* 62546962Smjacob * Inform users if tape state if frozen.... 62646962Smjacob */ 62746962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 62846962Smjacob xpt_print_path(periph->path); 62946962Smjacob printf("tape is now frozen- use an OFFLINE, REWIND or MTEOM " 63046962Smjacob "command to clear this state.\n"); 63146962Smjacob } 63239213Sgibbs 63353259Smjacob /* release the device if it is no longer mounted */ 63453259Smjacob if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) 63553259Smjacob sareservereleaseunit(periph, FALSE); 63639213Sgibbs 63739213Sgibbs cam_periph_unlock(periph); 63839213Sgibbs cam_periph_release(periph); 63939213Sgibbs 64046962Smjacob return (error); 64139213Sgibbs} 64239213Sgibbs 64339213Sgibbs/* 64439213Sgibbs * Actually translate the requested transfer into one the physical driver 64539213Sgibbs * can understand. The transfer is described by a buf and will include 64639213Sgibbs * only one physical transfer. 64739213Sgibbs */ 64839213Sgibbsstatic void 64959249Sphksastrategy(struct bio *bp) 65039213Sgibbs{ 65139213Sgibbs struct cam_periph *periph; 65239213Sgibbs struct sa_softc *softc; 65339213Sgibbs u_int unit; 65439213Sgibbs int s; 65539213Sgibbs 65659249Sphk if (SA_IS_CTRL(bp->bio_dev)) { 65759249Sphk bp->bio_error = EINVAL; 65843636Smjacob goto bad; 65943636Smjacob } 66059249Sphk unit = SAUNIT(bp->bio_dev); 66139213Sgibbs periph = cam_extend_get(saperiphs, unit); 66239213Sgibbs if (periph == NULL) { 66359249Sphk bp->bio_error = ENXIO; 66439213Sgibbs goto bad; 66539213Sgibbs } 66639213Sgibbs softc = (struct sa_softc *)periph->softc; 66739213Sgibbs 66840603Sken s = splsoftcam(); 66940603Sken 67040603Sken if (softc->flags & SA_FLAG_INVALID) { 67140603Sken splx(s); 67259249Sphk bp->bio_error = ENXIO; 67340603Sken goto bad; 67440603Sken } 67540603Sken 67646962Smjacob if (softc->flags & SA_FLAG_TAPE_FROZEN) { 67746962Smjacob splx(s); 67859249Sphk bp->bio_error = EPERM; 67946962Smjacob goto bad; 68046962Smjacob } 68146962Smjacob 68240603Sken splx(s); 68340603Sken 68439213Sgibbs /* 68539213Sgibbs * If it's a null transfer, return immediatly 68639213Sgibbs */ 68759249Sphk if (bp->bio_bcount == 0) 68839213Sgibbs goto done; 68939213Sgibbs 69039213Sgibbs /* valid request? */ 69139213Sgibbs if (softc->flags & SA_FLAG_FIXED) { 69239213Sgibbs /* 69339213Sgibbs * Fixed block device. The byte count must 69439213Sgibbs * be a multiple of our block size. 69539213Sgibbs */ 69642716Smjacob if (((softc->blk_mask != ~0) && 69759249Sphk ((bp->bio_bcount & softc->blk_mask) != 0)) || 69842716Smjacob ((softc->blk_mask == ~0) && 69959249Sphk ((bp->bio_bcount % softc->min_blk) != 0))) { 70039213Sgibbs xpt_print_path(periph->path); 70139213Sgibbs printf("Invalid request. Fixed block device " 70239213Sgibbs "requests must be a multiple " 70339213Sgibbs "of %d bytes\n", softc->min_blk); 70459249Sphk bp->bio_error = EINVAL; 70539213Sgibbs goto bad; 70639213Sgibbs } 70759249Sphk } else if ((bp->bio_bcount > softc->max_blk) || 70859249Sphk (bp->bio_bcount < softc->min_blk) || 70959249Sphk (bp->bio_bcount & softc->blk_mask) != 0) { 71039213Sgibbs 71139213Sgibbs xpt_print_path(periph->path); 71239213Sgibbs printf("Invalid request. Variable block device " 71342716Smjacob "requests must be "); 71439213Sgibbs if (softc->blk_mask != 0) { 71542716Smjacob printf("a multiple of %d ", (0x1 << softc->blk_gran)); 71639213Sgibbs } 71742716Smjacob printf("between %d and %d bytes\n", softc->min_blk, 71842716Smjacob softc->max_blk); 71959249Sphk bp->bio_error = EINVAL; 72039213Sgibbs goto bad; 72139213Sgibbs } 72239213Sgibbs 72339213Sgibbs /* 72442716Smjacob * Mask interrupts so that the device cannot be invalidated until 72539213Sgibbs * after we are in the queue. Otherwise, we might not properly 72639213Sgibbs * clean up one of the buffers. 72739213Sgibbs */ 72839213Sgibbs s = splbio(); 72939213Sgibbs 73039213Sgibbs /* 73142716Smjacob * Place it at the end of the queue. 73239213Sgibbs */ 73359249Sphk bioq_insert_tail(&softc->bio_queue, bp); 73439213Sgibbs 73546962Smjacob softc->queue_count++; 73646962Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("sastrategy: enqueuing a %d " 73759249Sphk "%s byte %s queue count now %d\n", (int) bp->bio_bcount, 73846962Smjacob (softc->flags & SA_FLAG_FIXED)? "fixed" : "variable", 73959249Sphk (bp->bio_cmd == BIO_READ)? "read" : "write", softc->queue_count)); 74046962Smjacob 74139213Sgibbs splx(s); 74239213Sgibbs 74339213Sgibbs /* 74439213Sgibbs * Schedule ourselves for performing the work. 74539213Sgibbs */ 74642716Smjacob xpt_schedule(periph, 1); 74739213Sgibbs 74839213Sgibbs return; 74939213Sgibbsbad: 75059249Sphk bp->bio_flags |= BIO_ERROR; 75139213Sgibbsdone: 75239213Sgibbs 75339213Sgibbs /* 75439213Sgibbs * Correctly set the buf to indicate a completed xfer 75539213Sgibbs */ 75659249Sphk bp->bio_resid = bp->bio_bcount; 75739213Sgibbs biodone(bp); 75839213Sgibbs} 75939213Sgibbs 76039213Sgibbsstatic int 76139213Sgibbssaioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) 76239213Sgibbs{ 76339213Sgibbs struct cam_periph *periph; 76439213Sgibbs struct sa_softc *softc; 76548520Speter scsi_space_code spaceop; 76643636Smjacob int didlockperiph = 0; 76743636Smjacob int s; 76839213Sgibbs int unit; 76939213Sgibbs int mode; 77039213Sgibbs int density; 77153259Smjacob int error = 0; 77239213Sgibbs 77339213Sgibbs unit = SAUNIT(dev); 77439213Sgibbs mode = SAMODE(dev); 77539213Sgibbs density = SADENSITY(dev); 77648520Speter error = 0; /* shut up gcc */ 77748520Speter spaceop = 0; /* shut up gcc */ 77839213Sgibbs 77939213Sgibbs periph = cam_extend_get(saperiphs, unit); 78039213Sgibbs if (periph == NULL) 78139213Sgibbs return (ENXIO); 78239213Sgibbs 78339213Sgibbs softc = (struct sa_softc *)periph->softc; 78439213Sgibbs 78539213Sgibbs /* 78643636Smjacob * Check for control mode accesses. We allow MTIOCGET and 78743636Smjacob * MTIOCERRSTAT (but need to be the only one open in order 78843636Smjacob * to clear latched status), and MTSETBSIZE, MTSETDNSTY 78943636Smjacob * and MTCOMP (but need to be the only one accessing this 79043636Smjacob * device to run those). 79143636Smjacob */ 79243636Smjacob 79343636Smjacob if (SA_IS_CTRL(dev)) { 79443636Smjacob switch (cmd) { 79546962Smjacob case MTIOCGETEOTMODEL: 79643636Smjacob case MTIOCGET: 79743636Smjacob break; 79843636Smjacob case MTIOCERRSTAT: 79943636Smjacob /* 80043636Smjacob * If the periph isn't already locked, lock it 80143636Smjacob * so our MTIOCERRSTAT can reset latched error stats. 80243636Smjacob * 80343636Smjacob * If the periph is already locked, skip it because 80443636Smjacob * we're just getting status and it'll be up to the 80543636Smjacob * other thread that has this device open to do 80643636Smjacob * an MTIOCERRSTAT that would clear latched status. 80743636Smjacob */ 80843636Smjacob s = splsoftcam(); 80943636Smjacob if ((periph->flags & CAM_PERIPH_LOCKED) == 0) { 81043636Smjacob error = cam_periph_lock(periph, PRIBIO|PCATCH); 81143636Smjacob if (error != 0) { 81243636Smjacob splx(s); 81343636Smjacob return (error); 81443636Smjacob } 81543636Smjacob didlockperiph = 1; 81643636Smjacob } 81743636Smjacob break; 81843636Smjacob 81946962Smjacob case MTIOCSETEOTMODEL: 82043636Smjacob case MTSETBSIZ: 82143636Smjacob case MTSETDNSTY: 82243636Smjacob case MTCOMP: 82343636Smjacob /* 82443636Smjacob * We need to acquire the peripheral here rather 82543636Smjacob * than at open time because we are sharing writable 82643636Smjacob * access to data structures. 82743636Smjacob */ 82843636Smjacob s = splsoftcam(); 82943636Smjacob error = cam_periph_lock(periph, PRIBIO|PCATCH); 83043636Smjacob if (error != 0) { 83143636Smjacob splx(s); 83243636Smjacob return (error); 83343636Smjacob } 83443636Smjacob didlockperiph = 1; 83543636Smjacob break; 83643636Smjacob 83743636Smjacob default: 83843636Smjacob return (EINVAL); 83943636Smjacob } 84043636Smjacob } 84143636Smjacob 84243636Smjacob /* 84339213Sgibbs * Find the device that the user is talking about 84439213Sgibbs */ 84539213Sgibbs switch (cmd) { 84639213Sgibbs case MTIOCGET: 84739213Sgibbs { 84839213Sgibbs struct mtget *g = (struct mtget *)arg; 84939213Sgibbs 85053259Smjacob /* 85153259Smjacob * If this isn't the control mode device, actually go out 85253259Smjacob * and ask the drive again what it's set to. 85353259Smjacob */ 85453259Smjacob if (!SA_IS_CTRL(dev)) { 85553259Smjacob u_int8_t write_protect; 85653259Smjacob int comp_enabled, comp_supported; 85753259Smjacob error = sagetparams(periph, SA_PARAM_ALL, 85853259Smjacob &softc->media_blksize, &softc->media_density, 85953259Smjacob &softc->media_numblks, &softc->buffer_mode, 86053259Smjacob &write_protect, &softc->speed, &comp_supported, 86153259Smjacob &comp_enabled, &softc->comp_algorithm, NULL); 86253259Smjacob if (error) 86353259Smjacob break; 86453259Smjacob if (write_protect) 86553259Smjacob softc->flags |= SA_FLAG_TAPE_WP; 86653259Smjacob else 86753259Smjacob softc->flags &= ~SA_FLAG_TAPE_WP; 86853259Smjacob softc->flags &= ~(SA_FLAG_COMP_SUPP| 86953259Smjacob SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP); 87053259Smjacob if (comp_supported) { 87153259Smjacob if (softc->saved_comp_algorithm == 0) 87253259Smjacob softc->saved_comp_algorithm = 87353259Smjacob softc->comp_algorithm; 87453259Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 87553259Smjacob if (comp_enabled) 87653259Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 87753259Smjacob } else 87853259Smjacob softc->flags |= SA_FLAG_COMP_UNSUPP; 87953259Smjacob } 88039213Sgibbs bzero(g, sizeof(struct mtget)); 88141948Smjacob g->mt_type = MT_ISAR; 88239213Sgibbs if (softc->flags & SA_FLAG_COMP_UNSUPP) { 88339213Sgibbs g->mt_comp = MT_COMP_UNSUPP; 88439213Sgibbs g->mt_comp0 = MT_COMP_UNSUPP; 88539213Sgibbs g->mt_comp1 = MT_COMP_UNSUPP; 88639213Sgibbs g->mt_comp2 = MT_COMP_UNSUPP; 88739213Sgibbs g->mt_comp3 = MT_COMP_UNSUPP; 88839213Sgibbs } else { 88946962Smjacob if ((softc->flags & SA_FLAG_COMP_ENABLED) == 0) { 89046962Smjacob g->mt_comp = MT_COMP_DISABLED; 89146962Smjacob } else { 89246962Smjacob g->mt_comp = softc->comp_algorithm; 89346962Smjacob } 89439213Sgibbs g->mt_comp0 = softc->comp_algorithm; 89539213Sgibbs g->mt_comp1 = softc->comp_algorithm; 89639213Sgibbs g->mt_comp2 = softc->comp_algorithm; 89739213Sgibbs g->mt_comp3 = softc->comp_algorithm; 89839213Sgibbs } 89946962Smjacob g->mt_density = softc->media_density; 90039213Sgibbs g->mt_density0 = softc->media_density; 90139213Sgibbs g->mt_density1 = softc->media_density; 90239213Sgibbs g->mt_density2 = softc->media_density; 90339213Sgibbs g->mt_density3 = softc->media_density; 90446962Smjacob g->mt_blksiz = softc->media_blksize; 90539213Sgibbs g->mt_blksiz0 = softc->media_blksize; 90639213Sgibbs g->mt_blksiz1 = softc->media_blksize; 90739213Sgibbs g->mt_blksiz2 = softc->media_blksize; 90839213Sgibbs g->mt_blksiz3 = softc->media_blksize; 90943636Smjacob g->mt_fileno = softc->fileno; 91043636Smjacob g->mt_blkno = softc->blkno; 91143636Smjacob g->mt_dsreg = (short) softc->dsreg; 91271268Smjacob /* 91371268Smjacob * Yes, we know that this is likely to overflow 91471268Smjacob */ 91571268Smjacob if (softc->last_resid_was_io) { 91671268Smjacob if ((g->mt_resid = (short) softc->last_io_resid) != 0) { 91771268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 91871268Smjacob softc->last_io_resid = 0; 91971268Smjacob } 92071268Smjacob } 92171268Smjacob } else { 92271268Smjacob if ((g->mt_resid = (short)softc->last_ctl_resid) != 0) { 92371268Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) { 92471268Smjacob softc->last_ctl_resid = 0; 92571268Smjacob } 92671268Smjacob } 92771268Smjacob } 92871268Smjacob if (g->mt_resid) { 92971268Smjacob } 93039213Sgibbs error = 0; 93139213Sgibbs break; 93239213Sgibbs } 93341948Smjacob case MTIOCERRSTAT: 93441948Smjacob { 93541948Smjacob struct scsi_tape_errors *sep = 93641948Smjacob &((union mterrstat *)arg)->scsi_errstat; 93741948Smjacob 93841948Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 93941948Smjacob ("saioctl: MTIOCERRSTAT\n")); 94041948Smjacob 94141948Smjacob bzero(sep, sizeof(*sep)); 94241948Smjacob sep->io_resid = softc->last_io_resid; 94341948Smjacob bcopy((caddr_t) &softc->last_io_sense, sep->io_sense, 94441948Smjacob sizeof (sep->io_sense)); 94542009Smjacob bcopy((caddr_t) &softc->last_io_cdb, sep->io_cdb, 94642009Smjacob sizeof (sep->io_cdb)); 94742009Smjacob sep->ctl_resid = softc->last_ctl_resid; 94841948Smjacob bcopy((caddr_t) &softc->last_ctl_sense, sep->ctl_sense, 94941948Smjacob sizeof (sep->ctl_sense)); 95042009Smjacob bcopy((caddr_t) &softc->last_ctl_cdb, sep->ctl_cdb, 95142009Smjacob sizeof (sep->ctl_cdb)); 95243636Smjacob 95343636Smjacob if (SA_IS_CTRL(dev) == 0 || didlockperiph) 95443636Smjacob bzero((caddr_t) &softc->errinfo, 95543636Smjacob sizeof (softc->errinfo)); 95641948Smjacob error = 0; 95741948Smjacob break; 95841948Smjacob } 95939213Sgibbs case MTIOCTOP: 96039213Sgibbs { 96139213Sgibbs struct mtop *mt; 96239213Sgibbs int count; 96339213Sgibbs 96439213Sgibbs mt = (struct mtop *)arg; 96539213Sgibbs 96639213Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 96739213Sgibbs ("saioctl: op=0x%x count=0x%x\n", 96839213Sgibbs mt->mt_op, mt->mt_count)); 96939213Sgibbs 97039213Sgibbs count = mt->mt_count; 97139213Sgibbs switch (mt->mt_op) { 97241906Smjacob case MTWEOF: /* write an end-of-file marker */ 97368114Smjacob /* 97468114Smjacob * We don't need to clear the SA_FLAG_TAPE_WRITTEN 97568114Smjacob * flag because by keeping track of filemarks 97668114Smjacob * we have last written we know ehether or not 97768114Smjacob * we need to write more when we close the device. 97868114Smjacob */ 97941906Smjacob error = sawritefilemarks(periph, count, FALSE); 98039213Sgibbs break; 98142009Smjacob case MTWSS: /* write a setmark */ 98242009Smjacob error = sawritefilemarks(periph, count, TRUE); 98342009Smjacob break; 98439213Sgibbs case MTBSR: /* backward space record */ 98539213Sgibbs case MTFSR: /* forward space record */ 98639213Sgibbs case MTBSF: /* backward space file */ 98739213Sgibbs case MTFSF: /* forward space file */ 98842009Smjacob case MTBSS: /* backward space setmark */ 98942009Smjacob case MTFSS: /* forward space setmark */ 99039213Sgibbs case MTEOD: /* space to end of recorded medium */ 99139213Sgibbs { 99239213Sgibbs int nmarks; 99339213Sgibbs 99448520Speter spaceop = SS_FILEMARKS; 99539213Sgibbs nmarks = softc->filemarks; 99639213Sgibbs error = sacheckeod(periph); 99741906Smjacob if (error) { 99841906Smjacob xpt_print_path(periph->path); 99941906Smjacob printf("EOD check prior to spacing failed\n"); 100041906Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 100141906Smjacob break; 100241906Smjacob } 100339213Sgibbs nmarks -= softc->filemarks; 100442009Smjacob switch(mt->mt_op) { 100542009Smjacob case MTBSR: 100639213Sgibbs count = -count; 100742009Smjacob /* FALLTHROUGH */ 100842009Smjacob case MTFSR: 100939213Sgibbs spaceop = SS_BLOCKS; 101042009Smjacob break; 101142009Smjacob case MTBSF: 101242009Smjacob count = -count; 101342009Smjacob /* FALLTHROUGH */ 101442009Smjacob case MTFSF: 101542009Smjacob break; 101642009Smjacob case MTBSS: 101742009Smjacob count = -count; 101842009Smjacob /* FALLTHROUGH */ 101942009Smjacob case MTFSS: 102042009Smjacob spaceop = SS_SETMARKS; 102142009Smjacob break; 102242009Smjacob case MTEOD: 102339213Sgibbs spaceop = SS_EOD; 102439213Sgibbs count = 0; 102539213Sgibbs nmarks = 0; 102642009Smjacob break; 102742009Smjacob default: 102842009Smjacob error = EINVAL; 102942009Smjacob break; 103039213Sgibbs } 103142009Smjacob if (error) 103242009Smjacob break; 103339213Sgibbs 103439213Sgibbs nmarks = softc->filemarks; 103542009Smjacob /* 103642009Smjacob * XXX: Why are we checking again? 103742009Smjacob */ 103839213Sgibbs error = sacheckeod(periph); 103942009Smjacob if (error) 104042009Smjacob break; 104139213Sgibbs nmarks -= softc->filemarks; 104242009Smjacob error = saspace(periph, count - nmarks, spaceop); 104341906Smjacob /* 104441906Smjacob * At this point, clear that we've written the tape 104541906Smjacob * and that we've written any filemarks. We really 104641906Smjacob * don't know what the applications wishes to do next- 104741906Smjacob * the sacheckeod's will make sure we terminated the 104841906Smjacob * tape correctly if we'd been writing, but the next 104941906Smjacob * action the user application takes will set again 105041906Smjacob * whether we need to write filemarks. 105141906Smjacob */ 105246962Smjacob softc->flags &= 105346962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 105441906Smjacob softc->filemarks = 0; 105539213Sgibbs break; 105639213Sgibbs } 105739213Sgibbs case MTREW: /* rewind */ 105841906Smjacob (void) sacheckeod(periph); 105939213Sgibbs error = sarewind(periph); 106041906Smjacob /* see above */ 106142009Smjacob softc->flags &= 106246962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 106341906Smjacob softc->filemarks = 0; 106439213Sgibbs break; 106539213Sgibbs case MTERASE: /* erase */ 106639213Sgibbs error = saerase(periph, count); 106746962Smjacob softc->flags &= 106846962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 106939213Sgibbs break; 107039213Sgibbs case MTRETENS: /* re-tension tape */ 107139213Sgibbs error = saretension(periph); 107246962Smjacob softc->flags &= 107346962Smjacob ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN); 107439213Sgibbs break; 107539213Sgibbs case MTOFFL: /* rewind and put the drive offline */ 107641906Smjacob 107741906Smjacob (void) sacheckeod(periph); 107841906Smjacob /* see above */ 107941906Smjacob softc->flags &= ~SA_FLAG_TAPE_WRITTEN; 108041906Smjacob softc->filemarks = 0; 108141906Smjacob 108246962Smjacob error = sarewind(periph); 108353522Smjacob /* clear the frozen flag anyway */ 108453522Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 108546962Smjacob 108639213Sgibbs /* 108753522Smjacob * Be sure to allow media removal before ejecting. 108839213Sgibbs */ 108946962Smjacob 109039213Sgibbs saprevent(periph, PR_ALLOW); 109153522Smjacob if (error == 0) { 109243636Smjacob error = saloadunload(periph, FALSE); 109353522Smjacob if (error == 0) { 109453522Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 109553522Smjacob } 109653522Smjacob } 109746962Smjacob break; 109839213Sgibbs 109939213Sgibbs case MTNOP: /* no operation, sets status only */ 110039213Sgibbs case MTCACHE: /* enable controller cache */ 110139213Sgibbs case MTNOCACHE: /* disable controller cache */ 110239213Sgibbs error = 0; 110339213Sgibbs break; 110446962Smjacob 110539213Sgibbs case MTSETBSIZ: /* Set block size for device */ 110639213Sgibbs 110739213Sgibbs error = sasetparams(periph, SA_PARAM_BLOCKSIZE, count, 110842563Smjacob 0, 0, 0); 110941674Smjacob if (error == 0) { 111041906Smjacob softc->last_media_blksize = 111141906Smjacob softc->media_blksize; 111241674Smjacob softc->media_blksize = count; 111341674Smjacob if (count) { 111441674Smjacob softc->flags |= SA_FLAG_FIXED; 111541674Smjacob if (powerof2(count)) { 111641674Smjacob softc->blk_shift = 111741674Smjacob ffs(count) - 1; 111841674Smjacob softc->blk_mask = count - 1; 111941674Smjacob } else { 112041674Smjacob softc->blk_mask = ~0; 112141674Smjacob softc->blk_shift = 0; 112241674Smjacob } 112341906Smjacob /* 112441906Smjacob * Make the user's desire 'persistent'. 112541906Smjacob */ 112641906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 112741906Smjacob softc->quirks |= SA_QUIRK_FIXED; 112841674Smjacob } else { 112941674Smjacob softc->flags &= ~SA_FLAG_FIXED; 113041674Smjacob if (softc->max_blk == 0) { 113141674Smjacob softc->max_blk = ~0; 113241674Smjacob } 113341674Smjacob softc->blk_shift = 0; 113441674Smjacob if (softc->blk_gran != 0) { 113541674Smjacob softc->blk_mask = 113641674Smjacob softc->blk_gran - 1; 113741674Smjacob } else { 113841674Smjacob softc->blk_mask = 0; 113941674Smjacob } 114041906Smjacob /* 114141906Smjacob * Make the user's desire 'persistent'. 114241906Smjacob */ 114341906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 114441906Smjacob softc->quirks &= ~SA_QUIRK_FIXED; 114541674Smjacob } 114641674Smjacob } 114739213Sgibbs break; 114839213Sgibbs case MTSETDNSTY: /* Set density for device and mode */ 114939213Sgibbs if (count > UCHAR_MAX) { 115039213Sgibbs error = EINVAL; 115139213Sgibbs break; 115239213Sgibbs } else { 115339213Sgibbs error = sasetparams(periph, SA_PARAM_DENSITY, 115442563Smjacob 0, count, 0, 0); 115539213Sgibbs } 115639213Sgibbs break; 115739213Sgibbs case MTCOMP: /* enable compression */ 115839213Sgibbs /* 115939213Sgibbs * Some devices don't support compression, and 116039213Sgibbs * don't like it if you ask them for the 116139213Sgibbs * compression page. 116239213Sgibbs */ 116343636Smjacob if ((softc->quirks & SA_QUIRK_NOCOMP) || 116443636Smjacob (softc->flags & SA_FLAG_COMP_UNSUPP)) { 116539213Sgibbs error = ENODEV; 116639213Sgibbs break; 116739213Sgibbs } 116839213Sgibbs error = sasetparams(periph, SA_PARAM_COMPRESSION, 116954099Smjacob 0, 0, count, SF_NO_PRINT); 117039213Sgibbs break; 117139213Sgibbs default: 117239213Sgibbs error = EINVAL; 117339213Sgibbs } 117439213Sgibbs break; 117539213Sgibbs } 117639213Sgibbs case MTIOCIEOT: 117739213Sgibbs case MTIOCEEOT: 117839213Sgibbs error = 0; 117939213Sgibbs break; 118041918Smjacob case MTIOCRDSPOS: 118141918Smjacob error = sardpos(periph, 0, (u_int32_t *) arg); 118241918Smjacob break; 118341918Smjacob case MTIOCRDHPOS: 118441918Smjacob error = sardpos(periph, 1, (u_int32_t *) arg); 118541918Smjacob break; 118641918Smjacob case MTIOCSLOCATE: 118741918Smjacob error = sasetpos(periph, 0, (u_int32_t *) arg); 118841918Smjacob break; 118941918Smjacob case MTIOCHLOCATE: 119041918Smjacob error = sasetpos(periph, 1, (u_int32_t *) arg); 119141918Smjacob break; 119246962Smjacob case MTIOCGETEOTMODEL: 119346962Smjacob error = 0; 119446962Smjacob if (softc->quirks & SA_QUIRK_1FM) 119546962Smjacob mode = 1; 119646962Smjacob else 119746962Smjacob mode = 2; 119846962Smjacob *((u_int32_t *) arg) = mode; 119946962Smjacob break; 120046962Smjacob case MTIOCSETEOTMODEL: 120146962Smjacob error = 0; 120246962Smjacob switch (*((u_int32_t *) arg)) { 120346962Smjacob case 1: 120446962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 120546962Smjacob softc->quirks |= SA_QUIRK_1FM; 120646962Smjacob break; 120746962Smjacob case 2: 120846962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 120946962Smjacob softc->quirks |= SA_QUIRK_2FM; 121046962Smjacob break; 121146962Smjacob default: 121246962Smjacob error = EINVAL; 121346962Smjacob break; 121446962Smjacob } 121546962Smjacob break; 121639213Sgibbs default: 121739213Sgibbs error = cam_periph_ioctl(periph, cmd, arg, saerror); 121839213Sgibbs break; 121939213Sgibbs } 122071268Smjacob 122171268Smjacob /* 122271268Smjacob * Check to see if we cleared a frozen state 122371268Smjacob */ 122471268Smjacob if (error == 0 && (softc->flags & SA_FLAG_TAPE_FROZEN)) { 122571268Smjacob switch(cmd) { 122671268Smjacob case MTIOCRDSPOS: 122771268Smjacob case MTIOCRDHPOS: 122871268Smjacob case MTIOCSLOCATE: 122971268Smjacob case MTIOCHLOCATE: 123071268Smjacob softc->fileno = (daddr_t) -1; 123171268Smjacob softc->blkno = (daddr_t) -1; 123271268Smjacob softc->flags &= ~SA_FLAG_TAPE_FROZEN; 123371268Smjacob xpt_print_path(periph->path); 123471268Smjacob printf("tape state now unfrozen.\n"); 123571268Smjacob break; 123671268Smjacob default: 123771268Smjacob break; 123871268Smjacob } 123971268Smjacob } 124043636Smjacob if (didlockperiph) { 124143636Smjacob cam_periph_unlock(periph); 124243636Smjacob } 124339213Sgibbs return (error); 124439213Sgibbs} 124539213Sgibbs 124639213Sgibbsstatic void 124739213Sgibbssainit(void) 124839213Sgibbs{ 124939213Sgibbs cam_status status; 125039213Sgibbs struct cam_path *path; 125139213Sgibbs 125239213Sgibbs /* 125339213Sgibbs * Create our extend array for storing the devices we attach to. 125439213Sgibbs */ 125539213Sgibbs saperiphs = cam_extend_new(); 125639213Sgibbs if (saperiphs == NULL) { 125739213Sgibbs printf("sa: Failed to alloc extend array!\n"); 125839213Sgibbs return; 125939213Sgibbs } 126039213Sgibbs 126139213Sgibbs /* 126239213Sgibbs * Install a global async callback. 126339213Sgibbs */ 126439213Sgibbs status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 126539213Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 126639213Sgibbs 126739213Sgibbs if (status == CAM_REQ_CMP) { 126839213Sgibbs /* Register the async callbacks of interrest */ 126939213Sgibbs struct ccb_setasync csa; /* 127039213Sgibbs * This is an immediate CCB, 127139213Sgibbs * so using the stack is OK 127239213Sgibbs */ 127346962Smjacob xpt_setup_ccb(&csa.ccb_h, path, 5); 127439213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 127539213Sgibbs csa.event_enable = AC_FOUND_DEVICE; 127639213Sgibbs csa.callback = saasync; 127739213Sgibbs csa.callback_arg = NULL; 127839213Sgibbs xpt_action((union ccb *)&csa); 127939213Sgibbs status = csa.ccb_h.status; 128039213Sgibbs xpt_free_path(path); 128139213Sgibbs } 128239213Sgibbs 128339213Sgibbs if (status != CAM_REQ_CMP) { 128439213Sgibbs printf("sa: Failed to attach master async callback " 128539213Sgibbs "due to status 0x%x!\n", status); 128639213Sgibbs } 128739213Sgibbs} 128839213Sgibbs 128939213Sgibbsstatic void 129040603Skensaoninvalidate(struct cam_periph *periph) 129140603Sken{ 129240603Sken struct sa_softc *softc; 129359249Sphk struct bio *q_bp; 129440603Sken struct ccb_setasync csa; 129540603Sken int s; 129640603Sken 129740603Sken softc = (struct sa_softc *)periph->softc; 129840603Sken 129940603Sken /* 130040603Sken * De-register any async callbacks. 130140603Sken */ 130240603Sken xpt_setup_ccb(&csa.ccb_h, periph->path, 130340603Sken /* priority */ 5); 130440603Sken csa.ccb_h.func_code = XPT_SASYNC_CB; 130540603Sken csa.event_enable = 0; 130640603Sken csa.callback = saasync; 130740603Sken csa.callback_arg = periph; 130840603Sken xpt_action((union ccb *)&csa); 130940603Sken 131040603Sken softc->flags |= SA_FLAG_INVALID; 131140603Sken 131240603Sken /* 131340603Sken * Although the oninvalidate() routines are always called at 131440603Sken * splsoftcam, we need to be at splbio() here to keep the buffer 131540603Sken * queue from being modified while we traverse it. 131640603Sken */ 131740603Sken s = splbio(); 131840603Sken 131940603Sken /* 132040603Sken * Return all queued I/O with ENXIO. 132140603Sken * XXX Handle any transactions queued to the card 132240603Sken * with XPT_ABORT_CCB. 132340603Sken */ 132459249Sphk while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){ 132559249Sphk bioq_remove(&softc->bio_queue, q_bp); 132659249Sphk q_bp->bio_resid = q_bp->bio_bcount; 132759249Sphk q_bp->bio_error = ENXIO; 132859249Sphk q_bp->bio_flags |= BIO_ERROR; 132940603Sken biodone(q_bp); 133040603Sken } 133146962Smjacob softc->queue_count = 0; 133240603Sken splx(s); 133340603Sken 133440603Sken xpt_print_path(periph->path); 133540603Sken printf("lost device\n"); 133640603Sken 133740603Sken} 133840603Sken 133940603Skenstatic void 134039213Sgibbssacleanup(struct cam_periph *periph) 134139213Sgibbs{ 134240603Sken struct sa_softc *softc; 134353259Smjacob int i; 134440603Sken 134540603Sken softc = (struct sa_softc *)periph->softc; 134640603Sken 134740603Sken devstat_remove_entry(&softc->device_stats); 134853259Smjacob 134953259Smjacob destroy_dev(softc->devs.ctl_dev); 135053259Smjacob 135153259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 135253259Smjacob destroy_dev(softc->devs.mode_devs[i].r_dev); 135353259Smjacob destroy_dev(softc->devs.mode_devs[i].nr_dev); 135453259Smjacob destroy_dev(softc->devs.mode_devs[i].er_dev); 135553259Smjacob } 135653259Smjacob 135739213Sgibbs cam_extend_release(saperiphs, periph->unit_number); 135839213Sgibbs xpt_print_path(periph->path); 135939213Sgibbs printf("removing device entry\n"); 136040603Sken free(softc, M_DEVBUF); 136139213Sgibbs} 136239213Sgibbs 136339213Sgibbsstatic void 136439213Sgibbssaasync(void *callback_arg, u_int32_t code, 136539213Sgibbs struct cam_path *path, void *arg) 136639213Sgibbs{ 136739213Sgibbs struct cam_periph *periph; 136839213Sgibbs 136939213Sgibbs periph = (struct cam_periph *)callback_arg; 137039213Sgibbs switch (code) { 137139213Sgibbs case AC_FOUND_DEVICE: 137239213Sgibbs { 137339213Sgibbs struct ccb_getdev *cgd; 137439213Sgibbs cam_status status; 137539213Sgibbs 137639213Sgibbs cgd = (struct ccb_getdev *)arg; 137739213Sgibbs 137856148Smjacob if (SID_TYPE(&cgd->inq_data) != T_SEQUENTIAL) 137939213Sgibbs break; 138039213Sgibbs 138139213Sgibbs /* 138239213Sgibbs * Allocate a peripheral instance for 138339213Sgibbs * this device and start the probe 138439213Sgibbs * process. 138539213Sgibbs */ 138640603Sken status = cam_periph_alloc(saregister, saoninvalidate, 138740603Sken sacleanup, sastart, 138839213Sgibbs "sa", CAM_PERIPH_BIO, cgd->ccb_h.path, 138939213Sgibbs saasync, AC_FOUND_DEVICE, cgd); 139039213Sgibbs 139139213Sgibbs if (status != CAM_REQ_CMP 139239213Sgibbs && status != CAM_REQ_INPROG) 139339213Sgibbs printf("saasync: Unable to probe new device " 139439213Sgibbs "due to status 0x%x\n", status); 139539213Sgibbs break; 139639213Sgibbs } 139739213Sgibbs default: 139847413Sgibbs cam_periph_async(periph, code, path, arg); 139939213Sgibbs break; 140039213Sgibbs } 140139213Sgibbs} 140239213Sgibbs 140339213Sgibbsstatic cam_status 140439213Sgibbssaregister(struct cam_periph *periph, void *arg) 140539213Sgibbs{ 140639213Sgibbs struct sa_softc *softc; 140739213Sgibbs struct ccb_setasync csa; 140839213Sgibbs struct ccb_getdev *cgd; 140939213Sgibbs caddr_t match; 141053259Smjacob int i; 141139213Sgibbs 141239213Sgibbs cgd = (struct ccb_getdev *)arg; 141339213Sgibbs if (periph == NULL) { 141439213Sgibbs printf("saregister: periph was NULL!!\n"); 141554099Smjacob return (CAM_REQ_CMP_ERR); 141639213Sgibbs } 141739213Sgibbs 141839213Sgibbs if (cgd == NULL) { 141939213Sgibbs printf("saregister: no getdev CCB, can't register device\n"); 142054099Smjacob return (CAM_REQ_CMP_ERR); 142139213Sgibbs } 142239213Sgibbs 142367723Smjacob softc = (struct sa_softc *) 142467723Smjacob malloc(sizeof (*softc), M_DEVBUF, M_NOWAIT | M_ZERO); 142539213Sgibbs if (softc == NULL) { 142639213Sgibbs printf("saregister: Unable to probe new device. " 142739213Sgibbs "Unable to allocate softc\n"); 142854099Smjacob return (CAM_REQ_CMP_ERR); 142939213Sgibbs } 143041674Smjacob softc->scsi_rev = SID_ANSI_REV(&cgd->inq_data); 143139213Sgibbs softc->state = SA_STATE_NORMAL; 143243636Smjacob softc->fileno = (daddr_t) -1; 143343636Smjacob softc->blkno = (daddr_t) -1; 143443636Smjacob 143559249Sphk bioq_init(&softc->bio_queue); 143639213Sgibbs periph->softc = softc; 143739213Sgibbs cam_extend_set(saperiphs, periph->unit_number, periph); 143839213Sgibbs 143939213Sgibbs /* 144039213Sgibbs * See if this device has any quirks. 144139213Sgibbs */ 144239213Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 144339213Sgibbs (caddr_t)sa_quirk_table, 144439213Sgibbs sizeof(sa_quirk_table)/sizeof(*sa_quirk_table), 144539213Sgibbs sizeof(*sa_quirk_table), scsi_inquiry_match); 144639213Sgibbs 144742563Smjacob if (match != NULL) { 144839213Sgibbs softc->quirks = ((struct sa_quirk_entry *)match)->quirks; 144942563Smjacob softc->last_media_blksize = 145042563Smjacob ((struct sa_quirk_entry *)match)->prefblk; 145142563Smjacob#ifdef CAMDEBUG 145242563Smjacob xpt_print_path(periph->path); 145343651Smjacob printf("found quirk entry %d\n", (int) 145443651Smjacob (((struct sa_quirk_entry *) match) - sa_quirk_table)); 145542563Smjacob#endif 145642563Smjacob } else 145739213Sgibbs softc->quirks = SA_QUIRK_NONE; 145839213Sgibbs 145939213Sgibbs /* 146039213Sgibbs * The SA driver supports a blocksize, but we don't know the 146146962Smjacob * blocksize until we media is inserted. So, set a flag to 146239213Sgibbs * indicate that the blocksize is unavailable right now. 146339213Sgibbs */ 146453259Smjacob devstat_add_entry(&softc->device_stats, "sa", periph->unit_number, 0, 146556148Smjacob DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) | 146656148Smjacob DEVSTAT_TYPE_IF_SCSI, DEVSTAT_PRIORITY_TAPE); 146753259Smjacob 146853259Smjacob softc->devs.ctl_dev = make_dev(&sa_cdevsw, SAMINOR(SA_CTLDEV, 146953259Smjacob periph->unit_number, 0, SA_ATYPE_R), UID_ROOT, GID_OPERATOR, 147053259Smjacob 0660, "r%s%d.ctl", periph->periph_name, periph->unit_number); 147153259Smjacob 147253259Smjacob for (i = 0; i < SA_NUM_MODES; i++) { 147353283Smjacob 147453259Smjacob softc->devs.mode_devs[i].r_dev = make_dev(&sa_cdevsw, 147553259Smjacob SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_R), 147653259Smjacob UID_ROOT, GID_OPERATOR, 0660, "r%s%d.%d", 147753259Smjacob periph->periph_name, periph->unit_number, i); 147853283Smjacob 147953259Smjacob softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw, 148053259Smjacob SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_NR), 148153259Smjacob UID_ROOT, GID_OPERATOR, 0660, "nr%s%d.%d", 148253259Smjacob periph->periph_name, periph->unit_number, i); 148353259Smjacob 148453283Smjacob 148553283Smjacob softc->devs.mode_devs[i].er_dev = make_dev(&sa_cdevsw, 148653259Smjacob SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_ER), 148753259Smjacob UID_ROOT, GID_OPERATOR, 0660, "er%s%d.%d", 148853259Smjacob periph->periph_name, periph->unit_number, i); 148965838Smjacob 149065838Smjacob /* 149165838Smjacob * Make the (well known) aliases for the first mode. 149265838Smjacob */ 149365838Smjacob if (i == 0) { 149465838Smjacob make_dev_alias(softc->devs.mode_devs[i].r_dev, 149565838Smjacob "r%s%d", periph->periph_name, periph->unit_number); 149665838Smjacob make_dev_alias(softc->devs.mode_devs[i].nr_dev, 149765838Smjacob "nr%s%d", periph->periph_name, periph->unit_number); 149865838Smjacob make_dev_alias(softc->devs.mode_devs[i].er_dev, 149965838Smjacob "er%s%d", periph->periph_name, periph->unit_number); 150065838Smjacob } 150153259Smjacob } 150253259Smjacob 150339213Sgibbs /* 150439213Sgibbs * Add an async callback so that we get 150539213Sgibbs * notified if this device goes away. 150639213Sgibbs */ 150739213Sgibbs xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 150839213Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 150939213Sgibbs csa.event_enable = AC_LOST_DEVICE; 151039213Sgibbs csa.callback = saasync; 151139213Sgibbs csa.callback_arg = periph; 151239213Sgibbs xpt_action((union ccb *)&csa); 151339213Sgibbs 151439213Sgibbs xpt_announce_periph(periph, NULL); 151539213Sgibbs 151654099Smjacob return (CAM_REQ_CMP); 151739213Sgibbs} 151839213Sgibbs 151939213Sgibbsstatic void 152039213Sgibbssastart(struct cam_periph *periph, union ccb *start_ccb) 152139213Sgibbs{ 152239213Sgibbs struct sa_softc *softc; 152339213Sgibbs 152439213Sgibbs softc = (struct sa_softc *)periph->softc; 152539213Sgibbs 152641948Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("sastart")); 152771082Smjacob 152839213Sgibbs 152939213Sgibbs switch (softc->state) { 153039213Sgibbs case SA_STATE_NORMAL: 153139213Sgibbs { 153239213Sgibbs /* Pull a buffer from the queue and get going on it */ 153359249Sphk struct bio *bp; 153439213Sgibbs int s; 153539213Sgibbs 153639213Sgibbs /* 153739213Sgibbs * See if there is a buf with work for us to do.. 153839213Sgibbs */ 153939213Sgibbs s = splbio(); 154059249Sphk bp = bioq_first(&softc->bio_queue); 154139213Sgibbs if (periph->immediate_priority <= periph->pinfo.priority) { 154239213Sgibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 154339213Sgibbs ("queuing for immediate ccb\n")); 154471082Smjacob Set_CCB_Type(start_ccb, SA_CCB_WAITING); 154539213Sgibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 154639213Sgibbs periph_links.sle); 154739213Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 154839213Sgibbs splx(s); 154939213Sgibbs wakeup(&periph->ccb_list); 155039213Sgibbs } else if (bp == NULL) { 155139213Sgibbs splx(s); 155239213Sgibbs xpt_release_ccb(start_ccb); 155339213Sgibbs } else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) { 155459249Sphk struct bio *done_bp; 155546962Smjacob softc->queue_count--; 155659249Sphk bioq_remove(&softc->bio_queue, bp); 155759249Sphk bp->bio_resid = bp->bio_bcount; 155859249Sphk bp->bio_flags |= BIO_ERROR; 155939213Sgibbs if ((softc->flags & SA_FLAG_EOM_PENDING) != 0) { 156059249Sphk if (bp->bio_cmd == BIO_WRITE) 156159249Sphk bp->bio_error = ENOSPC; 156244354Smjacob else 156359249Sphk bp->bio_error = EIO; 156439213Sgibbs } 156541948Smjacob if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) { 156659249Sphk bp->bio_error = EIO; 156741948Smjacob } 156839213Sgibbs if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) { 156959249Sphk bp->bio_error = EIO; 157039213Sgibbs } 157141948Smjacob done_bp = bp; 157259249Sphk bp = bioq_first(&softc->bio_queue); 157344354Smjacob /* 157444354Smjacob * Only if we have no other buffers queued up 157544354Smjacob * do we clear the pending error flag. 157644354Smjacob */ 157744354Smjacob if (bp == NULL) 157844354Smjacob softc->flags &= ~SA_FLAG_ERR_PENDING; 157944354Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 158046962Smjacob ("sastart- ERR_PENDING now 0x%x, bp is %sNULL, " 158146962Smjacob "%d more buffers queued up\n", 158244354Smjacob (softc->flags & SA_FLAG_ERR_PENDING), 158346962Smjacob (bp != NULL)? "not " : " ", softc->queue_count)); 158439213Sgibbs splx(s); 158544354Smjacob xpt_release_ccb(start_ccb); 158641948Smjacob biodone(done_bp); 158739213Sgibbs } else { 158839213Sgibbs u_int32_t length; 158939213Sgibbs 159059249Sphk bioq_remove(&softc->bio_queue, bp); 159146962Smjacob softc->queue_count--; 159239213Sgibbs 159339213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) { 159439213Sgibbs if (softc->blk_shift != 0) { 159539213Sgibbs length = 159659249Sphk bp->bio_bcount >> softc->blk_shift; 159743636Smjacob } else if (softc->media_blksize != 0) { 159871082Smjacob length = bp->bio_bcount / 159971082Smjacob softc->media_blksize; 160043636Smjacob } else { 160159249Sphk bp->bio_error = EIO; 160243636Smjacob xpt_print_path(periph->path); 160343636Smjacob printf("zero blocksize for " 160443636Smjacob "FIXED length writes?\n"); 160543636Smjacob splx(s); 160643636Smjacob biodone(bp); 160743636Smjacob break; 160839213Sgibbs } 160941906Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 161041906Smjacob ("Fixed Record Count is %d\n", length)); 161139213Sgibbs } else { 161259249Sphk length = bp->bio_bcount; 161341906Smjacob CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 161441906Smjacob ("Variable Record Count is %d\n", length)); 161539213Sgibbs } 161639213Sgibbs devstat_start_transaction(&softc->device_stats); 161739213Sgibbs /* 161841906Smjacob * Some people have theorized that we should 161939213Sgibbs * suppress illegal length indication if we are 162039213Sgibbs * running in variable block mode so that we don't 162139213Sgibbs * have to request sense every time our requested 162239213Sgibbs * block size is larger than the written block. 162339213Sgibbs * The residual information from the ccb allows 162439213Sgibbs * us to identify this situation anyway. The only 162539213Sgibbs * problem with this is that we will not get 162639213Sgibbs * information about blocks that are larger than 162739213Sgibbs * our read buffer unless we set the block size 162839213Sgibbs * in the mode page to something other than 0. 162941906Smjacob * 163041906Smjacob * I believe that this is a non-issue. If user apps 163141906Smjacob * don't adjust their read size to match our record 163241906Smjacob * size, that's just life. Anyway, the typical usage 163341906Smjacob * would be to issue, e.g., 64KB reads and occasionally 163441906Smjacob * have to do deal with 512 byte or 1KB intermediate 163541906Smjacob * records. 163639213Sgibbs */ 163759249Sphk softc->dsreg = (bp->bio_cmd == BIO_READ)? 163843636Smjacob MTIO_DSREG_RD : MTIO_DSREG_WR; 163946962Smjacob scsi_sa_read_write(&start_ccb->csio, 0, sadone, 164059249Sphk MSG_SIMPLE_Q_TAG, (bp->bio_cmd == BIO_READ), 164146962Smjacob FALSE, (softc->flags & SA_FLAG_FIXED) != 0, 164259249Sphk length, bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE, 164346962Smjacob 120 * 60 * 1000); 164471082Smjacob start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED; 164571082Smjacob Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO); 164639213Sgibbs start_ccb->ccb_h.ccb_bp = bp; 164759249Sphk bp = bioq_first(&softc->bio_queue); 164839213Sgibbs splx(s); 164939213Sgibbs xpt_action(start_ccb); 165039213Sgibbs } 165139213Sgibbs 165239213Sgibbs if (bp != NULL) { 165339213Sgibbs /* Have more work to do, so ensure we stay scheduled */ 165446962Smjacob xpt_schedule(periph, 1); 165539213Sgibbs } 165639213Sgibbs break; 165739213Sgibbs } 165846962Smjacob case SA_STATE_ABNORMAL: 165946962Smjacob default: 166046962Smjacob panic("state 0x%x in sastart", softc->state); 166146962Smjacob break; 166239213Sgibbs } 166339213Sgibbs} 166439213Sgibbs 166539213Sgibbs 166639213Sgibbsstatic void 166739213Sgibbssadone(struct cam_periph *periph, union ccb *done_ccb) 166839213Sgibbs{ 166939213Sgibbs struct sa_softc *softc; 167039213Sgibbs struct ccb_scsiio *csio; 167139213Sgibbs 167239213Sgibbs softc = (struct sa_softc *)periph->softc; 167339213Sgibbs csio = &done_ccb->csio; 167471082Smjacob switch (CCB_Type(csio)) { 167539213Sgibbs case SA_CCB_BUFFER_IO: 167639213Sgibbs { 167759249Sphk struct bio *bp; 167839213Sgibbs int error; 167939213Sgibbs 168043636Smjacob softc->dsreg = MTIO_DSREG_REST; 168159249Sphk bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 168239213Sgibbs error = 0; 168339213Sgibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 168439213Sgibbs if ((error = saerror(done_ccb, 0, 0)) == ERESTART) { 168539213Sgibbs /* 168641948Smjacob * A retry was scheduled, so just return. 168739213Sgibbs */ 168839213Sgibbs return; 168939213Sgibbs } 169039213Sgibbs } 169139213Sgibbs 169239213Sgibbs if (error == EIO) { 169339213Sgibbs int s; 169459249Sphk struct bio *q_bp; 169539213Sgibbs 169639213Sgibbs /* 169753522Smjacob * Catastrophic error. Mark the tape as frozen 169853522Smjacob * (we no longer know tape position). 169953522Smjacob * 170044354Smjacob * Return all queued I/O with EIO, and unfreeze 170139213Sgibbs * our queue so that future transactions that 170239213Sgibbs * attempt to fix this problem can get to the 170339213Sgibbs * device. 170439213Sgibbs * 170539213Sgibbs */ 170639213Sgibbs 170739213Sgibbs s = splbio(); 170853522Smjacob softc->flags |= SA_FLAG_TAPE_FROZEN; 170959249Sphk while ((q_bp = bioq_first(&softc->bio_queue)) != NULL) { 171059249Sphk bioq_remove(&softc->bio_queue, q_bp); 171159249Sphk q_bp->bio_resid = q_bp->bio_bcount; 171259249Sphk q_bp->bio_error = EIO; 171359249Sphk q_bp->bio_flags |= BIO_ERROR; 171439213Sgibbs biodone(q_bp); 171539213Sgibbs } 171639213Sgibbs splx(s); 171739213Sgibbs } 171839213Sgibbs if (error != 0) { 171959249Sphk bp->bio_resid = bp->bio_bcount; 172059249Sphk bp->bio_error = error; 172159249Sphk bp->bio_flags |= BIO_ERROR; 172243636Smjacob /* 172343636Smjacob * In the error case, position is updated in saerror. 172443636Smjacob */ 172539213Sgibbs } else { 172659249Sphk bp->bio_resid = csio->resid; 172759249Sphk bp->bio_error = 0; 172839213Sgibbs if (csio->resid != 0) { 172959249Sphk bp->bio_flags |= BIO_ERROR; 173039213Sgibbs } 173159249Sphk if (bp->bio_cmd == BIO_WRITE) { 173239213Sgibbs softc->flags |= SA_FLAG_TAPE_WRITTEN; 173339213Sgibbs softc->filemarks = 0; 173439213Sgibbs } 173571082Smjacob if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) && 173671082Smjacob (softc->blkno != (daddr_t) -1)) { 173743636Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 173843636Smjacob u_int32_t l; 173943636Smjacob if (softc->blk_shift != 0) { 174059249Sphk l = bp->bio_bcount >> 174143636Smjacob softc->blk_shift; 174243636Smjacob } else { 174359249Sphk l = bp->bio_bcount / 174443636Smjacob softc->media_blksize; 174543636Smjacob } 174643636Smjacob softc->blkno += (daddr_t) l; 174743636Smjacob } else { 174843636Smjacob softc->blkno++; 174943636Smjacob } 175043636Smjacob } 175139213Sgibbs } 175246962Smjacob /* 175346962Smjacob * If we had an error (immediate or pending), 175446962Smjacob * release the device queue now. 175546962Smjacob */ 175646962Smjacob if (error || (softc->flags & SA_FLAG_ERR_PENDING)) 175746962Smjacob cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0); 175841674Smjacob#ifdef CAMDEBUG 175959249Sphk if (error || bp->bio_resid) { 176041674Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 176141674Smjacob ("error %d resid %ld count %ld\n", error, 176259249Sphk bp->bio_resid, bp->bio_bcount)); 176341674Smjacob } 176441674Smjacob#endif 176559249Sphk devstat_end_transaction_bio(&softc->device_stats, bp); 176639213Sgibbs biodone(bp); 176739213Sgibbs break; 176839213Sgibbs } 176939213Sgibbs case SA_CCB_WAITING: 177039213Sgibbs { 177139213Sgibbs /* Caller will release the CCB */ 177239213Sgibbs wakeup(&done_ccb->ccb_h.cbfcnp); 177339213Sgibbs return; 177439213Sgibbs } 177539213Sgibbs } 177639213Sgibbs xpt_release_ccb(done_ccb); 177739213Sgibbs} 177839213Sgibbs 177941906Smjacob/* 178041906Smjacob * Mount the tape (make sure it's ready for I/O). 178141906Smjacob */ 178239213Sgibbsstatic int 178341906Smjacobsamount(struct cam_periph *periph, int oflags, dev_t dev) 178439213Sgibbs{ 178539213Sgibbs struct sa_softc *softc; 178639213Sgibbs union ccb *ccb; 178739213Sgibbs int error; 178839213Sgibbs 178941906Smjacob /* 179041906Smjacob * oflags can be checked for 'kind' of open (read-only check) - later 179141906Smjacob * dev can be checked for a control-mode or compression open - later 179241906Smjacob */ 179341906Smjacob UNUSED_PARAMETER(oflags); 179441906Smjacob UNUSED_PARAMETER(dev); 179541906Smjacob 179641906Smjacob 179739213Sgibbs softc = (struct sa_softc *)periph->softc; 179839213Sgibbs 179939213Sgibbs /* 180053259Smjacob * This should determine if something has happend since the last 180153259Smjacob * open/mount that would invalidate the mount. We do *not* want 180253259Smjacob * to retry this command- we just want the status. But we only 180353259Smjacob * do this if we're mounted already- if we're not mounted, 180453259Smjacob * we don't care about the unit read state and can instead use 180553259Smjacob * this opportunity to attempt to reserve the tape unit. 180639213Sgibbs */ 180753259Smjacob 180853259Smjacob if (softc->flags & SA_FLAG_TAPE_MOUNTED) { 180953259Smjacob ccb = cam_periph_getccb(periph, 1); 181053259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 181153259Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5 * 60 * 1000); 181254099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 181353259Smjacob &softc->device_stats); 181453259Smjacob QFRLS(ccb); 181553259Smjacob if (error == ENXIO) { 181653259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 181753259Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 181853259Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5 * 60 * 1000); 181954099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 182053259Smjacob &softc->device_stats); 182153259Smjacob QFRLS(ccb); 182253259Smjacob } else if (error) { 182354099Smjacob /* 182454099Smjacob * We don't need to freeze the tape because we 182554099Smjacob * will now attempt to rewind/load it. 182654099Smjacob */ 182753259Smjacob softc->flags &= ~SA_FLAG_TAPE_MOUNTED; 182854099Smjacob if (CAM_DEBUGGED(ccb->ccb_h.path, CAM_DEBUG_INFO)) { 182954099Smjacob xpt_print_path(ccb->ccb_h.path); 183054099Smjacob printf("error %d on TUR in samount\n", error); 183154099Smjacob } 183253259Smjacob } 183353259Smjacob } else { 183453259Smjacob error = sareservereleaseunit(periph, TRUE); 183553259Smjacob if (error) { 183653259Smjacob return (error); 183753259Smjacob } 183853259Smjacob ccb = cam_periph_getccb(periph, 1); 183954105Smjacob scsi_test_unit_ready(&ccb->csio, 0, sadone, 184054105Smjacob MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5 * 60 * 1000); 184154105Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 184254105Smjacob &softc->device_stats); 184354105Smjacob QFRLS(ccb); 184453259Smjacob } 184539213Sgibbs 184639213Sgibbs if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) { 184753259Smjacob struct scsi_read_block_limits_data *rblim = NULL; 184853259Smjacob int comp_enabled, comp_supported; 184941906Smjacob u_int8_t write_protect, guessing = 0; 185039213Sgibbs 185139213Sgibbs /* 185239213Sgibbs * Clear out old state. 185339213Sgibbs */ 185439213Sgibbs softc->flags &= ~(SA_FLAG_TAPE_WP|SA_FLAG_TAPE_WRITTEN| 185539213Sgibbs SA_FLAG_ERR_PENDING|SA_FLAG_COMP_ENABLED| 185646962Smjacob SA_FLAG_COMP_SUPP|SA_FLAG_COMP_UNSUPP); 185739213Sgibbs softc->filemarks = 0; 185839213Sgibbs 185939213Sgibbs /* 186043636Smjacob * *Very* first off, make sure we're loaded to BOT. 186139213Sgibbs */ 186243636Smjacob scsi_load_unload(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 186354099Smjacob FALSE, FALSE, 1, SSD_FULL_SIZE, REWIND_TIMEOUT); 186454099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 186543636Smjacob &softc->device_stats); 186653259Smjacob QFRLS(ccb); 186753259Smjacob 186843636Smjacob /* 186944354Smjacob * In case this doesn't work, do a REWIND instead 187043636Smjacob */ 187144354Smjacob if (error) { 187253259Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 187353259Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 187454099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 187543636Smjacob &softc->device_stats); 187653259Smjacob QFRLS(ccb); 187743636Smjacob } 187843636Smjacob if (error) { 187943636Smjacob xpt_release_ccb(ccb); 188043636Smjacob goto exit; 188143636Smjacob } 188243636Smjacob 188343636Smjacob /* 188453259Smjacob * Do a dummy test read to force access to the 188553259Smjacob * media so that the drive will really know what's 188654099Smjacob * there. We actually don't really care what the 188754099Smjacob * blocksize on tape is and don't expect to really 188854099Smjacob * read a full record. 188943636Smjacob */ 189039213Sgibbs rblim = (struct scsi_read_block_limits_data *) 189154099Smjacob malloc(8192, M_TEMP, M_WAITOK); 189253259Smjacob if (rblim == NULL) { 189353259Smjacob xpt_print_path(ccb->ccb_h.path); 189453259Smjacob printf("no memory for test read\n"); 189553259Smjacob xpt_release_ccb(ccb); 189653259Smjacob error = ENOMEM; 189753259Smjacob goto exit; 189853259Smjacob } 189956981Smjacob 190056981Smjacob if ((softc->quirks & SA_QUIRK_NODREAD) == 0) { 190156981Smjacob scsi_sa_read_write(&ccb->csio, 0, sadone, 190256981Smjacob MSG_SIMPLE_Q_TAG, 1, FALSE, 0, 8192, 190356981Smjacob (void *) rblim, 8192, SSD_FULL_SIZE, 190456981Smjacob 120 * 60 * 1000); 190556981Smjacob (void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 190656981Smjacob &softc->device_stats); 190756981Smjacob QFRLS(ccb); 190856981Smjacob scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 190956981Smjacob FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT); 191056981Smjacob error = cam_periph_runccb(ccb, saerror, 0, 191156981Smjacob SF_NO_PRINT | SF_RETRY_SELTO | SF_RETRY_UA, 191256981Smjacob &softc->device_stats); 191356981Smjacob QFRLS(ccb); 191456981Smjacob if (error) { 191556981Smjacob xpt_print_path(ccb->ccb_h.path); 191656981Smjacob printf("unable to rewind after test read\n"); 191756981Smjacob xpt_release_ccb(ccb); 191856981Smjacob goto exit; 191956981Smjacob } 192053259Smjacob } 192139213Sgibbs 192253259Smjacob /* 192353259Smjacob * Next off, determine block limits. 192453259Smjacob */ 192553259Smjacob scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 192642563Smjacob rblim, SSD_FULL_SIZE, 5000); 192739213Sgibbs 192842563Smjacob error = cam_periph_runccb(ccb, saerror, 0, 192954099Smjacob SF_NO_PRINT | SF_RETRY_UA | SF_RETRY_SELTO, 193054099Smjacob &softc->device_stats); 193153259Smjacob QFRLS(ccb); 193239213Sgibbs xpt_release_ccb(ccb); 193339213Sgibbs 193441674Smjacob if (error != 0) { 193541674Smjacob /* 193641674Smjacob * If it's less than SCSI-2, READ BLOCK LIMITS is not 193741674Smjacob * a MANDATORY command. Anyway- it doesn't matter- 193841674Smjacob * we can proceed anyway. 193941674Smjacob */ 194041674Smjacob softc->blk_gran = 0; 194141674Smjacob softc->max_blk = ~0; 194241674Smjacob softc->min_blk = 0; 194341674Smjacob } else { 194441674Smjacob if (softc->scsi_rev >= SCSI_REV_3) { 194541674Smjacob softc->blk_gran = RBL_GRAN(rblim); 194641674Smjacob } else { 194741674Smjacob softc->blk_gran = 0; 194841674Smjacob } 194941674Smjacob /* 195041674Smjacob * We take max_blk == min_blk to mean a default to 195141674Smjacob * fixed mode- but note that whatever we get out of 195241674Smjacob * sagetparams below will actually determine whether 195341674Smjacob * we are actually *in* fixed mode. 195441674Smjacob */ 195541674Smjacob softc->max_blk = scsi_3btoul(rblim->maximum); 195641674Smjacob softc->min_blk = scsi_2btoul(rblim->minimum); 195741674Smjacob 195841674Smjacob 195941674Smjacob } 196041674Smjacob /* 196141674Smjacob * Next, perform a mode sense to determine 196241674Smjacob * current density, blocksize, compression etc. 196341674Smjacob */ 196441674Smjacob error = sagetparams(periph, SA_PARAM_ALL, 196541674Smjacob &softc->media_blksize, 196641674Smjacob &softc->media_density, 196741674Smjacob &softc->media_numblks, 196841674Smjacob &softc->buffer_mode, &write_protect, 196941674Smjacob &softc->speed, &comp_supported, 197041674Smjacob &comp_enabled, &softc->comp_algorithm, 197141674Smjacob NULL); 197241674Smjacob 197341674Smjacob if (error != 0) { 197441674Smjacob /* 197541674Smjacob * We could work a little harder here. We could 197641674Smjacob * adjust our attempts to get information. It 197741674Smjacob * might be an ancient tape drive. If someone 197841674Smjacob * nudges us, we'll do that. 197941674Smjacob */ 198039213Sgibbs goto exit; 198141674Smjacob } 198239213Sgibbs 198341906Smjacob /* 198441906Smjacob * If no quirk has determined that this is a device that is 198541906Smjacob * preferred to be in fixed or variable mode, now is the time 198641906Smjacob * to find out. 198741906Smjacob */ 198841906Smjacob if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) { 198941906Smjacob guessing = 1; 199043636Smjacob /* 199143636Smjacob * This could be expensive to find out. Luckily we 199243636Smjacob * only need to do this once. If we start out in 199343636Smjacob * 'default' mode, try and set ourselves to one 199443636Smjacob * of the densities that would determine a wad 199543636Smjacob * of other stuff. Go from highest to lowest. 199643636Smjacob */ 199743636Smjacob if (softc->media_density == SCSI_DEFAULT_DENSITY) { 199843636Smjacob int i; 199943636Smjacob static u_int8_t ctry[] = { 200043636Smjacob SCSI_DENSITY_HALFINCH_PE, 200143636Smjacob SCSI_DENSITY_HALFINCH_6250C, 200243636Smjacob SCSI_DENSITY_HALFINCH_6250, 200343636Smjacob SCSI_DENSITY_HALFINCH_1600, 200443636Smjacob SCSI_DENSITY_HALFINCH_800, 200546962Smjacob SCSI_DENSITY_QIC_4GB, 200646962Smjacob SCSI_DENSITY_QIC_2GB, 200743636Smjacob SCSI_DENSITY_QIC_525_320, 200843636Smjacob SCSI_DENSITY_QIC_150, 200943636Smjacob SCSI_DENSITY_QIC_120, 201043636Smjacob SCSI_DENSITY_QIC_24, 201143636Smjacob SCSI_DENSITY_QIC_11_9TRK, 201243636Smjacob SCSI_DENSITY_QIC_11_4TRK, 201346962Smjacob SCSI_DENSITY_QIC_1320, 201446962Smjacob SCSI_DENSITY_QIC_3080, 201543636Smjacob 0 201643636Smjacob }; 201743636Smjacob for (i = 0; ctry[i]; i++) { 201843636Smjacob error = sasetparams(periph, 201943636Smjacob SA_PARAM_DENSITY, 0, ctry[i], 202043636Smjacob 0, SF_NO_PRINT); 202143636Smjacob if (error == 0) { 202243636Smjacob softc->media_density = ctry[i]; 202343636Smjacob break; 202443636Smjacob } 202543636Smjacob } 202643636Smjacob } 202741906Smjacob switch (softc->media_density) { 202841906Smjacob case SCSI_DENSITY_QIC_11_4TRK: 202941906Smjacob case SCSI_DENSITY_QIC_11_9TRK: 203041906Smjacob case SCSI_DENSITY_QIC_24: 203141906Smjacob case SCSI_DENSITY_QIC_120: 203241906Smjacob case SCSI_DENSITY_QIC_150: 203365861Smjacob case SCSI_DENSITY_QIC_525_320: 203443636Smjacob case SCSI_DENSITY_QIC_1320: 203543636Smjacob case SCSI_DENSITY_QIC_3080: 203646962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 203743636Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 203841906Smjacob softc->last_media_blksize = 512; 203941906Smjacob break; 204046962Smjacob case SCSI_DENSITY_QIC_4GB: 204146962Smjacob case SCSI_DENSITY_QIC_2GB: 204246962Smjacob softc->quirks &= ~SA_QUIRK_2FM; 204346962Smjacob softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM; 204446962Smjacob softc->last_media_blksize = 1024; 204546962Smjacob break; 204641906Smjacob default: 204741906Smjacob softc->last_media_blksize = 204841906Smjacob softc->media_blksize; 204941906Smjacob softc->quirks |= SA_QUIRK_VARIABLE; 205041906Smjacob break; 205141906Smjacob } 205241906Smjacob } 205342563Smjacob 205441906Smjacob /* 205541906Smjacob * If no quirk has determined that this is a device that needs 205641906Smjacob * to have 2 Filemarks at EOD, now is the time to find out. 205741906Smjacob */ 205842563Smjacob 205942735Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) { 206041906Smjacob switch (softc->media_density) { 206141906Smjacob case SCSI_DENSITY_HALFINCH_800: 206241906Smjacob case SCSI_DENSITY_HALFINCH_1600: 206341906Smjacob case SCSI_DENSITY_HALFINCH_6250: 206441906Smjacob case SCSI_DENSITY_HALFINCH_6250C: 206541906Smjacob case SCSI_DENSITY_HALFINCH_PE: 206646962Smjacob softc->quirks &= ~SA_QUIRK_1FM; 206741906Smjacob softc->quirks |= SA_QUIRK_2FM; 206841906Smjacob break; 206941906Smjacob default: 207041906Smjacob break; 207141906Smjacob } 207241906Smjacob } 207341906Smjacob 207441906Smjacob /* 207541906Smjacob * Now validate that some info we got makes sense. 207641906Smjacob */ 207741674Smjacob if ((softc->max_blk < softc->media_blksize) || 207841674Smjacob (softc->min_blk > softc->media_blksize && 207941674Smjacob softc->media_blksize)) { 208041674Smjacob xpt_print_path(ccb->ccb_h.path); 208141674Smjacob printf("BLOCK LIMITS (%d..%d) could not match current " 208241674Smjacob "block settings (%d)- adjusting\n", softc->min_blk, 208341674Smjacob softc->max_blk, softc->media_blksize); 208441674Smjacob softc->max_blk = softc->min_blk = 208541674Smjacob softc->media_blksize; 208641674Smjacob } 208741906Smjacob 208841674Smjacob /* 208941906Smjacob * Now put ourselves into the right frame of mind based 209041906Smjacob * upon quirks... 209141906Smjacob */ 209241906Smjacobtryagain: 209342563Smjacob /* 209442563Smjacob * If we want to be in FIXED mode and our current blocksize 209542563Smjacob * is not equal to our last blocksize (if nonzero), try and 209642563Smjacob * set ourselves to this last blocksize (as the 'preferred' 209742563Smjacob * block size). The initial quirkmatch at registry sets the 209842563Smjacob * initial 'last' blocksize. If, for whatever reason, this 209942563Smjacob * 'last' blocksize is zero, set the blocksize to 512, 210042563Smjacob * or min_blk if that's larger. 210142563Smjacob */ 210241906Smjacob if ((softc->quirks & SA_QUIRK_FIXED) && 210360235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0 && 210442563Smjacob (softc->media_blksize != softc->last_media_blksize)) { 210541906Smjacob softc->media_blksize = softc->last_media_blksize; 210641906Smjacob if (softc->media_blksize == 0) { 210742563Smjacob softc->media_blksize = 512; 210841906Smjacob if (softc->media_blksize < softc->min_blk) { 210941906Smjacob softc->media_blksize = softc->min_blk; 211041906Smjacob } 211141906Smjacob } 211241906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 211342563Smjacob softc->media_blksize, 0, 0, SF_NO_PRINT); 211441906Smjacob if (error) { 211541906Smjacob xpt_print_path(ccb->ccb_h.path); 211641906Smjacob printf("unable to set fixed blocksize to %d\n", 211741906Smjacob softc->media_blksize); 211841906Smjacob goto exit; 211941906Smjacob } 212041906Smjacob } 212141906Smjacob 212241906Smjacob if ((softc->quirks & SA_QUIRK_VARIABLE) && 212341906Smjacob (softc->media_blksize != 0)) { 212441906Smjacob softc->last_media_blksize = softc->media_blksize; 212541906Smjacob softc->media_blksize = 0; 212641906Smjacob error = sasetparams(periph, SA_PARAM_BLOCKSIZE, 212742563Smjacob 0, 0, 0, SF_NO_PRINT); 212841906Smjacob if (error) { 212941906Smjacob /* 213041906Smjacob * If this fails and we were guessing, just 213141906Smjacob * assume that we got it wrong and go try 213242563Smjacob * fixed block mode. Don't even check against 213342563Smjacob * density code at this point. 213441906Smjacob */ 213542563Smjacob if (guessing) { 213641906Smjacob softc->quirks &= ~SA_QUIRK_VARIABLE; 213741906Smjacob softc->quirks |= SA_QUIRK_FIXED; 213841906Smjacob if (softc->last_media_blksize == 0) 213941906Smjacob softc->last_media_blksize = 512; 214041906Smjacob goto tryagain; 214141906Smjacob } 214242563Smjacob xpt_print_path(ccb->ccb_h.path); 214341906Smjacob printf("unable to set variable blocksize\n"); 214441906Smjacob goto exit; 214541906Smjacob } 214641906Smjacob } 214741906Smjacob 214841906Smjacob /* 214941674Smjacob * Now that we have the current block size, 215041674Smjacob * set up some parameters for sastart's usage. 215141674Smjacob */ 215241674Smjacob if (softc->media_blksize) { 215339213Sgibbs softc->flags |= SA_FLAG_FIXED; 215441674Smjacob if (powerof2(softc->media_blksize)) { 215541674Smjacob softc->blk_shift = 215641674Smjacob ffs(softc->media_blksize) - 1; 215741674Smjacob softc->blk_mask = softc->media_blksize - 1; 215839213Sgibbs } else { 215939213Sgibbs softc->blk_mask = ~0; 216039213Sgibbs softc->blk_shift = 0; 216139213Sgibbs } 216239213Sgibbs } else { 216339213Sgibbs /* 216441674Smjacob * The SCSI-3 spec allows 0 to mean "unspecified". 216541674Smjacob * The SCSI-1 spec allows 0 to mean 'infinite'. 216641674Smjacob * 216741674Smjacob * Either works here. 216839213Sgibbs */ 216939213Sgibbs if (softc->max_blk == 0) { 217039213Sgibbs softc->max_blk = ~0; 217139213Sgibbs } 217239213Sgibbs softc->blk_shift = 0; 217339213Sgibbs if (softc->blk_gran != 0) { 217439213Sgibbs softc->blk_mask = softc->blk_gran - 1; 217539213Sgibbs } else { 217639213Sgibbs softc->blk_mask = 0; 217739213Sgibbs } 217839213Sgibbs } 217939213Sgibbs 218039213Sgibbs if (write_protect) 218139213Sgibbs softc->flags |= SA_FLAG_TAPE_WP; 218239213Sgibbs 218339213Sgibbs if (comp_supported) { 218443636Smjacob if (softc->saved_comp_algorithm == 0) 218543636Smjacob softc->saved_comp_algorithm = 218643636Smjacob softc->comp_algorithm; 218746962Smjacob softc->flags |= SA_FLAG_COMP_SUPP; 218846962Smjacob if (comp_enabled) 218946962Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 219039213Sgibbs } else 219139213Sgibbs softc->flags |= SA_FLAG_COMP_UNSUPP; 219239213Sgibbs 219360235Smjacob if ((softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) && 219460235Smjacob (softc->quirks & SA_QUIRK_NO_MODESEL) == 0) { 219541906Smjacob error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0, 219642563Smjacob 0, 0, SF_NO_PRINT); 219741906Smjacob if (error == 0) 219841906Smjacob softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF; 219960235Smjacob xpt_print_path(ccb->ccb_h.path); 220060235Smjacob printf("unable to set buffered mode\n"); 220160235Smjacob error = 0; /* not an error */ 220241906Smjacob } 220339213Sgibbs 220439213Sgibbs 220544354Smjacob if (error == 0) { 220641906Smjacob softc->flags |= SA_FLAG_TAPE_MOUNTED; 220744354Smjacob } 220839213Sgibbsexit: 220939213Sgibbs if (rblim != NULL) 221039213Sgibbs free(rblim, M_TEMP); 221139213Sgibbs 221243636Smjacob if (error != 0) { 221343636Smjacob softc->dsreg = MTIO_DSREG_NIL; 221444354Smjacob } else { 221544354Smjacob softc->fileno = softc->blkno = 0; 221643636Smjacob softc->dsreg = MTIO_DSREG_REST; 221744354Smjacob } 221851875Smjacob#ifdef SA_1FM_AT_EOD 221951875Smjacob if ((softc->quirks & SA_QUIRK_2FM) == 0) 222051875Smjacob softc->quirks |= SA_QUIRK_1FM; 222151875Smjacob#else 222246962Smjacob if ((softc->quirks & SA_QUIRK_1FM) == 0) 222343636Smjacob softc->quirks |= SA_QUIRK_2FM; 222443636Smjacob#endif 222539213Sgibbs } else 222639213Sgibbs xpt_release_ccb(ccb); 222739213Sgibbs 222853259Smjacob /* 222953259Smjacob * If we return an error, we're not mounted any more, 223053259Smjacob * so release any device reservation. 223153259Smjacob */ 223253259Smjacob if (error != 0) { 223353259Smjacob (void) sareservereleaseunit(periph, FALSE); 223453259Smjacob } 223554099Smjacob return (error); 223639213Sgibbs} 223739213Sgibbs 223868114Smjacob/* 223968114Smjacob * How many filemarks do we need to write if we were to terminate the 224068114Smjacob * tape session right now? Note that this can be a negative number 224168114Smjacob */ 224268114Smjacob 224339213Sgibbsstatic int 224468114Smjacobsamarkswanted(struct cam_periph *periph) 224539213Sgibbs{ 224639213Sgibbs int markswanted; 224739213Sgibbs struct sa_softc *softc; 224839213Sgibbs 224939213Sgibbs softc = (struct sa_softc *)periph->softc; 225039213Sgibbs markswanted = 0; 225139213Sgibbs if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) { 225239213Sgibbs markswanted++; 225346962Smjacob if (softc->quirks & SA_QUIRK_2FM) 225439213Sgibbs markswanted++; 225539213Sgibbs } 225668114Smjacob markswanted -= softc->filemarks; 225768114Smjacob return (markswanted); 225868114Smjacob} 225939213Sgibbs 226068114Smjacobstatic int 226168114Smjacobsacheckeod(struct cam_periph *periph) 226268114Smjacob{ 226368114Smjacob int error; 226468114Smjacob int markswanted; 226568114Smjacob struct sa_softc *softc; 226668114Smjacob 226768114Smjacob softc = (struct sa_softc *)periph->softc; 226868114Smjacob markswanted = samarkswanted(periph); 226968114Smjacob 227068114Smjacob if (markswanted > 0) { 227141906Smjacob error = sawritefilemarks(periph, markswanted, FALSE); 227239213Sgibbs } else { 227339213Sgibbs error = 0; 227439213Sgibbs } 227539213Sgibbs return (error); 227639213Sgibbs} 227739213Sgibbs 227839213Sgibbsstatic int 227946962Smjacobsaerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) 228039213Sgibbs{ 228146962Smjacob static const char *toobig = 228246962Smjacob "%d-byte tape record bigger than suplied buffer\n"; 228339213Sgibbs struct cam_periph *periph; 228439213Sgibbs struct sa_softc *softc; 228539213Sgibbs struct ccb_scsiio *csio; 228639213Sgibbs struct scsi_sense_data *sense; 228753259Smjacob u_int32_t resid = 0; 228853259Smjacob int32_t info = 0; 228939213Sgibbs int error_code, sense_key, asc, ascq; 229046962Smjacob int error, defer_action; 229139213Sgibbs 229239213Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 229339213Sgibbs softc = (struct sa_softc *)periph->softc; 229439213Sgibbs csio = &ccb->csio; 229539213Sgibbs sense = &csio->sense_data; 229639213Sgibbs scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); 229739213Sgibbs error = 0; 229846962Smjacob 229946962Smjacob /* 230046962Smjacob * Calculate/latch up, any residuals... 230146962Smjacob */ 230241948Smjacob if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) { 230339213Sgibbs if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { 230446962Smjacob info = (int32_t) scsi_4btoul(sense->info); 230539213Sgibbs resid = info; 230639213Sgibbs if ((softc->flags & SA_FLAG_FIXED) != 0) 230739213Sgibbs resid *= softc->media_blksize; 230839213Sgibbs } else { 230939213Sgibbs resid = csio->dxfer_len; 231039213Sgibbs info = resid; 231141674Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 231241674Smjacob if (softc->media_blksize) 231341674Smjacob info /= softc->media_blksize; 231441674Smjacob } 231539213Sgibbs } 231671082Smjacob if (CCB_Type(csio) == SA_CCB_BUFFER_IO) { 231741948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense, 231841948Smjacob sizeof (struct scsi_sense_data)); 231942009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb, 232042009Smjacob (int) csio->cdb_len); 232141948Smjacob softc->last_io_resid = resid; 232271268Smjacob softc->last_resid_was_io = 1; 232341948Smjacob } else { 232441948Smjacob bcopy((caddr_t) sense, (caddr_t) &softc->last_ctl_sense, 232541948Smjacob sizeof (struct scsi_sense_data)); 232642009Smjacob bcopy(csio->cdb_io.cdb_bytes, softc->last_ctl_cdb, 232742009Smjacob (int) csio->cdb_len); 232841948Smjacob softc->last_ctl_resid = resid; 232971268Smjacob softc->last_resid_was_io = 0; 233041948Smjacob } 233171082Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Key 0x%x ASC/ASCQ " 233271082Smjacob "0x%x 0x%x flags 0x%x resid %d dxfer_len %d\n", sense_key, 233353259Smjacob asc, ascq, sense->flags & ~SSD_KEY_RESERVED, resid, 233453259Smjacob csio->dxfer_len)); 233553259Smjacob } else { 233653259Smjacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Cam Status 0x%x\n", 233753259Smjacob csio->ccb_h.status & CAM_STATUS_MASK)); 233841948Smjacob } 233941948Smjacob 234046962Smjacob /* 234146962Smjacob * If it's neither a SCSI Check Condition Error nor a non-read/write 234246962Smjacob * command, let the common code deal with it the error setting. 234346962Smjacob */ 234446962Smjacob if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR || 234571082Smjacob (CCB_Type(csio) == SA_CCB_WAITING)) { 234646962Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 234746962Smjacob } 234841948Smjacob 234946962Smjacob /* 235046962Smjacob * Calculate whether we'll defer action. 235146962Smjacob */ 235246962Smjacob 235346962Smjacob if (resid > 0 && resid < csio->dxfer_len && 235446962Smjacob (softc->flags & SA_FLAG_FIXED) != 0) { 235546962Smjacob defer_action = TRUE; 235646962Smjacob } else { 235746962Smjacob defer_action = FALSE; 235846962Smjacob } 235946962Smjacob 236046962Smjacob /* 236146962Smjacob * Handle filemark, end of tape, mismatched record sizes.... 236246962Smjacob * From this point out, we're only handling read/write cases. 236346962Smjacob * Handle writes && reads differently. 236446962Smjacob */ 236546962Smjacob 236646962Smjacob if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) { 236746962Smjacob if (sense->flags & SSD_FILEMARK) { 236846962Smjacob xpt_print_path(csio->ccb_h.path); 236946962Smjacob printf("filemark detected on write?\n"); 237046962Smjacob if (softc->fileno != (daddr_t) -1) { 237146962Smjacob softc->fileno++; 237246962Smjacob softc->blkno = 0; 237371082Smjacob csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED; 237446962Smjacob } 237546962Smjacob } 237646962Smjacob if (sense->flags & SSD_EOM) { 237739213Sgibbs csio->resid = resid; 237839213Sgibbs if (defer_action) { 237946962Smjacob error = -1; 238039213Sgibbs softc->flags |= SA_FLAG_EOM_PENDING; 238139213Sgibbs } else { 238246962Smjacob error = ENOSPC; 238339213Sgibbs } 238439213Sgibbs } 238546962Smjacob } else { 238646962Smjacob if (sense_key == SSD_KEY_BLANK_CHECK) { 238739213Sgibbs csio->resid = resid; 238846962Smjacob if (defer_action) { 238946962Smjacob error = -1; 239046962Smjacob softc->flags |= SA_FLAG_EOM_PENDING; 239146962Smjacob } else { 239246962Smjacob error = EIO; 239346962Smjacob } 239446962Smjacob } 239546962Smjacob if (sense->flags & SSD_FILEMARK) { 239646962Smjacob csio->resid = resid; 239746962Smjacob if (defer_action) { 239846962Smjacob error = -1; 239939213Sgibbs softc->flags |= SA_FLAG_EOF_PENDING; 240046962Smjacob } 240146962Smjacob /* 240246962Smjacob * Unconditionally, if we detected a filemark on a read, 240346962Smjacob * mark that we've run moved a file ahead. 240446962Smjacob */ 240543636Smjacob if (softc->fileno != (daddr_t) -1) { 240643636Smjacob softc->fileno++; 240743636Smjacob softc->blkno = 0; 240871082Smjacob csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED; 240943636Smjacob } 241039213Sgibbs } 241146962Smjacob } 241246962Smjacob /* 241346962Smjacob * Incorrect Length usually applies to read, but can apply to writes. 241446962Smjacob */ 241546962Smjacob if (error == 0 && (sense->flags & SSD_ILI)) { 241646962Smjacob if (info < 0) { 241746962Smjacob xpt_print_path(csio->ccb_h.path); 241846962Smjacob printf(toobig, csio->dxfer_len - info); 241946962Smjacob csio->resid = csio->dxfer_len; 242046962Smjacob error = EIO; 242146962Smjacob } else { 242246962Smjacob csio->resid = resid; 242346962Smjacob if ((softc->flags & SA_FLAG_FIXED) != 0) { 242446962Smjacob if (defer_action) 242546962Smjacob softc->flags |= SA_FLAG_EIO_PENDING; 242646962Smjacob else 242746962Smjacob error = EIO; 242846962Smjacob } 242946962Smjacob /* 243046962Smjacob * Bump the block number if we hadn't seen a filemark. 243146962Smjacob * Do this independent of errors (we've moved anyway). 243246962Smjacob */ 243346962Smjacob if ((sense->flags & SSD_FILEMARK) == 0) { 243446962Smjacob if (softc->blkno != (daddr_t) -1) { 243546962Smjacob softc->blkno++; 243671082Smjacob csio->ccb_h.ccb_pflags |= 243771082Smjacob SA_POSITION_UPDATED; 243839213Sgibbs } 243939213Sgibbs } 244039213Sgibbs } 244139213Sgibbs } 244239213Sgibbs if (error == 0) 244346962Smjacob return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); 244439213Sgibbs 244546962Smjacob if (error == -1) 244646962Smjacob return (0); 244746962Smjacob else 244846962Smjacob return (error); 244939213Sgibbs} 245039213Sgibbs 245139213Sgibbsstatic int 245239213Sgibbssagetparams(struct cam_periph *periph, sa_params params_to_get, 245339213Sgibbs u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks, 245439213Sgibbs int *buff_mode, u_int8_t *write_protect, u_int8_t *speed, 245539213Sgibbs int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm, 245646962Smjacob sa_comp_t *tcs) 245739213Sgibbs{ 245839213Sgibbs union ccb *ccb; 245939213Sgibbs void *mode_buffer; 246039213Sgibbs struct scsi_mode_header_6 *mode_hdr; 246139213Sgibbs struct scsi_mode_blk_desc *mode_blk; 246239213Sgibbs int mode_buffer_len; 246339213Sgibbs struct sa_softc *softc; 246446962Smjacob u_int8_t cpage; 246539213Sgibbs int error; 246639213Sgibbs cam_status status; 246739213Sgibbs 246839213Sgibbs softc = (struct sa_softc *)periph->softc; 246946962Smjacob ccb = cam_periph_getccb(periph, 1); 247071082Smjacob if (softc->quirks & SA_QUIRK_NO_CPAGE) 247171082Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 247271082Smjacob else 247371082Smjacob cpage = SA_DATA_COMPRESSION_PAGE; 247439213Sgibbs 247539213Sgibbsretry: 247639213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 247739213Sgibbs 247839213Sgibbs if (params_to_get & SA_PARAM_COMPRESSION) { 247939213Sgibbs if (softc->quirks & SA_QUIRK_NOCOMP) { 248039213Sgibbs *comp_supported = FALSE; 248139213Sgibbs params_to_get &= ~SA_PARAM_COMPRESSION; 248239213Sgibbs } else 248346962Smjacob mode_buffer_len += sizeof (sa_comp_t); 248439213Sgibbs } 248554099Smjacob 248667723Smjacob mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO); 248739213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 248839213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 248939213Sgibbs 249042716Smjacob /* it is safe to retry this */ 249142716Smjacob scsi_mode_sense(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 249242716Smjacob SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ? 249346962Smjacob cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len, 249446962Smjacob SSD_FULL_SIZE, 5000); 249539213Sgibbs 249654099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 249754099Smjacob &softc->device_stats); 249854099Smjacob QFRLS(ccb); 249939213Sgibbs 250039213Sgibbs status = ccb->ccb_h.status & CAM_STATUS_MASK; 250139213Sgibbs 250242716Smjacob if (error == EINVAL && (params_to_get & SA_PARAM_COMPRESSION) != 0) { 250339213Sgibbs /* 250446962Smjacob * Hmm. Let's see if we can try another page... 250546962Smjacob * If we've already done that, give up on compression 250646962Smjacob * for this device and remember this for the future 250746962Smjacob * and attempt the request without asking for compression 250846962Smjacob * info. 250939213Sgibbs */ 251046962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 251146962Smjacob cpage = SA_DEVICE_CONFIGURATION_PAGE; 251246962Smjacob goto retry; 251346962Smjacob } 251439213Sgibbs softc->quirks |= SA_QUIRK_NOCOMP; 251539213Sgibbs free(mode_buffer, M_TEMP); 251639213Sgibbs goto retry; 251746962Smjacob } else if (status == CAM_SCSI_STATUS_ERROR) { 251846962Smjacob /* Tell the user about the fatal error. */ 251946962Smjacob scsi_sense_print(&ccb->csio); 252046962Smjacob goto sagetparamsexit; 252146962Smjacob } 252239213Sgibbs 252346962Smjacob /* 252446962Smjacob * If the user only wants the compression information, and 252546962Smjacob * the device doesn't send back the block descriptor, it's 252646962Smjacob * no big deal. If the user wants more than just 252746962Smjacob * compression, though, and the device doesn't pass back the 252846962Smjacob * block descriptor, we need to send another mode sense to 252946962Smjacob * get the block descriptor. 253046962Smjacob */ 253146962Smjacob if ((mode_hdr->blk_desc_len == 0) && 253246962Smjacob (params_to_get & SA_PARAM_COMPRESSION) && 253346962Smjacob (params_to_get & ~(SA_PARAM_COMPRESSION))) { 253439213Sgibbs 253539213Sgibbs /* 253646962Smjacob * Decrease the mode buffer length by the size of 253746962Smjacob * the compression page, to make sure the data 253846962Smjacob * there doesn't get overwritten. 253939213Sgibbs */ 254046962Smjacob mode_buffer_len -= sizeof (sa_comp_t); 254139213Sgibbs 254246962Smjacob /* 254346962Smjacob * Now move the compression page that we presumably 254446962Smjacob * got back down the memory chunk a little bit so 254546962Smjacob * it doesn't get spammed. 254646962Smjacob */ 254754099Smjacob bcopy(&mode_hdr[0], &mode_hdr[1], sizeof (sa_comp_t)); 254854099Smjacob bzero(&mode_hdr[0], sizeof (mode_hdr[0])); 254939213Sgibbs 255046962Smjacob /* 255146962Smjacob * Now, we issue another mode sense and just ask 255246962Smjacob * for the block descriptor, etc. 255346962Smjacob */ 255439213Sgibbs 255546962Smjacob scsi_mode_sense(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 255646962Smjacob SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE, 255746962Smjacob mode_buffer, mode_buffer_len, SSD_FULL_SIZE, 5000); 255839213Sgibbs 255954099Smjacob error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT, 256046962Smjacob &softc->device_stats); 256154099Smjacob QFRLS(ccb); 256239213Sgibbs 256346962Smjacob if (error != 0) 256446962Smjacob goto sagetparamsexit; 256546962Smjacob } 256639213Sgibbs 256746962Smjacob if (params_to_get & SA_PARAM_BLOCKSIZE) 256846962Smjacob *blocksize = scsi_3btoul(mode_blk->blklen); 256939213Sgibbs 257046962Smjacob if (params_to_get & SA_PARAM_NUMBLOCKS) 257146962Smjacob *numblocks = scsi_3btoul(mode_blk->nblocks); 257239213Sgibbs 257346962Smjacob if (params_to_get & SA_PARAM_BUFF_MODE) 257446962Smjacob *buff_mode = mode_hdr->dev_spec & SMH_SA_BUF_MODE_MASK; 257539213Sgibbs 257646962Smjacob if (params_to_get & SA_PARAM_DENSITY) 257746962Smjacob *density = mode_blk->density; 257839213Sgibbs 257946962Smjacob if (params_to_get & SA_PARAM_WP) 258046962Smjacob *write_protect = (mode_hdr->dev_spec & SMH_SA_WP)? TRUE : FALSE; 258139213Sgibbs 258246962Smjacob if (params_to_get & SA_PARAM_SPEED) 258346962Smjacob *speed = mode_hdr->dev_spec & SMH_SA_SPEED_MASK; 258439213Sgibbs 258546962Smjacob if (params_to_get & SA_PARAM_COMPRESSION) { 258654099Smjacob sa_comp_t *ntcs = (sa_comp_t *) &mode_blk[1]; 258746962Smjacob if (cpage == SA_DATA_COMPRESSION_PAGE) { 258846962Smjacob struct scsi_data_compression_page *cp = &ntcs->dcomp; 258946962Smjacob *comp_supported = 259046962Smjacob (cp->dce_and_dcc & SA_DCP_DCC)? TRUE : FALSE; 259146962Smjacob *comp_enabled = 259246962Smjacob (cp->dce_and_dcc & SA_DCP_DCE)? TRUE : FALSE; 259346962Smjacob *comp_algorithm = scsi_4btoul(cp->comp_algorithm); 259446962Smjacob } else { 259546962Smjacob struct scsi_dev_conf_page *cp = &ntcs->dconf; 259646962Smjacob /* 259746962Smjacob * We don't really know whether this device supports 259846962Smjacob * Data Compression if the the algorithm field is 259946962Smjacob * zero. Just say we do. 260046962Smjacob */ 260146962Smjacob *comp_supported = TRUE; 260246962Smjacob *comp_enabled = 260346962Smjacob (cp->sel_comp_alg != SA_COMP_NONE)? TRUE : FALSE; 260446962Smjacob *comp_algorithm = cp->sel_comp_alg; 260541906Smjacob } 260646962Smjacob if (tcs != NULL) 260754099Smjacob bcopy(ntcs, tcs, sizeof (sa_comp_t)); 260839213Sgibbs } 260939213Sgibbs 261046962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 261146962Smjacob int idx; 261246962Smjacob char *xyz = mode_buffer; 261346962Smjacob xpt_print_path(periph->path); 261446962Smjacob printf("Mode Sense Data="); 261546962Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 261646962Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 261746962Smjacob printf("\n"); 261846962Smjacob } 261946962Smjacob 262039213Sgibbssagetparamsexit: 262139213Sgibbs 262239213Sgibbs xpt_release_ccb(ccb); 262339213Sgibbs free(mode_buffer, M_TEMP); 262454099Smjacob return (error); 262539213Sgibbs} 262639213Sgibbs 262739213Sgibbs/* 262839213Sgibbs * The purpose of this function is to set one of four different parameters 262939213Sgibbs * for a tape drive: 263039213Sgibbs * - blocksize 263139213Sgibbs * - density 263239213Sgibbs * - compression / compression algorithm 263339213Sgibbs * - buffering mode 263439213Sgibbs * 263539213Sgibbs * The assumption is that this will be called from saioctl(), and therefore 263639213Sgibbs * from a process context. Thus the waiting malloc calls below. If that 263739213Sgibbs * assumption ever changes, the malloc calls should be changed to be 263839213Sgibbs * NOWAIT mallocs. 263939213Sgibbs * 264039213Sgibbs * Any or all of the four parameters may be set when this function is 264139213Sgibbs * called. It should handle setting more than one parameter at once. 264239213Sgibbs */ 264339213Sgibbsstatic int 264439213Sgibbssasetparams(struct cam_periph *periph, sa_params params_to_set, 264546962Smjacob u_int32_t blocksize, u_int8_t density, u_int32_t calg, 264642563Smjacob u_int32_t sense_flags) 264739213Sgibbs{ 264839213Sgibbs struct sa_softc *softc; 264939213Sgibbs u_int32_t current_blocksize; 265046962Smjacob u_int32_t current_calg; 265139213Sgibbs u_int8_t current_density; 265239213Sgibbs u_int8_t current_speed; 265339213Sgibbs int comp_enabled, comp_supported; 265439213Sgibbs void *mode_buffer; 265539213Sgibbs int mode_buffer_len; 265639213Sgibbs struct scsi_mode_header_6 *mode_hdr; 265739213Sgibbs struct scsi_mode_blk_desc *mode_blk; 265846962Smjacob sa_comp_t *ccomp, *cpage; 265939213Sgibbs int buff_mode; 266046962Smjacob union ccb *ccb = NULL; 266139213Sgibbs int error; 266239213Sgibbs 266339213Sgibbs softc = (struct sa_softc *)periph->softc; 266439213Sgibbs 266546962Smjacob ccomp = malloc(sizeof (sa_comp_t), M_TEMP, M_WAITOK); 266639213Sgibbs 266739213Sgibbs /* 266839213Sgibbs * Since it doesn't make sense to set the number of blocks, or 266939213Sgibbs * write protection, we won't try to get the current value. We 267039213Sgibbs * always want to get the blocksize, so we can set it back to the 267139213Sgibbs * proper value. 267239213Sgibbs */ 267346962Smjacob error = sagetparams(periph, 267446962Smjacob params_to_set | SA_PARAM_BLOCKSIZE | SA_PARAM_SPEED, 267546962Smjacob ¤t_blocksize, ¤t_density, NULL, &buff_mode, NULL, 267646962Smjacob ¤t_speed, &comp_supported, &comp_enabled, 267746962Smjacob ¤t_calg, ccomp); 267839213Sgibbs 267939213Sgibbs if (error != 0) { 268046962Smjacob free(ccomp, M_TEMP); 268154099Smjacob return (error); 268239213Sgibbs } 268339213Sgibbs 268439213Sgibbs mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk); 268539213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 268646962Smjacob mode_buffer_len += sizeof (sa_comp_t); 268739213Sgibbs 268867723Smjacob mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO); 268939213Sgibbs 269039213Sgibbs mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; 269139213Sgibbs mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 269239213Sgibbs 269353259Smjacob ccb = cam_periph_getccb(periph, 1); 269453259Smjacob 269553259Smjacobretry: 269653259Smjacob 269739213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) { 269853259Smjacob if (mode_blk) { 269953259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 270053259Smjacob } else { 270153259Smjacob cpage = (sa_comp_t *)&mode_hdr[1]; 270253259Smjacob } 270346962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 270454099Smjacob cpage->hdr.pagecode &= ~0x80; 270539213Sgibbs } else 270646962Smjacob cpage = NULL; 270739213Sgibbs 270839213Sgibbs /* 270939213Sgibbs * If the caller wants us to set the blocksize, use the one they 271039213Sgibbs * pass in. Otherwise, use the blocksize we got back from the 271139213Sgibbs * mode select above. 271239213Sgibbs */ 271353259Smjacob if (mode_blk) { 271453259Smjacob if (params_to_set & SA_PARAM_BLOCKSIZE) 271553259Smjacob scsi_ulto3b(blocksize, mode_blk->blklen); 271653259Smjacob else 271753259Smjacob scsi_ulto3b(current_blocksize, mode_blk->blklen); 271839213Sgibbs 271953259Smjacob /* 272053259Smjacob * Set density if requested, else preserve old density. 272153259Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 272253259Smjacob * devices, else density we've latched up in our softc. 272353259Smjacob */ 272453259Smjacob if (params_to_set & SA_PARAM_DENSITY) { 272553259Smjacob mode_blk->density = density; 272653259Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 272753259Smjacob mode_blk->density = SCSI_SAME_DENSITY; 272853259Smjacob } else { 272953259Smjacob mode_blk->density = softc->media_density; 273053259Smjacob } 273141674Smjacob } 273239213Sgibbs 273339213Sgibbs /* 273439213Sgibbs * For mode selects, these two fields must be zero. 273539213Sgibbs */ 273639213Sgibbs mode_hdr->data_length = 0; 273739213Sgibbs mode_hdr->medium_type = 0; 273839213Sgibbs 273939213Sgibbs /* set the speed to the current value */ 274039213Sgibbs mode_hdr->dev_spec = current_speed; 274139213Sgibbs 274239213Sgibbs /* set single-initiator buffering mode */ 274339213Sgibbs mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF; 274439213Sgibbs 274553259Smjacob if (mode_blk) 274653259Smjacob mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc); 274753259Smjacob else 274853259Smjacob mode_hdr->blk_desc_len = 0; 274939213Sgibbs 275039213Sgibbs /* 275139213Sgibbs * First, if the user wants us to set the compression algorithm or 275239213Sgibbs * just turn compression on, check to make sure that this drive 275339213Sgibbs * supports compression. 275439213Sgibbs */ 275546962Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 275639213Sgibbs /* 275739213Sgibbs * If the compression algorithm is 0, disable compression. 275839213Sgibbs * If the compression algorithm is non-zero, enable 275939213Sgibbs * compression and set the compression type to the 276039213Sgibbs * specified compression algorithm, unless the algorithm is 276139213Sgibbs * MT_COMP_ENABLE. In that case, we look at the 276239213Sgibbs * compression algorithm that is currently set and if it is 276339213Sgibbs * non-zero, we leave it as-is. If it is zero, and we have 276439213Sgibbs * saved a compression algorithm from a time when 276539213Sgibbs * compression was enabled before, set the compression to 276639213Sgibbs * the saved value. 276739213Sgibbs */ 276854099Smjacob switch (ccomp->hdr.pagecode & ~0x80) { 276946962Smjacob case SA_DATA_COMPRESSION_PAGE: 277046962Smjacob if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) { 277146962Smjacob struct scsi_data_compression_page *dcp = &cpage->dcomp; 277246962Smjacob if (calg == 0) { 277354099Smjacob /* 277454099Smjacob * Disable compression, but leave the 277554099Smjacob * decompression and the capability bit 277654099Smjacob * alone. 277754099Smjacob */ 277854099Smjacob dcp->dce_and_dcc = SA_DCP_DCC; 277954099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 278046962Smjacob break; 278146962Smjacob } 278253259Smjacob /* enable compression && decompression */ 278354099Smjacob dcp->dce_and_dcc = SA_DCP_DCE | SA_DCP_DCC; 278454099Smjacob dcp->dde_and_red |= SA_DCP_DDE; 278553259Smjacob /* 278653259Smjacob * If there, use compression algorithm from caller. 278753259Smjacob * Otherwise, if there's a saved compression algorithm 278853259Smjacob * and there is no current algorithm, use the saved 278953259Smjacob * algorithm. Else parrot back what we got and hope 279053259Smjacob * for the best. 279153259Smjacob */ 279246962Smjacob if (calg != MT_COMP_ENABLE) { 279346962Smjacob scsi_ulto4b(calg, dcp->comp_algorithm); 279453259Smjacob scsi_ulto4b(calg, dcp->decomp_algorithm); 279546962Smjacob } else if (scsi_4btoul(dcp->comp_algorithm) == 0 && 279646962Smjacob softc->saved_comp_algorithm != 0) { 279739213Sgibbs scsi_ulto4b(softc->saved_comp_algorithm, 279846962Smjacob dcp->comp_algorithm); 279953259Smjacob scsi_ulto4b(softc->saved_comp_algorithm, 280053259Smjacob dcp->decomp_algorithm); 280139213Sgibbs } 280246962Smjacob break; 280339213Sgibbs } 280453259Smjacob case SA_DEVICE_CONFIGURATION_PAGE: 280546962Smjacob { 280646962Smjacob struct scsi_dev_conf_page *dcp = &cpage->dconf; 280746962Smjacob if (calg == 0) { 280846962Smjacob dcp->sel_comp_alg = SA_COMP_NONE; 280946962Smjacob break; 281046962Smjacob } 281146962Smjacob if (calg != MT_COMP_ENABLE) { 281246962Smjacob dcp->sel_comp_alg = calg; 281346962Smjacob } else if (dcp->sel_comp_alg == SA_COMP_NONE && 281446962Smjacob softc->saved_comp_algorithm != 0) { 281546962Smjacob dcp->sel_comp_alg = softc->saved_comp_algorithm; 281646962Smjacob } 281746962Smjacob break; 281839213Sgibbs } 281946962Smjacob default: 282046962Smjacob /* 282154099Smjacob * The drive doesn't seem to support compression, 282246962Smjacob * so turn off the set compression bit. 282346962Smjacob */ 282446962Smjacob params_to_set &= ~SA_PARAM_COMPRESSION; 282546962Smjacob xpt_print_path(periph->path); 282654099Smjacob printf("device does not seem to support compression\n"); 282754099Smjacob 282846962Smjacob /* 282946962Smjacob * If that was the only thing the user wanted us to set, 283046962Smjacob * clean up allocated resources and return with 283146962Smjacob * 'operation not supported'. 283246962Smjacob */ 283346962Smjacob if (params_to_set == SA_PARAM_NONE) { 283446962Smjacob free(mode_buffer, M_TEMP); 283554099Smjacob xpt_release_ccb(ccb); 283654099Smjacob return (ENODEV); 283746962Smjacob } 283846962Smjacob 283946962Smjacob /* 284046962Smjacob * That wasn't the only thing the user wanted us to set. 284146962Smjacob * So, decrease the stated mode buffer length by the 284246962Smjacob * size of the compression mode page. 284346962Smjacob */ 284446962Smjacob mode_buffer_len -= sizeof(sa_comp_t); 284546962Smjacob } 284639213Sgibbs } 284739213Sgibbs 284846962Smjacob /* It is safe to retry this operation */ 284946962Smjacob scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, 285046962Smjacob (params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE, 285146962Smjacob FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, 5000); 285241674Smjacob 285346962Smjacob error = cam_periph_runccb(ccb, saerror, 0, 285446962Smjacob sense_flags, &softc->device_stats); 285554099Smjacob QFRLS(ccb); 285639213Sgibbs 285746962Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 285841906Smjacob int idx; 285941674Smjacob char *xyz = mode_buffer; 286041674Smjacob xpt_print_path(periph->path); 286142009Smjacob printf("Err%d, Mode Select Data=", error); 286241906Smjacob for (idx = 0; idx < mode_buffer_len; idx++) 286342009Smjacob printf(" 0x%02x", xyz[idx] & 0xff); 286441674Smjacob printf("\n"); 286541674Smjacob } 286641674Smjacob 286739213Sgibbs 286853259Smjacob if (error) { 286939213Sgibbs /* 287053259Smjacob * If we can, try without setting density/blocksize. 287153259Smjacob */ 287253259Smjacob if (mode_blk) { 287353259Smjacob if ((params_to_set & 287453259Smjacob (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) { 287553259Smjacob mode_blk = NULL; 287653259Smjacob goto retry; 287753259Smjacob } 287853259Smjacob } else { 287953259Smjacob mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; 288053259Smjacob cpage = (sa_comp_t *)&mode_blk[1]; 288153259Smjacob } 288253259Smjacob 288353259Smjacob /* 288439213Sgibbs * If we were setting the blocksize, and that failed, we 288539213Sgibbs * want to set it to its original value. If we weren't 288639213Sgibbs * setting the blocksize, we don't want to change it. 288739213Sgibbs */ 288839213Sgibbs scsi_ulto3b(current_blocksize, mode_blk->blklen); 288939213Sgibbs 289039213Sgibbs /* 289141674Smjacob * Set density if requested, else preserve old density. 289241674Smjacob * SCSI_SAME_DENSITY only applies to SCSI-2 or better 289341674Smjacob * devices, else density we've latched up in our softc. 289439213Sgibbs */ 289541674Smjacob if (params_to_set & SA_PARAM_DENSITY) { 289639213Sgibbs mode_blk->density = current_density; 289741674Smjacob } else if (softc->scsi_rev > SCSI_REV_CCS) { 289841674Smjacob mode_blk->density = SCSI_SAME_DENSITY; 289941674Smjacob } else { 290041674Smjacob mode_blk->density = softc->media_density; 290141674Smjacob } 290239213Sgibbs 290339213Sgibbs if (params_to_set & SA_PARAM_COMPRESSION) 290446962Smjacob bcopy(ccomp, cpage, sizeof (sa_comp_t)); 290539213Sgibbs 290639213Sgibbs /* 290739213Sgibbs * The retry count is the only CCB field that might have been 290839213Sgibbs * changed that we care about, so reset it back to 1. 290939213Sgibbs */ 291039213Sgibbs ccb->ccb_h.retry_count = 1; 291154099Smjacob cam_periph_runccb(ccb, saerror, 0, sense_flags, 291254099Smjacob &softc->device_stats); 291354099Smjacob QFRLS(ccb); 291439213Sgibbs } 291539213Sgibbs 291653259Smjacob xpt_release_ccb(ccb); 291753259Smjacob 291846962Smjacob if (ccomp != NULL) 291946962Smjacob free(ccomp, M_TEMP); 292039213Sgibbs 292141948Smjacob if (params_to_set & SA_PARAM_COMPRESSION) { 292241948Smjacob if (error) { 292341948Smjacob softc->flags &= ~SA_FLAG_COMP_ENABLED; 292446962Smjacob /* 292546962Smjacob * Even if we get an error setting compression, 292646962Smjacob * do not say that we don't support it. We could 292746962Smjacob * have been wrong, or it may be media specific. 292846962Smjacob * softc->flags &= ~SA_FLAG_COMP_SUPP; 292946962Smjacob */ 293041948Smjacob softc->saved_comp_algorithm = softc->comp_algorithm; 293141948Smjacob softc->comp_algorithm = 0; 293241948Smjacob } else { 293341948Smjacob softc->flags |= SA_FLAG_COMP_ENABLED; 293446962Smjacob softc->comp_algorithm = calg; 293541948Smjacob } 293641948Smjacob } 293741948Smjacob 293839213Sgibbs free(mode_buffer, M_TEMP); 293954099Smjacob return (error); 294039213Sgibbs} 294139213Sgibbs 294239213Sgibbsstatic void 294339213Sgibbssaprevent(struct cam_periph *periph, int action) 294439213Sgibbs{ 294539213Sgibbs struct sa_softc *softc; 294639213Sgibbs union ccb *ccb; 294742735Smjacob int error, sf; 294839213Sgibbs 294939213Sgibbs softc = (struct sa_softc *)periph->softc; 295039213Sgibbs 295142735Smjacob if ((action == PR_ALLOW) && (softc->flags & SA_FLAG_TAPE_LOCKED) == 0) 295239213Sgibbs return; 295342735Smjacob if ((action == PR_PREVENT) && (softc->flags & SA_FLAG_TAPE_LOCKED) != 0) 295442735Smjacob return; 295539213Sgibbs 295656981Smjacob /* 295756981Smjacob * We can be quiet about illegal requests. 295856981Smjacob */ 295956981Smjacob if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { 296042735Smjacob sf = 0; 296156981Smjacob } else 296242735Smjacob sf = SF_QUIET_IR; 296342735Smjacob 296442716Smjacob ccb = cam_periph_getccb(periph, 1); 296539213Sgibbs 296642716Smjacob /* It is safe to retry this operation */ 296742716Smjacob scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action, 296853259Smjacob SSD_FULL_SIZE, 100000); 296939213Sgibbs 297043636Smjacob error = cam_periph_runccb(ccb, saerror, 0, sf, &softc->device_stats); 297153522Smjacob QFRLS(ccb); 297239213Sgibbs if (error == 0) { 297339213Sgibbs if (action == PR_ALLOW) 297439213Sgibbs softc->flags &= ~SA_FLAG_TAPE_LOCKED; 297539213Sgibbs else 297639213Sgibbs softc->flags |= SA_FLAG_TAPE_LOCKED; 297739213Sgibbs } 297839213Sgibbs 297939213Sgibbs xpt_release_ccb(ccb); 298039213Sgibbs} 298139213Sgibbs 298239213Sgibbsstatic int 298339213Sgibbssarewind(struct cam_periph *periph) 298439213Sgibbs{ 298539213Sgibbs union ccb *ccb; 298639213Sgibbs struct sa_softc *softc; 298739213Sgibbs int error; 298839213Sgibbs 298939213Sgibbs softc = (struct sa_softc *)periph->softc; 299039213Sgibbs 299146962Smjacob ccb = cam_periph_getccb(periph, 1); 299239213Sgibbs 299342716Smjacob /* It is safe to retry this operation */ 299446962Smjacob scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE, 299553259Smjacob SSD_FULL_SIZE, REWIND_TIMEOUT); 299639213Sgibbs 299743636Smjacob softc->dsreg = MTIO_DSREG_REW; 299842716Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 299943636Smjacob softc->dsreg = MTIO_DSREG_REST; 300039213Sgibbs 300139213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 300242716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 300342716Smjacob 300439213Sgibbs xpt_release_ccb(ccb); 300543636Smjacob if (error == 0) 300643636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 300743636Smjacob else 300843636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 300939213Sgibbs return (error); 301039213Sgibbs} 301139213Sgibbs 301239213Sgibbsstatic int 301339213Sgibbssaspace(struct cam_periph *periph, int count, scsi_space_code code) 301439213Sgibbs{ 301539213Sgibbs union ccb *ccb; 301639213Sgibbs struct sa_softc *softc; 301739213Sgibbs int error; 301839213Sgibbs 301939213Sgibbs softc = (struct sa_softc *)periph->softc; 302039213Sgibbs 302146962Smjacob ccb = cam_periph_getccb(periph, 1); 302239213Sgibbs 302342716Smjacob /* This cannot be retried */ 302439213Sgibbs 302542716Smjacob scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count, 302653259Smjacob SSD_FULL_SIZE, SPACE_TIMEOUT); 302739213Sgibbs 302871087Smjacob /* 302971087Smjacob * Clear residual because we will be using it. 303071087Smjacob */ 303171087Smjacob softc->last_ctl_resid = 0; 303271087Smjacob 303343636Smjacob softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD; 303442716Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 303543636Smjacob softc->dsreg = MTIO_DSREG_REST; 303642716Smjacob 303739213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 303842716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 303942716Smjacob 304039213Sgibbs xpt_release_ccb(ccb); 304143636Smjacob 304242716Smjacob /* 304343636Smjacob * If a spacing operation has failed, we need to invalidate 304443636Smjacob * this mount. 304543636Smjacob * 304643636Smjacob * If the spacing operation was setmarks or to end of recorded data, 304743636Smjacob * we no longer know our relative position. 304843636Smjacob * 304971087Smjacob * If the spacing operations was spacing files in reverse, we 305071087Smjacob * take account of the residual, but still check against less 305171087Smjacob * than zero- if we've gone negative, we must have hit BOT. 305271087Smjacob * 305371087Smjacob * If the spacing operations was spacing records in reverse and 305471087Smjacob * we have a residual, we've either hit BOT or hit a filemark. 305571087Smjacob * In the former case, we know our new record number (0). In 305671087Smjacob * the latter case, we have absolutely no idea what the real 305771087Smjacob * record number is- we've stopped between the end of the last 305871087Smjacob * record in the previous file and the filemark that stopped 305971087Smjacob * our spacing backwards. 306042716Smjacob */ 306143636Smjacob if (error) { 306243636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 306343636Smjacob } else if (code == SS_SETMARKS || code == SS_EOD) { 306443636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 306543636Smjacob } else if (code == SS_FILEMARKS && softc->fileno != (daddr_t) -1) { 306671087Smjacob softc->fileno += (count - softc->last_ctl_resid); 306771087Smjacob if (softc->fileno < 0) /* we must of hit BOT */ 306871087Smjacob softc->fileno = 0; 306943636Smjacob softc->blkno = 0; 307043636Smjacob } else if (code == SS_BLOCKS && softc->blkno != (daddr_t) -1) { 307171087Smjacob softc->blkno += (count - softc->last_ctl_resid); 307271087Smjacob if (count < 0) { 307371087Smjacob if (softc->last_ctl_resid || softc->blkno < 0) { 307471087Smjacob if (softc->fileno == 0) { 307571087Smjacob softc->blkno = 0; 307671087Smjacob } else { 307771087Smjacob softc->blkno = (daddr_t) -1; 307871087Smjacob } 307971087Smjacob } 308071087Smjacob } 308143636Smjacob } 308239213Sgibbs return (error); 308339213Sgibbs} 308439213Sgibbs 308539213Sgibbsstatic int 308639213Sgibbssawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks) 308739213Sgibbs{ 308839213Sgibbs union ccb *ccb; 308939213Sgibbs struct sa_softc *softc; 309071087Smjacob int error, nwm = 0; 309139213Sgibbs 309239213Sgibbs softc = (struct sa_softc *)periph->softc; 309339213Sgibbs 309446962Smjacob ccb = cam_periph_getccb(periph, 1); 309571087Smjacob /* 309671087Smjacob * Clear residual because we will be using it. 309771087Smjacob */ 309871087Smjacob softc->last_ctl_resid = 0; 309939213Sgibbs 310043636Smjacob softc->dsreg = MTIO_DSREG_FMK; 310142716Smjacob /* this *must* not be retried */ 310242716Smjacob scsi_write_filemarks(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, 310341918Smjacob FALSE, setmarks, nmarks, SSD_FULL_SIZE, 60000); 310443636Smjacob softc->dsreg = MTIO_DSREG_REST; 310539213Sgibbs 310643636Smjacob 310741918Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 310839213Sgibbs 310939213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 311042716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 311139213Sgibbs 311241918Smjacob if (error == 0 && nmarks) { 311341918Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 311471087Smjacob nwm = nmarks - softc->last_ctl_resid; 311571087Smjacob softc->filemarks += nwm; 311639213Sgibbs } 311771087Smjacob 311841918Smjacob xpt_release_ccb(ccb); 311943636Smjacob 312043636Smjacob /* 312143636Smjacob * Update relative positions (if we're doing that). 312243636Smjacob */ 312343636Smjacob if (error) { 312443636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 312543636Smjacob } else if (softc->fileno != (daddr_t) -1) { 312671087Smjacob softc->fileno += nwm; 312743636Smjacob softc->blkno = 0; 312843636Smjacob } 312941918Smjacob return (error); 313041918Smjacob} 313139213Sgibbs 313241918Smjacobstatic int 313341918Smjacobsardpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 313441918Smjacob{ 313541918Smjacob struct scsi_tape_position_data loc; 313641918Smjacob union ccb *ccb; 313746962Smjacob struct sa_softc *softc = (struct sa_softc *)periph->softc; 313841918Smjacob int error; 313941918Smjacob 314041918Smjacob /* 314171082Smjacob * We try and flush any buffered writes here if we were writing 314271082Smjacob * and we're trying to get hardware block position. It eats 314371082Smjacob * up performance substantially, but I'm wary of drive firmware. 314446962Smjacob * 314571082Smjacob * I think that *logical* block position is probably okay- 314671082Smjacob * but hardware block position might have to wait for data 314771082Smjacob * to hit media to be valid. Caveat Emptor. 314841918Smjacob */ 314941918Smjacob 315071082Smjacob if (hard && (softc->flags & SA_FLAG_TAPE_WRITTEN)) { 315146962Smjacob error = sawritefilemarks(periph, 0, 0); 315246962Smjacob if (error && error != EACCES) 315346962Smjacob return (error); 315446962Smjacob } 315541918Smjacob 315666678Smjacob ccb = cam_periph_getccb(periph, 1); 315741918Smjacob scsi_read_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 315841918Smjacob hard, &loc, SSD_FULL_SIZE, 5000); 315943636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 316041918Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 316143636Smjacob softc->dsreg = MTIO_DSREG_REST; 316241918Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 316341918Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 316441918Smjacob 316541918Smjacob if (error == 0) { 316641918Smjacob if (loc.flags & SA_RPOS_UNCERTAIN) { 316741918Smjacob error = EINVAL; /* nothing is certain */ 316841918Smjacob } else { 316941918Smjacob *blkptr = scsi_4btoul(loc.firstblk); 317041918Smjacob } 317141918Smjacob } 317241918Smjacob 317339213Sgibbs xpt_release_ccb(ccb); 317439213Sgibbs return (error); 317539213Sgibbs} 317639213Sgibbs 317739213Sgibbsstatic int 317841918Smjacobsasetpos(struct cam_periph *periph, int hard, u_int32_t *blkptr) 317941918Smjacob{ 318041918Smjacob union ccb *ccb; 318141918Smjacob struct sa_softc *softc; 318241918Smjacob int error; 318341918Smjacob 318441918Smjacob /* 318546962Smjacob * We used to try and flush any buffered writes here. 318646962Smjacob * Now we push this onto user applications to either 318746962Smjacob * flush the pending writes themselves (via a zero count 318846962Smjacob * WRITE FILEMARKS command) or they can trust their tape 318946962Smjacob * drive to do this correctly for them. 319046962Smjacob */ 319141918Smjacob 319241918Smjacob softc = (struct sa_softc *)periph->softc; 319346962Smjacob ccb = cam_periph_getccb(periph, 1); 319441918Smjacob 319543636Smjacob 319641918Smjacob scsi_set_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, 319741918Smjacob hard, *blkptr, SSD_FULL_SIZE, 60 * 60 * 1000); 319843636Smjacob 319943636Smjacob softc->dsreg = MTIO_DSREG_POS; 320041918Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 320143636Smjacob softc->dsreg = MTIO_DSREG_REST; 320241918Smjacob if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 320341918Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 320441918Smjacob xpt_release_ccb(ccb); 320541918Smjacob /* 320646962Smjacob * Note relative file && block number position as now unknown. 320741918Smjacob */ 320843636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 320941918Smjacob return (error); 321041918Smjacob} 321141918Smjacob 321241918Smjacobstatic int 321339213Sgibbssaretension(struct cam_periph *periph) 321439213Sgibbs{ 321539213Sgibbs union ccb *ccb; 321639213Sgibbs struct sa_softc *softc; 321739213Sgibbs int error; 321839213Sgibbs 321939213Sgibbs softc = (struct sa_softc *)periph->softc; 322039213Sgibbs 322146962Smjacob ccb = cam_periph_getccb(periph, 1); 322239213Sgibbs 322342716Smjacob /* It is safe to retry this operation */ 322442716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 322553259Smjacob FALSE, TRUE, TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT); 322639213Sgibbs 322743636Smjacob softc->dsreg = MTIO_DSREG_TEN; 322842716Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 322943636Smjacob softc->dsreg = MTIO_DSREG_REST; 323039213Sgibbs 323139213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 323242716Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 323339213Sgibbs xpt_release_ccb(ccb); 323443636Smjacob if (error == 0) 323543636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 323643636Smjacob else 323743636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 323854099Smjacob return (error); 323939213Sgibbs} 324039213Sgibbs 324139213Sgibbsstatic int 324239213Sgibbssareservereleaseunit(struct cam_periph *periph, int reserve) 324339213Sgibbs{ 324439213Sgibbs union ccb *ccb; 324539213Sgibbs struct sa_softc *softc; 324654099Smjacob int error; 324739213Sgibbs 324842009Smjacob softc = (struct sa_softc *)periph->softc; 324942716Smjacob ccb = cam_periph_getccb(periph, 1); 325039213Sgibbs 325142716Smjacob /* It is safe to retry this operation */ 325254099Smjacob scsi_reserve_release_unit(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, 325342716Smjacob FALSE, 0, SSD_FULL_SIZE, 5000, reserve); 325443636Smjacob softc->dsreg = MTIO_DSREG_RBSY; 325554099Smjacob error = cam_periph_runccb(ccb, saerror, 0, 325654099Smjacob SF_RETRY_UA | SF_NO_PRINT, &softc->device_stats); 325743636Smjacob softc->dsreg = MTIO_DSREG_REST; 325854099Smjacob QFRLS(ccb); 325939213Sgibbs xpt_release_ccb(ccb); 326039213Sgibbs 326141674Smjacob /* 326241674Smjacob * If the error was Illegal Request, then the device doesn't support 326341674Smjacob * RESERVE/RELEASE. This is not an error. 326441674Smjacob */ 326542009Smjacob if (error == EINVAL) { 326641674Smjacob error = 0; 326742009Smjacob } 326841674Smjacob 326939213Sgibbs return (error); 327039213Sgibbs} 327139213Sgibbs 327239213Sgibbsstatic int 327339213Sgibbssaloadunload(struct cam_periph *periph, int load) 327439213Sgibbs{ 327539213Sgibbs union ccb *ccb; 327639213Sgibbs struct sa_softc *softc; 327739213Sgibbs int error; 327839213Sgibbs 327939213Sgibbs softc = (struct sa_softc *)periph->softc; 328039213Sgibbs 328146962Smjacob ccb = cam_periph_getccb(periph, 1); 328239213Sgibbs 328342716Smjacob /* It is safe to retry this operation */ 328442716Smjacob scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE, 328554099Smjacob FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT); 328639213Sgibbs 328743636Smjacob softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL; 328842716Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 328943636Smjacob softc->dsreg = MTIO_DSREG_REST; 329054099Smjacob QFRLS(ccb); 329139213Sgibbs xpt_release_ccb(ccb); 329243636Smjacob 329343636Smjacob if (error || load == 0) 329443636Smjacob softc->fileno = softc->blkno = (daddr_t) -1; 329543636Smjacob else if (error == 0) 329643636Smjacob softc->fileno = softc->blkno = (daddr_t) 0; 329739213Sgibbs return (error); 329839213Sgibbs} 329939213Sgibbs 330039213Sgibbsstatic int 330139213Sgibbssaerase(struct cam_periph *periph, int longerase) 330239213Sgibbs{ 330339213Sgibbs 330439213Sgibbs union ccb *ccb; 330539213Sgibbs struct sa_softc *softc; 330639213Sgibbs int error; 330739213Sgibbs 330839213Sgibbs softc = (struct sa_softc *)periph->softc; 330939213Sgibbs 331046962Smjacob ccb = cam_periph_getccb(periph, 1); 331139213Sgibbs 331243636Smjacob scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase, 331353259Smjacob SSD_FULL_SIZE, ERASE_TIMEOUT); 331439213Sgibbs 331543636Smjacob softc->dsreg = MTIO_DSREG_ZER; 331643636Smjacob error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats); 331743636Smjacob softc->dsreg = MTIO_DSREG_REST; 331839213Sgibbs 331939213Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 332043636Smjacob cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); 332139213Sgibbs xpt_release_ccb(ccb); 332239213Sgibbs return (error); 332339213Sgibbs} 332439213Sgibbs 332555205Speter#endif /* _KERNEL */ 332639213Sgibbs 332739213Sgibbs/* 332839213Sgibbs * Read tape block limits command. 332939213Sgibbs */ 333039213Sgibbsvoid 333139213Sgibbsscsi_read_block_limits(struct ccb_scsiio *csio, u_int32_t retries, 333239213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 333339213Sgibbs u_int8_t tag_action, 333439213Sgibbs struct scsi_read_block_limits_data *rlimit_buf, 333539213Sgibbs u_int8_t sense_len, u_int32_t timeout) 333639213Sgibbs{ 333739213Sgibbs struct scsi_read_block_limits *scsi_cmd; 333839213Sgibbs 333946962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 334046962Smjacob (u_int8_t *)rlimit_buf, sizeof(*rlimit_buf), sense_len, 334146962Smjacob sizeof(*scsi_cmd), timeout); 334239213Sgibbs 334339213Sgibbs scsi_cmd = (struct scsi_read_block_limits *)&csio->cdb_io.cdb_bytes; 334439213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 334539213Sgibbs scsi_cmd->opcode = READ_BLOCK_LIMITS; 334639213Sgibbs} 334739213Sgibbs 334839213Sgibbsvoid 334939213Sgibbsscsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries, 335039213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 335139213Sgibbs u_int8_t tag_action, int readop, int sli, 335239213Sgibbs int fixed, u_int32_t length, u_int8_t *data_ptr, 335339213Sgibbs u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout) 335439213Sgibbs{ 335539213Sgibbs struct scsi_sa_rw *scsi_cmd; 335639213Sgibbs 335739213Sgibbs scsi_cmd = (struct scsi_sa_rw *)&csio->cdb_io.cdb_bytes; 335839213Sgibbs scsi_cmd->opcode = readop ? SA_READ : SA_WRITE; 335939213Sgibbs scsi_cmd->sli_fixed = 0; 336039213Sgibbs if (sli && readop) 336139213Sgibbs scsi_cmd->sli_fixed |= SAR_SLI; 336239213Sgibbs if (fixed) 336339213Sgibbs scsi_cmd->sli_fixed |= SARW_FIXED; 336439213Sgibbs scsi_ulto3b(length, scsi_cmd->length); 336539213Sgibbs scsi_cmd->control = 0; 336639213Sgibbs 336746962Smjacob cam_fill_csio(csio, retries, cbfcnp, readop ? CAM_DIR_IN : CAM_DIR_OUT, 336846962Smjacob tag_action, data_ptr, dxfer_len, sense_len, 336946962Smjacob sizeof(*scsi_cmd), timeout); 337039213Sgibbs} 337139213Sgibbs 337239213Sgibbsvoid 337339213Sgibbsscsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries, 337439213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 337539213Sgibbs u_int8_t tag_action, int immediate, int eot, 337639213Sgibbs int reten, int load, u_int8_t sense_len, 337739213Sgibbs u_int32_t timeout) 337839213Sgibbs{ 337939213Sgibbs struct scsi_load_unload *scsi_cmd; 338039213Sgibbs 338139213Sgibbs scsi_cmd = (struct scsi_load_unload *)&csio->cdb_io.cdb_bytes; 338239213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 338339213Sgibbs scsi_cmd->opcode = LOAD_UNLOAD; 338439213Sgibbs if (immediate) 338539213Sgibbs scsi_cmd->immediate = SLU_IMMED; 338639213Sgibbs if (eot) 338739213Sgibbs scsi_cmd->eot_reten_load |= SLU_EOT; 338839213Sgibbs if (reten) 338939213Sgibbs scsi_cmd->eot_reten_load |= SLU_RETEN; 339039213Sgibbs if (load) 339139213Sgibbs scsi_cmd->eot_reten_load |= SLU_LOAD; 339239213Sgibbs 339346962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 339446962Smjacob NULL, 0, sense_len, sizeof(*scsi_cmd), timeout); 339539213Sgibbs} 339639213Sgibbs 339739213Sgibbsvoid 339839213Sgibbsscsi_rewind(struct ccb_scsiio *csio, u_int32_t retries, 339939213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 340039213Sgibbs u_int8_t tag_action, int immediate, u_int8_t sense_len, 340139213Sgibbs u_int32_t timeout) 340239213Sgibbs{ 340339213Sgibbs struct scsi_rewind *scsi_cmd; 340439213Sgibbs 340539213Sgibbs scsi_cmd = (struct scsi_rewind *)&csio->cdb_io.cdb_bytes; 340639213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 340739213Sgibbs scsi_cmd->opcode = REWIND; 340839213Sgibbs if (immediate) 340939213Sgibbs scsi_cmd->immediate = SREW_IMMED; 341039213Sgibbs 341146962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 341246962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 341339213Sgibbs} 341439213Sgibbs 341539213Sgibbsvoid 341639213Sgibbsscsi_space(struct ccb_scsiio *csio, u_int32_t retries, 341739213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 341839213Sgibbs u_int8_t tag_action, scsi_space_code code, 341939213Sgibbs u_int32_t count, u_int8_t sense_len, u_int32_t timeout) 342039213Sgibbs{ 342139213Sgibbs struct scsi_space *scsi_cmd; 342239213Sgibbs 342339213Sgibbs scsi_cmd = (struct scsi_space *)&csio->cdb_io.cdb_bytes; 342439213Sgibbs scsi_cmd->opcode = SPACE; 342539213Sgibbs scsi_cmd->code = code; 342639213Sgibbs scsi_ulto3b(count, scsi_cmd->count); 342739213Sgibbs scsi_cmd->control = 0; 342839213Sgibbs 342946962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 343046962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 343139213Sgibbs} 343239213Sgibbs 343339213Sgibbsvoid 343439213Sgibbsscsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries, 343539213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 343639213Sgibbs u_int8_t tag_action, int immediate, int setmark, 343739213Sgibbs u_int32_t num_marks, u_int8_t sense_len, 343839213Sgibbs u_int32_t timeout) 343939213Sgibbs{ 344039213Sgibbs struct scsi_write_filemarks *scsi_cmd; 344139213Sgibbs 344239213Sgibbs scsi_cmd = (struct scsi_write_filemarks *)&csio->cdb_io.cdb_bytes; 344339213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 344439213Sgibbs scsi_cmd->opcode = WRITE_FILEMARKS; 344539213Sgibbs if (immediate) 344639213Sgibbs scsi_cmd->byte2 |= SWFMRK_IMMED; 344739213Sgibbs if (setmark) 344839213Sgibbs scsi_cmd->byte2 |= SWFMRK_WSMK; 344939213Sgibbs 345039213Sgibbs scsi_ulto3b(num_marks, scsi_cmd->num_marks); 345139213Sgibbs 345246962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 345346962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 345439213Sgibbs} 345539213Sgibbs 345639213Sgibbs/* 345739213Sgibbs * The reserve and release unit commands differ only by their opcodes. 345839213Sgibbs */ 345939213Sgibbsvoid 346039213Sgibbsscsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries, 346139213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 346239213Sgibbs u_int8_t tag_action, int third_party, 346339213Sgibbs int third_party_id, u_int8_t sense_len, 346439213Sgibbs u_int32_t timeout, int reserve) 346539213Sgibbs{ 346639213Sgibbs struct scsi_reserve_release_unit *scsi_cmd; 346739213Sgibbs 346839213Sgibbs scsi_cmd = (struct scsi_reserve_release_unit *)&csio->cdb_io.cdb_bytes; 346939213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 347039213Sgibbs 347139213Sgibbs if (reserve) 347239213Sgibbs scsi_cmd->opcode = RESERVE_UNIT; 347339213Sgibbs else 347439213Sgibbs scsi_cmd->opcode = RELEASE_UNIT; 347539213Sgibbs 347639213Sgibbs if (third_party) { 347739213Sgibbs scsi_cmd->lun_thirdparty |= SRRU_3RD_PARTY; 347839213Sgibbs scsi_cmd->lun_thirdparty |= 347939213Sgibbs ((third_party_id << SRRU_3RD_SHAMT) & SRRU_3RD_MASK); 348039213Sgibbs } 348139213Sgibbs 348246962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 348346962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 348439213Sgibbs} 348539213Sgibbs 348639213Sgibbsvoid 348739213Sgibbsscsi_erase(struct ccb_scsiio *csio, u_int32_t retries, 348839213Sgibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 348939213Sgibbs u_int8_t tag_action, int immediate, int long_erase, 349039213Sgibbs u_int8_t sense_len, u_int32_t timeout) 349139213Sgibbs{ 349239213Sgibbs struct scsi_erase *scsi_cmd; 349339213Sgibbs 349439213Sgibbs scsi_cmd = (struct scsi_erase *)&csio->cdb_io.cdb_bytes; 349539213Sgibbs bzero(scsi_cmd, sizeof(*scsi_cmd)); 349639213Sgibbs 349739213Sgibbs scsi_cmd->opcode = ERASE; 349839213Sgibbs 349939213Sgibbs if (immediate) 350039213Sgibbs scsi_cmd->lun_imm_long |= SE_IMMED; 350139213Sgibbs 350239213Sgibbs if (long_erase) 350339213Sgibbs scsi_cmd->lun_imm_long |= SE_LONG; 350439213Sgibbs 350546962Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL, 350646962Smjacob 0, sense_len, sizeof(*scsi_cmd), timeout); 350739213Sgibbs} 350841918Smjacob 350941918Smjacob/* 351041918Smjacob * Read Tape Position command. 351141918Smjacob */ 351241918Smjacobvoid 351341918Smjacobscsi_read_position(struct ccb_scsiio *csio, u_int32_t retries, 351441918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 351541918Smjacob u_int8_t tag_action, int hardsoft, 351641918Smjacob struct scsi_tape_position_data *sbp, 351741918Smjacob u_int8_t sense_len, u_int32_t timeout) 351841918Smjacob{ 351941918Smjacob struct scsi_tape_read_position *scmd; 352041918Smjacob 352141918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action, 352241918Smjacob (u_int8_t *)sbp, sizeof (*sbp), sense_len, sizeof(*scmd), timeout); 352341918Smjacob scmd = (struct scsi_tape_read_position *)&csio->cdb_io.cdb_bytes; 352441918Smjacob bzero(scmd, sizeof(*scmd)); 352541918Smjacob scmd->opcode = READ_POSITION; 352641918Smjacob scmd->byte1 = hardsoft; 352741918Smjacob} 352841918Smjacob 352941918Smjacob/* 353041918Smjacob * Set Tape Position command. 353141918Smjacob */ 353241918Smjacobvoid 353341918Smjacobscsi_set_position(struct ccb_scsiio *csio, u_int32_t retries, 353441918Smjacob void (*cbfcnp)(struct cam_periph *, union ccb *), 353541918Smjacob u_int8_t tag_action, int hardsoft, u_int32_t blkno, 353641918Smjacob u_int8_t sense_len, u_int32_t timeout) 353741918Smjacob{ 353841918Smjacob struct scsi_tape_locate *scmd; 353941918Smjacob 354041918Smjacob cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, 354141918Smjacob (u_int8_t *)NULL, 0, sense_len, sizeof(*scmd), timeout); 354241918Smjacob scmd = (struct scsi_tape_locate *)&csio->cdb_io.cdb_bytes; 354341918Smjacob bzero(scmd, sizeof(*scmd)); 354441918Smjacob scmd->opcode = LOCATE; 354541918Smjacob if (hardsoft) 354641918Smjacob scmd->byte1 |= SA_SPOS_BT; 354741918Smjacob scsi_ulto4b(blkno, scmd->blkaddr); 354841918Smjacob} 3549