// SPDX-License-Identifier: GPL-2.0-only /* SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying file Documentation/scsi/st.rst for more information.
History: Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. Contribution and ideas from several people including (in alphabetical order) Klaus Ehrenfried, Eugene Exarevsky, Eric Lee Green, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and Eric Youngdale.
Copyright 1992 - 2016 Kai Makisara email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
/* The driver prints some debugging information on the console if DEBUG
is defined and non-zero. */ #define DEBUG 1 #define NO_DEBUG 0
#define ST_DEB_MSG KERN_NOTICE #if DEBUG /* The message level for the debug messages is currently set to KERN_NOTICE so that people can easily see the messages. Later when the debugging messages
in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ #define DEB(a) a #define DEBC(a) if (debugging) { a ; } #else #define DEB(a) #define DEBC(a) #endif
/* Set 'perm' (4th argument) to 0 to disable module_param's definition * of sysfs parameters (which module_param doesn't yet support). * Sysfs parameters defined explicitly later.
*/
module_param_named(buffer_kbs, buffer_kbs, int, 0);
MODULE_PARM_DESC(buffer_kbs, "Default driver buffer size for fixed block mode (KB; 32)");
module_param_named(max_sg_segs, max_sg_segs, int, 0);
MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)");
module_param_named(try_direct_io, try_direct_io, int, 0);
MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)");
module_param_named(debug_flag, debug_flag, int, 0);
MODULE_PARM_DESC(debug_flag, "Enable DEBUG, same as setting debugging=1");
/* Extra parameters for testing */
module_param_named(try_rdio, try_rdio, int, 0);
MODULE_PARM_DESC(try_rdio, "Try direct read i/o when possible");
module_param_named(try_wdio, try_wdio, int, 0);
MODULE_PARM_DESC(try_wdio, "Try direct write i/o when possible");
/* Restrict the number of modes so that names for all are assigned */ #if ST_NBR_MODES > 16 #error"Maximum number of modes is 16" #endif /* Bit reversed order to get same names for same minors with all
mode counts */ staticconstchar *st_formats[] = { "", "r", "k", "s", "l", "t", "o", "u", "m", "v", "p", "x", "a", "y", "q", "z"};
/* The default definitions have been moved to st_options.h */
/* The buffer size should fit into the 24 bits for length in the
6-byte SCSI read and write commands. */ #if ST_FIXED_BUFFER_SIZE >= (2 << 24 - 1) #error"Buffer size should not exceed (2 << 24 - 1) bytes!" #endif
staticint debugging = DEBUG;
/* Setting these non-zero may risk recognizing resets */ #define MAX_RETRIES 0 #define MAX_WRITE_RETRIES 0 #define MAX_READY_RETRIES 0
/* If the device signature is on the list of incompatible drives, the
function returns a pointer to the name of the correct driver (if known) */ staticchar * st_incompatible(struct scsi_device* SDp)
{ struct st_reject_data *rp;
for (rp=&(reject_list[0]); rp->vendor != NULL; rp++) if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
!strncmp(rp->model, SDp->model, strlen(rp->model)) &&
!strncmp(rp->rev, SDp->rev, strlen(rp->rev))) { if (rp->driver_hint) return rp->driver_hint; else return"unknown";
} return NULL;
}
/* Do the scsi command. Waits until command performed if do_wait is true. Otherwise write_behind_check() is used to check that the command
has finished. */ staticstruct st_request *
st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsignedchar *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
{ struct completion *waiting; struct rq_map_data *mdata = &STp->buffer->map_data; int ret;
/* if async, make sure there's no command outstanding */ if (!do_wait && ((STp->buffer)->last_SRpnt)) {
st_printk(KERN_ERR, STp, "Async command already active.\n"); if (signal_pending(current))
(STp->buffer)->syscall_result = (-EINTR); else
(STp->buffer)->syscall_result = (-EBUSY); return NULL;
}
if (!SRpnt) {
SRpnt = st_allocate_request(STp); if (!SRpnt) return NULL;
}
/* If async IO, set last_SRpnt. This ptr tells write_behind_check
which IO is outstanding. It's nulled out when the IO completes. */ if (!do_wait)
(STp->buffer)->last_SRpnt = SRpnt;
ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout,
retries); if (ret) { /* could not allocate the buffer or request was too large */
(STp->buffer)->syscall_result = (-EBUSY);
(STp->buffer)->last_SRpnt = NULL;
} elseif (do_wait) {
wait_for_completion(waiting);
SRpnt->waiting = NULL;
(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
}
return SRpnt;
}
/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if write has been correct but EOM early warning reached, -EIO if write ended in error or zero if write successful. Asynchronous writes are used only in
variable block mode. */ staticint write_behind_check(struct scsi_tape * STp)
{ int retval = 0; struct st_buffer *STbuffer; struct st_partstat *STps; struct st_cmdstatus *cmdstatp; struct st_request *SRpnt;
STbuffer = STp->buffer; if (!STbuffer->writing) return 0;
DEB( if (STp->write_pending)
STp->nbr_waits++; else
STp->nbr_finished++;
) /* end DEB */
cmdstatp = &STbuffer->cmdstat; if (STbuffer->syscall_result) {
retval = -EIO; if (cmdstatp->have_sense && !cmdstatp->deferred &&
(cmdstatp->flags & SENSE_EOM) &&
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) { /* EOM at write-behind, has all data been written? */ if (!cmdstatp->remainder_valid ||
cmdstatp->uremainder64 == 0)
retval = -ENOSPC;
} if (retval == -EIO)
STps->drv_block = -1;
}
STbuffer->writing = 0;
DEB(if (debugging && retval)
st_printk(ST_DEB_MSG, STp, "Async write error %x, return value %d.\n",
STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */
return retval;
}
/* Step over EOF if it has been inadvertently crossed (ioctl not used because
it messes up the block number). */ staticint cross_eof(struct scsi_tape * STp, int forward)
{ struct st_request *SRpnt; unsignedchar cmd[MAX_COMMAND_SIZE];
if (cmdstatp->have_sense && !cmdstatp->deferred &&
(cmdstatp->flags & SENSE_EOM) &&
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
(!cmdstatp->remainder_valid ||
cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0; if (STps->drv_block >= 0)
STps->drv_block += blks;
result = (-ENOSPC);
} else {
st_printk(KERN_ERR, STp, "Error on flush.\n");
STps->drv_block = (-1);
result = (-EIO);
}
} else { if (STps->drv_block >= 0)
STps->drv_block += blks;
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
}
st_release_request(SRpnt);
SRpnt = NULL;
} return result;
}
/* Flush the tape buffer. The tape will be positioned correctly unless
seek_next is true. */ staticint flush_buffer(struct scsi_tape *STp, int seek_next)
{ int backspace, result; struct st_partstat *STps;
if (STp->ready != ST_READY) return 0;
/* * If there was a bus reset, block further access * to this device.
*/ if (STp->pos_unknown) return (-EIO);
/* Set the internal state after reset */ staticvoid reset_state(struct scsi_tape *STp)
{ int i; struct st_partstat *STps;
STp->pos_unknown = 0; for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STps = &(STp->ps[i]);
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
STps->last_block_valid = 0;
STps->drv_block = -1;
STps->drv_file = -1;
} if (STp->can_partitions) {
STp->partition = find_partition(STp); if (STp->partition < 0)
STp->partition = 0;
}
}
/* Test if the drive is ready. Returns either one of the codes below or a negative system
error code. */ #define CHKRES_READY 0 #define CHKRES_NEW_SESSION 1 #define CHKRES_NOT_READY 2 #define CHKRES_NO_TAPE 3
if (STp->can_partitions && STp->nbr_partitions < 1) { /* This code is reached when the device is opened for the first time after the driver has been initialized with tape in the drive and the
partition support has been enabled. */
DEBC_printk(STp, "Updating partition number in status.\n"); if ((STp->partition = find_partition(STp)) < 0) {
retval = STp->partition; goto err_out;
}
STp->new_partition = STp->partition;
STp->nbr_partitions = 1; /* This guess will be updated when necessary */
}
if (new_session) { /* Change the drive parameters for the new mode */
STp->density_changed = STp->blksize_changed = 0;
STp->compression_changed = 0; if (!(STm->defaults_for_writes) &&
(retval = set_mode_densblk(STp, STm)) < 0) goto err_out;
if (STp->default_drvbuffer != 0xff) { if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))
st_printk(KERN_WARNING, STp, "Can't set default drive " "buffering to %d.\n",
STp->default_drvbuffer);
}
}
return CHKRES_READY;
err_out: return retval;
}
/* Open the device. Needs to take the BKL only because of incrementing the SCSI host
module count. */ staticint st_open(struct inode *inode, struct file *filp)
{ int i, retval = (-EIO); int resumed = 0; struct scsi_tape *STp; struct st_partstat *STps; int dev = TAPE_NR(inode);
/* * We really want to do nonseekable_open(inode, filp); here, but some * versions of tar incorrectly call lseek on tapes and bail out if that * fails. So we disallow pread() and pwrite(), but permit lseeks.
*/
filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
if (!(STp = scsi_tape_get(dev))) { return -ENXIO;
}
filp->private_data = STp;
spin_lock(&st_use_lock); if (STp->in_use) {
spin_unlock(&st_use_lock);
DEBC_printk(STp, "Device already in use.\n");
scsi_tape_put(STp); return (-EBUSY);
}
/* See that we have at least a one page buffer available */ if (!enlarge_buffer(STp->buffer, PAGE_SIZE)) {
st_printk(KERN_WARNING, STp, "Can't allocate one page tape buffer.\n");
retval = (-EOVERFLOW); goto err_out;
}
/* Flush the tape buffer before close */ staticint st_flush(struct file *filp, fl_owner_t id)
{ int result = 0, result2; unsignedchar cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; struct scsi_tape *STp = filp->private_data; struct st_modedef *STm = &(STp->modes[STp->current_mode]); struct st_partstat *STps = &(STp->ps[STp->partition]);
if (file_count(filp) > 1) return 0;
if (STps->rw == ST_WRITING && !STp->pos_unknown) {
result = st_flush_write_buffer(STp); if (result != 0 && result != (-ENOSPC)) goto out;
}
if (STp->can_partitions &&
(result2 = switch_partition(STp)) < 0) {
DEBC_printk(STp, "switch_partition at close failed.\n"); if (result == 0)
result = result2; goto out;
}
DEBC( if (STp->nbr_requests)
st_printk(KERN_DEBUG, STp, "Number of r/w requests %d, dio used in %d, " "pages %d.\n", STp->nbr_requests, STp->nbr_dio,
STp->nbr_pages));
out: if (STp->rew_at_close) {
result2 = st_int_ioctl(STp, MTREW, 1); if (result == 0)
result = result2;
} return result;
}
/* Close the device and release it. BKL is not needed: this is the only thread
accessing this tape. */ staticint st_release(struct inode *inode, struct file *filp)
{ struct scsi_tape *STp = filp->private_data;
if (STp->door_locked == ST_LOCKED_AUTO)
do_door_lock(STp, 0);
/* The checks common to both reading and writing */ static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
{
ssize_t retval = 0;
/* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited.
*/ if (!scsi_block_when_processing_errors(STp->device)) {
retval = (-ENXIO); goto out;
}
if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE)
retval = (-ENOMEDIUM); else
retval = (-EIO); goto out;
}
if (! STp->modes[STp->current_mode].defined) {
retval = (-ENXIO); goto out;
}
/* * If there was a bus reset, block further access * to this device.
*/ if (STp->pos_unknown) {
retval = (-EIO); goto out;
}
if (count == 0) goto out;
DEB( if (!STp->in_use) {
st_printk(ST_DEB_MSG, STp, "Incorrect device.\n");
retval = (-EIO); goto out;
} ) /* end DEB */
if (STp->can_partitions &&
(retval = switch_partition(STp)) < 0) goto out;
staticint setup_buffering(struct scsi_tape *STp, constchar __user *buf,
size_t count, int is_read)
{ int i, bufsize, retval = 0; struct st_buffer *STbp = STp->buffer;
if (is_read)
i = STp->try_dio_now && try_rdio; else
i = STp->try_dio_now && try_wdio;
if (i && ((unsignedlong)buf & queue_dma_alignment(
STp->device->request_queue)) == 0) {
i = sgl_map_user_pages(STbp, STbp->use_sg, (unsignedlong)buf,
count, (is_read ? READ : WRITE)); if (i > 0) {
STbp->do_dio = i;
STbp->buffer_bytes = 0; /* can be used as transfer counter */
} else
STbp->do_dio = 0; /* fall back to buffering with any error */
STbp->sg_segs = STbp->do_dio;
DEB( if (STbp->do_dio) {
STp->nbr_dio++;
STp->nbr_pages += STbp->do_dio;
}
)
} else
STbp->do_dio = 0;
DEB( STp->nbr_requests++; )
if (!STbp->do_dio) { if (STp->block_size)
bufsize = STp->block_size > st_fixed_buffer_size ?
STp->block_size : st_fixed_buffer_size; else {
bufsize = count; /* Make sure that data from previous user is not leaked even if
HBA does not return correct residual */ if (is_read && STp->sili && !STbp->cleared)
clear_buffer(STbp);
}
/* Can be called more than once after each setup_buffer() */ staticvoid release_buffering(struct scsi_tape *STp, int is_read)
{ struct st_buffer *STbp;
/* Write must be integral number of blocks */ if (STp->block_size != 0 && (count % STp->block_size) != 0) {
st_printk(KERN_WARNING, STp, "Write not multiple of tape block size.\n");
retval = (-EINVAL); goto out;
}
if (STbp->syscall_result != 0) { struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
DEBC_printk(STp, "Error on write:\n"); if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
scode = cmdstatp->sense_hdr.sense_key; if (cmdstatp->remainder_valid)
undone = (int)cmdstatp->uremainder64; elseif (STp->block_size == 0 &&
scode == VOLUME_OVERFLOW)
undone = transfer; else
undone = 0; if (STp->block_size != 0)
undone *= STp->block_size; if (undone <= do_count) { /* Only data from this write is not written */
count += undone;
b_point -= undone;
do_count -= undone; if (STp->block_size)
blks = (transfer - undone) / STp->block_size;
STps->eof = ST_EOM_OK; /* Continue in fixed block mode if all written in this request but still something left to write (retval left to zero)
*/ if (STp->block_size == 0 ||
undone > 0 || count == 0)
retval = (-ENOSPC); /* EOM within current request */
DEBC_printk(STp, "EOM with %d " "bytes unwritten.\n",
(int)count);
} else { /* EOT within data buffered earlier (possible only
in fixed block mode without direct i/o) */ if (!retry_eot && !cmdstatp->deferred &&
(scode == NO_SENSE || scode == RECOVERED_ERROR)) {
move_buffer_data(STp->buffer, transfer - undone);
retry_eot = 1; if (STps->drv_block >= 0) {
STps->drv_block += (transfer - undone) /
STp->block_size;
}
STps->eof = ST_EOM_OK;
DEBC_printk(STp, "Retry " "write of %d " "bytes at EOM.\n",
STp->buffer->buffer_bytes); goto retry_write;
} else { /* Either error within data buffered by driver or
failed retry */
count -= do_count;
blks = do_count = 0;
STps->eof = ST_EOM_ERROR;
STps->drv_block = (-1); /* Too cautious? */
retval = (-EIO); /* EOM for old data */
DEBC_printk(STp, "EOM with " "lost data.\n");
}
}
} else {
count += do_count;
STps->drv_block = (-1); /* Too cautious? */
retval = STbp->syscall_result;
}
}
if (STps->drv_block >= 0) { if (STp->block_size == 0)
STps->drv_block += (do_count > 0); else
STps->drv_block += blks;
}
STbp->buffer_bytes = 0;
STp->dirty = 0;
if (retval || retry_eot) { if (count < total)
retval = total - count; goto out;
}
}
if (STps->eof == ST_EOD_1)
STps->eof = ST_EOM_OK; elseif (STps->eof != ST_EOM_OK)
STps->eof = ST_NOEOF;
retval = total - count;
out: if (SRpnt != NULL)
st_release_request(SRpnt);
release_buffering(STp, 0);
mutex_unlock(&STp->lock);
return retval;
}
/* Read data from the tape. Returns zero in the normal case, one if the eof status has changed, and the negative error code in case of a fatal error. Otherwise updates the buffer and the eof state.
Does release user buffer mapping if it is set.
*/ staticlong read_tape(struct scsi_tape *STp, long count, struct st_request ** aSRpnt)
{ int transfer, blks, bytes; unsignedchar cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; struct st_modedef *STm; struct st_partstat *STps; struct st_buffer *STbp; int retval = 0;
if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
cmdstatp->flags &= 0xcf; /* No need for EOM in this case */
if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */ /* Compute the residual count */ if (cmdstatp->remainder_valid)
transfer = (int)cmdstatp->uremainder64; else
transfer = 0; if (cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR) { if (STp->block_size == 0)
transfer = bytes; /* Some drives set ILI with MEDIUM ERROR */
cmdstatp->flags &= ~SENSE_ILI;
}
if (cmdstatp->flags & SENSE_ILI) { /* ILI */ if (STp->block_size == 0 &&
transfer < 0) {
st_printk(KERN_NOTICE, STp, "Failed to read %d " "byte block with %d " "byte transfer.\n",
bytes - transfer,
bytes); if (STps->drv_block >= 0)
STps->drv_block += 1;
STbp->buffer_bytes = 0; return (-ENOMEM);
} elseif (STp->block_size == 0) {
STbp->buffer_bytes = bytes - transfer;
} else {
st_release_request(SRpnt);
SRpnt = *aSRpnt = NULL; if (transfer == blks) { /* We did not get anything, error */
st_printk(KERN_NOTICE, STp, "Incorrect " "block size.\n"); if (STps->drv_block >= 0)
STps->drv_block += blks - transfer + 1;
st_int_ioctl(STp, MTBSR, 1); return (-EIO);
} /* We have some data, deliver it */
STbp->buffer_bytes = (blks - transfer) *
STp->block_size;
DEBC_printk(STp, "ILI but " "enough data " "received %ld " "%d.\n", count,
STbp->buffer_bytes); if (STps->drv_block >= 0)
STps->drv_block += 1; if (st_int_ioctl(STp, MTBSR, 1)) return (-EIO);
}
} elseif (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */ if (STps->eof != ST_FM_HIT)
STps->eof = ST_FM_HIT; else
STps->eof = ST_EOD_2; if (STp->block_size == 0)
STbp->buffer_bytes = 0; else
STbp->buffer_bytes =
bytes - transfer * STp->block_size;
DEBC_printk(STp, "EOF detected (%d " "bytes read).\n",
STbp->buffer_bytes);
} elseif (cmdstatp->flags & SENSE_EOM) { if (STps->eof == ST_FM)
STps->eof = ST_EOD_1; else
STps->eof = ST_EOM_OK; if (STp->block_size == 0)
STbp->buffer_bytes = bytes - transfer; else
STbp->buffer_bytes =
bytes - transfer * STp->block_size;
DEBC_printk(STp, "EOM detected (%d " "bytes read).\n",
STbp->buffer_bytes);
}
} /* end of EOF, EOM, ILI test */ else { /* nonzero sense key */
DEBC_printk(STp, "Tape error while reading.\n");
STps->drv_block = (-1); if (STps->eof == ST_FM &&
cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
DEBC_printk(STp, "Zero returned for " "first BLANK CHECK " "after EOF.\n");
STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */
} else/* Some other extended sense code */
retval = (-EIO);
}
if (STbp->buffer_bytes < 0) /* Caused by bogus sense data */
STbp->buffer_bytes = 0;
} /* End of extended sense test */ else { /* Non-extended sense */
retval = STbp->syscall_result;
}
} /* End of error handling */ else { /* Read successful */
STbp->buffer_bytes = bytes; if (STp->sili) /* In fixed block mode residual is always zero here */
STbp->buffer_bytes -= STp->buffer->cmdstat.residual;
}
if (STps->drv_block >= 0) { if (STp->block_size == 0)
STps->drv_block++; else
STps->drv_block += STbp->buffer_bytes / STp->block_size;
} return retval;
}
if (do_dio) { /* Check the buffer writability before any tape movement. Don't alter
buffer data. */ if (copy_from_user(&i, buf, 1) != 0 ||
copy_to_user(buf, &i, 1) != 0 ||
copy_from_user(&i, buf + count - 1, 1) != 0 ||
copy_to_user(buf + count - 1, &i, 1) != 0) {
retval = (-EFAULT); goto out;
}
}
STps->rw = ST_READING;
/* Loop until enough data in buffer or a special condition found */ for (total = 0, special = 0; total < count && !special;) {
/* Get new data if the buffer is empty */ if (STbp->buffer_bytes == 0) {
special = read_tape(STp, count - total, &SRpnt); if (special < 0) { /* No need to continue read */
retval = special; goto out;
}
}
/* Move the data from driver buffer to user buffer */ if (STbp->buffer_bytes > 0) {
DEB( if (debugging && STps->eof != ST_NOEOF)
st_printk(ST_DEB_MSG, STp, "EOF up (%d). Left %d, needed %d.\n",
STps->eof, STbp->buffer_bytes,
(int)(count - total));
) /* end DEB */
transfer = STbp->buffer_bytes < count - total ?
STbp->buffer_bytes : count - total; if (!do_dio) {
i = from_buffer(STbp, buf, transfer); if (i) {
retval = i; goto out;
}
}
buf += transfer;
total += transfer;
}
if (STp->block_size == 0) break; /* Read only one variable length block */
} /* for (total = 0, special = 0;
total < count && !special; ) */
/* Change the eof state if no data from tape or buffer */ if (total == 0) { if (STps->eof == ST_FM_HIT) {
STps->eof = ST_FM;
STps->drv_block = 0; if (STps->drv_file >= 0)
STps->drv_file++;
} elseif (STps->eof == ST_EOD_1) {
STps->eof = ST_EOD_2;
STps->drv_block = 0; if (STps->drv_file >= 0)
STps->drv_file++;
} elseif (STps->eof == ST_EOD_2)
STps->eof = ST_EOD;
} elseif (STps->eof == ST_FM)
STps->eof = ST_NOEOF;
retval = total;
/* Read a mode page into the tape buffer. The block descriptors are included if incl_block_descs is true. The page control is ored to the page number
parameter, if necessary. */ staticint read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
{ unsignedchar cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt;
/* Send the mode page in the tape buffer to the drive. Assumes that the mode data
in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */ staticint write_mode_page(struct scsi_tape *STp, int page, int slow)
{ int pgo; unsignedchar cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; int timeout;
/* Control the compression with mode page 15. Algorithm not changed if zero.
The block descriptors are read and written because Sony SDT-7000 does not work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
Including block descriptors should not cause any harm to other drives. */
staticint st_compression(struct scsi_tape * STp, int state)
{ int retval; int mpoffs; /* Offset to mode page start */ unsignedchar *b_data = (STp->buffer)->b_data;
if (STp->ready != ST_READY) return (-EIO);
/* Read the current page contents */
retval = read_mode_page(STp, COMPRESSION_PAGE, 0); if (retval) {
DEBC_printk(STp, "Compression mode page not supported.\n"); return (-EIO);
}
mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH];
DEBC_printk(STp, "Compression state is %d.\n",
(b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0));
/* Check if compression can be changed */ if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
DEBC_printk(STp, "Compression not supported.\n"); return (-EIO);
}
/* Do the change */ if (state) {
b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK; if (STp->c_algo != 0)
b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
} else {
b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK; if (STp->c_algo != 0)
b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
}
retval = write_mode_page(STp, COMPRESSION_PAGE, 0); if (retval) {
DEBC_printk(STp, "Compression change failed.\n"); return (-EIO);
}
DEBC_printk(STp, "Compression state changed to %d.\n", state);
STp->compression_changed = 1; return 0;
}
/* Process the load and unload commands (does unload if the load code is zero) */ staticint do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code)
{ int retval = (-EIO), timeout; unsignedchar cmd[MAX_COMMAND_SIZE]; struct st_partstat *STps; struct st_request *SRpnt;
if (STp->ready != ST_READY && !load_code) { if (STp->ready == ST_NO_TAPE) return (-ENOMEDIUM); else return (-EIO);
}
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = START_STOP; if (load_code)
cmd[4] |= 1; /* * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
*/ if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
&& load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
DEBC_printk(STp, " Enhanced %sload slot %2d.\n",
(cmd[4]) ? "" : "un",
load_code - MT_ST_HPLOADER_OFFSET);
cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
} if (STp->immediate) {
cmd[1] = 1; /* Don't wait for completion */
timeout = STp->device->request_queue->rq_timeout;
} else
timeout = STp->long_timeout;
if (cmd_in == MTWEOF || cmd_in == MTWEOFI)
STps->rw = ST_IDLE; /* prevent automatic WEOF at close */
} else { /* SCSI command was not completely successful. Don't return
from this block without releasing the SCSI command block! */ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
/* Set the tape block and partition. Negative partition means that only the
block should be set in vendor specific way. */ staticint set_location(struct scsi_tape *STp, unsignedint block, int partition, int logical)
{ struct st_partstat *STps; int result, p; unsignedint blk; int timeout; unsignedchar scmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt;
/* Find the current partition number for the drive status. Called from open and
returns either partition number of negative error code. */ staticint find_partition(struct scsi_tape *STp)
{ int i, partition; unsignedint block;
if ((i = get_location(STp, &block, &partition, 1)) < 0) return i; if (partition >= ST_NBR_PARTITIONS) return (-EIO); return partition;
}
/* Change the partition if necessary */ staticint switch_partition(struct scsi_tape *STp)
{ struct st_partstat *STps;
if (STp->partition == STp->new_partition) return 0;
STps = &(STp->ps[STp->new_partition]); if (!STps->last_block_valid)
STps->last_block_visited = 0; return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
}
/* Functions for reading and writing the medium partition mode page. */
/* Get the number of partitions on the tape. As a side effect reads the
mode page into the tape buffer. */ staticint nbr_partitions(struct scsi_tape *STp)
{ int result;
if (STp->ready != ST_READY) return (-EIO);
result = read_mode_page(STp, PART_PAGE, 1);
if (result) {
DEBC_printk(STp, "Can't read medium partition page.\n");
result = (-EIO);
} else {
result = (STp->buffer)->b_data[MODE_HEADER_LENGTH +
PP_OFF_NBR_ADD_PARTS] + 1;
DEBC_printk(STp, "Number of partitions %d.\n", result);
}
return result;
}
staticint format_medium(struct scsi_tape *STp, int format)
{ int result = 0; int timeout = STp->long_timeout; unsignedchar scmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt;
memset(scmd, 0, MAX_COMMAND_SIZE);
scmd[0] = FORMAT_UNIT;
scmd[2] = format; if (STp->immediate) {
scmd[1] |= 1; /* Don't wait for completion */
timeout = STp->device->request_queue->rq_timeout;
}
DEBC_printk(STp, "Sending FORMAT MEDIUM\n");
SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
timeout, MAX_RETRIES, 1); if (!SRpnt)
result = STp->buffer->syscall_result; return result;
}
/* Partition the tape into two partitions if size > 0 or one partition if size == 0.
The block descriptors are read and written because Sony SDT-7000 does not work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
My HP C1533A drive returns only one partition size field. This is used to set the size of partition 1. There is no size field for the default partition. Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is used to set the size of partition 1 (this is what the SCSI-3 standard specifies). The following algorithm is used to accommodate both drives: if the number of partition size fields is greater than the maximum number of additional partitions in the mode page, the second field is used. Otherwise the first field is used.
For Seagate DDS drives the page length must be 8 when no partitions is defined and 10 when 1 partition is defined (information from Eric Lee Green). This is is acceptable also to some other old drives and enforced if the first partition size field is used for the first additional partition size.
For drives that advertize SCSI-3 or newer, use the SSC-3 methods.
*/ staticint partition_tape(struct scsi_tape *STp, int size)
{ int result; int target_partition; bool scsi3 = STp->device->scsi_level >= SCSI_3, needs_format = false; int pgo, psd_cnt, psdo; int psum = PP_MSK_PSUM_MB, units = 0; unsignedchar *bp;
/* The mode page is in the buffer. Let's modify it and write it. */
bp = (STp->buffer)->b_data;
pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
DEBC_printk(STp, "Partition page length is %d bytes.\n",
bp[pgo + MP_OFF_PAGE_LENGTH] + 2);
if (scsi3) {
needs_format = (bp[pgo + PP_OFF_FLAGS] & PP_MSK_POFM) != 0; if (needs_format && size == 0) { /* No need to write the mode page when clearing * partitioning
*/
DEBC_printk(STp, "Formatting tape with one partition.\n");
result = format_medium(STp, 0); goto out;
} if (needs_format) /* Leave the old value for HP DATs claiming SCSI_3 */
psd_cnt = 2; if ((bp[pgo + PP_OFF_FLAGS] & PP_MSK_PSUM_UNITS) == PP_MSK_PSUM_UNITS) { /* Use units scaling for large partitions if the device * suggests it and no precision lost. Required for IBM * TS1140/50 drives that don't support MB units.
*/ if (size >= 1000 && (size % 1000) == 0) {
size /= 1000;
psum = PP_MSK_PSUM_UNITS;
units = 9; /* GB */
}
} /* Try it anyway if too large to specify in MB */ if (psum == PP_MSK_PSUM_MB && size >= 65534) {
size /= 1000;
psum = PP_MSK_PSUM_UNITS;
units = 9; /* GB */
}
}
if (size >= 65535 || /* Does not fit into two bytes */
(target_partition == 0 && psd_cnt < 2)) {
result = -EINVAL; goto out;
}
psdo = pgo + PART_PAGE_FIXED_LENGTH; /* The second condition is for HP DDS which use only one partition size * descriptor
*/ if (target_partition > 0 &&
(psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS] ||
bp[pgo + PP_OFF_MAX_ADD_PARTS] != 1)) {
bp[psdo] = bp[psdo + 1] = 0xff; /* Rest to partition 0 */
psdo += 2;
}
memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
/* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited.
*/
retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
file->f_flags & O_NDELAY); if (retval) goto out;
if (mtc.mt_op == MTSEEK) { /* Old position must be restored if partition will be
changed */
i = !STp->can_partitions ||
(STp->new_partition != STp->partition);
} else {
i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
mtc.mt_op == MTCOMPRESSION;
}
i = flush_buffer(STp, i); if (i < 0) {
retval = i; goto out;
} if (STps->rw == ST_WRITING &&
(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
mtc.mt_op == MTSEEK ||
mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) {
i = st_int_ioctl(STp, MTWEOF, 1); if (i < 0) {
retval = i; goto out;
} if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)
mtc.mt_count++;
STps->rw = ST_IDLE;
}
} else { /* * If there was a bus reset, block further access * to this device. If the user wants to rewind the tape, * then reset the flag and allow access again.
*/ if (mtc.mt_op != MTREW &&
mtc.mt_op != MTOFFL &&
mtc.mt_op != MTLOAD &&
mtc.mt_op != MTRETEN &&
mtc.mt_op != MTERASE &&
mtc.mt_op != MTSEEK &&
mtc.mt_op != MTEOM) {
retval = (-EIO); goto out;
}
reset_state(STp); /* Clears pos_unknown */
/* Fix the device settings after reset, ignore errors */ if (mtc.mt_op == MTREW || mtc.mt_op == MTSEEK ||
mtc.mt_op == MTEOM) { if (STp->can_partitions) { /* STp->new_partition contains the * latest partition set
*/
STp->partition = 0;
switch_partition(STp);
} if (STp->density_changed)
st_int_ioctl(STp, MTSETDENSITY, STp->changed_density); if (STp->blksize_changed)
st_int_ioctl(STp, MTSETBLK, STp->changed_blksize);
}
}
switch (cmd_in) { case SG_IO: case SCSI_IOCTL_SEND_COMMAND: case CDROM_SEND_PACKET: if (!capable(CAP_SYS_RAWIO)) return -EPERM; break; default: break;
}
#ifdef CONFIG_COMPAT staticlong st_compat_ioctl(struct file *file, unsignedint cmd_in, unsignedlong arg)
{ /* argument conversion is handled using put_user_mtpos/put_user_mtget */ switch (cmd_in) { case MTIOCPOS32:
cmd_in = MTIOCPOS; break; case MTIOCGET32:
cmd_in = MTIOCGET; break;
}
return st_ioctl(file, cmd_in, arg);
} #endif
/* Try to allocate a new tape buffer. Calling function must not hold
dev_arr_lock. */ staticstruct st_buffer *new_tape_buffer(int max_sg)
{ struct st_buffer *tb;
/* Make sure that no data from previous user is in the internal buffer */ staticvoid clear_buffer(struct st_buffer * st_bp)
{ int i;
for (i=0; i < st_bp->frp_segs; i++)
memset(page_address(st_bp->reserved_pages[i]), 0,
PAGE_SIZE << st_bp->reserved_page_order);
st_bp->cleared = 1;
}
/* Release the extra buffer */ staticvoid normalize_buffer(struct st_buffer * STbuffer)
{ int i, order = STbuffer->reserved_page_order;
for (i = 0; i < STbuffer->frp_segs; i++) {
__free_pages(STbuffer->reserved_pages[i], order);
STbuffer->buffer_size -= (PAGE_SIZE << order);
}
STbuffer->frp_segs = 0;
STbuffer->sg_segs = 0;
STbuffer->reserved_page_order = 0;
STbuffer->map_data.offset = 0;
}
/* Move data from the user buffer to the tape buffer. Returns zero (success) or
negative error code. */ staticint append_to_buffer(constchar __user *ubp, struct st_buffer * st_bp, int do_count)
{ int i, cnt, res, offset; int length = PAGE_SIZE << st_bp->reserved_page_order;
for (i = 0, offset = st_bp->buffer_bytes;
i < st_bp->frp_segs && offset >= length; i++)
offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */
printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); return (-EIO);
} for (; i < st_bp->frp_segs && do_count > 0; i++) { struct page *page = st_bp->reserved_pages[i];
cnt = length - offset < do_count ? length - offset : do_count;
res = copy_from_user(page_address(page) + offset, ubp, cnt); if (res) return (-EFAULT);
do_count -= cnt;
st_bp->buffer_bytes += cnt;
ubp += cnt;
offset = 0;
} if (do_count) /* Should never happen */ return (-EIO);
return 0;
}
/* Move data from the tape buffer to the user buffer. Returns zero (success) or
negative error code. */ staticint from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
{ int i, cnt, res, offset; int length = PAGE_SIZE << st_bp->reserved_page_order;
for (i = 0, offset = st_bp->read_pointer;
i < st_bp->frp_segs && offset >= length; i++)
offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */
printk(KERN_WARNING "st: from_buffer offset overflow.\n"); return (-EIO);
} for (; i < st_bp->frp_segs && do_count > 0; i++) { struct page *page = st_bp->reserved_pages[i];
cnt = length - offset < do_count ? length - offset : do_count;
res = copy_to_user(ubp, page_address(page) + offset, cnt); if (res) return (-EFAULT);
do_count -= cnt;
st_bp->buffer_bytes -= cnt;
st_bp->read_pointer += cnt;
ubp += cnt;
offset = 0;
} if (do_count) /* Should never happen */ return (-EIO);
return 0;
}
/* Move data towards start of buffer */ staticvoid move_buffer_data(struct st_buffer * st_bp, int offset)
{ int src_seg, dst_seg, src_offset = 0, dst_offset; int count, total; int length = PAGE_SIZE << st_bp->reserved_page_order;
/* Validate the options from command line or module parameters */ staticvoid validate_options(void)
{ if (buffer_kbs > 0)
st_fixed_buffer_size = buffer_kbs * ST_KILOBYTE; if (max_sg_segs >= ST_FIRST_SG)
st_max_sg_segs = max_sg_segs;
}
#ifndef MODULE /* Set the boot options. Syntax is defined in Documenation/scsi/st.txt.
*/ staticint __init st_setup(char *str)
{ int i, len, ints[ARRAY_SIZE(parms) + 1]; char *stp;
stp = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0) { for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) if (parms[i].val)
*parms[i].val = ints[i + 1];
} else { while (stp != NULL) { for (i = 0; i < ARRAY_SIZE(parms); i++) {
len = strlen(parms[i].name); if (!strncmp(stp, parms[i].name, len) &&
(*(stp + len) == ':' || *(stp + len) == '=')) { if (parms[i].val)
*parms[i].val =
simple_strtoul(stp + len + 1, NULL, 0); else
printk(KERN_WARNING "st: Obsolete parameter %s\n",
parms[i].name); break;
}
} if (i >= ARRAY_SIZE(parms))
printk(KERN_WARNING "st: invalid parameter in '%s'\n",
stp);
stp = strchr(stp, ','); if (stp)
stp++;
}
}
if (SDp->type != TYPE_TAPE) return -ENODEV; if (st_incompatible(SDp)) {
sdev_printk(KERN_INFO, SDp, "OnStream tapes are no longer supported;\n");
sdev_printk(KERN_INFO, SDp, "please mail to linux-scsi@vger.kernel.org.\n"); return -ENODEV;
}
scsi_autopm_get_device(SDp);
i = queue_max_segments(SDp->request_queue); if (st_max_sg_segs < i)
i = st_max_sg_segs;
buffer = new_tape_buffer(i); if (buffer == NULL) {
sdev_printk(KERN_ERR, SDp, "st: Can't allocate new tape buffer. " "Device not attached.\n"); goto out;
}
/** * scsi_tape_release - Called to free the Scsi_Tape structure * @kref: pointer to embedded kref * * st_ref_mutex must be held entering this routine. Because it is * called on last put, you should always use the scsi_tape_get() * scsi_tape_put() helpers which manipulate the semaphore directly * and never do a direct kref_put().
**/ staticvoid scsi_tape_release(struct kref *kref)
{ struct scsi_tape *tpnt = to_scsi_tape(kref);
tpnt->device = NULL;
if (tpnt->buffer) {
normalize_buffer(tpnt->buffer);
kfree(tpnt->buffer->reserved_pages);
kfree(tpnt->buffer);
}
err = class_register(&st_sysfs_class); if (err) {
pr_err("Unable register sysfs class for SCSI tapes\n"); return err;
}
err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES, "st"); if (err) {
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
SCSI_TAPE_MAJOR); goto err_class;
}
err = scsi_register_driver(&st_template.gendrv); if (err) goto err_chrdev;
#if DEBUG static ssize_t debug_flag_store(struct device_driver *ddp, constchar *buf, size_t count)
{ /* We only care what the first byte of the data is the rest is unused. * if it's a '1' we turn on debug and if it's a '0' we disable it. All * other values have -EINVAL returned if they are passed in.
*/ if (count > 0) { if (buf[0] == '0') {
debugging = NO_DEBUG; return count;
} elseif (buf[0] == '1') {
debugging = 1; return count;
}
} return -EINVAL;
}
/** * position_lost_in_reset_show - Value 1 indicates that reads, writes, etc. * are blocked because a device reset has occurred and no operation positioning * the tape has been issued. * @dev: struct device * @attr: attribute structure * @buf: buffer to return formatted data in
*/ static ssize_t position_lost_in_reset_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct st_modedef *STm = dev_get_drvdata(dev); struct scsi_tape *STp = STm->tape;
/** * read_byte_cnt_show - return read byte count - tape drives * may use blocks less than 512 bytes this gives the raw byte count of * of data read from the tape drive. * @dev: struct device * @attr: attribute structure * @buf: buffer to return formatted data in
*/ static ssize_t read_byte_cnt_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct st_modedef *STm = dev_get_drvdata(dev);
/** * write_cnt_show - write count - number of user calls * to write(2) that have written data to tape. * @dev: struct device * @attr: attribute structure * @buf: buffer to return formatted data in
*/ static ssize_t write_cnt_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct st_modedef *STm = dev_get_drvdata(dev);
/** * in_flight_show - number of I/Os currently in flight - * in most cases this will be either 0 or 1. It may be higher if someone * has also issued other SCSI commands such as via an ioctl. * @dev: struct device * @attr: attribute structure * @buf: buffer to return formatted data in
*/ static ssize_t in_flight_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct st_modedef *STm = dev_get_drvdata(dev);
/** * io_ns_show - io wait ns - this is the number of ns spent * waiting on all I/O to complete. This includes tape movement commands * such as rewinding, seeking to end of file or tape, it also includes * read and write. To determine the time spent on tape movement * subtract the read and write ns from this value. * @dev: struct device * @attr: attribute structure * @buf: buffer to return formatted data in
*/ static ssize_t io_ns_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct st_modedef *STm = dev_get_drvdata(dev);
/** * other_cnt_show - other io count - this is the number of * I/O requests other than read and write requests. * Typically these are tape movement requests but will include driver * tape movement. This includes only requests issued by the st driver. * @dev: struct device * @attr: attribute structure * @buf: buffer to return formatted data in
*/ static ssize_t other_cnt_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct st_modedef *STm = dev_get_drvdata(dev);
/** * resid_cnt_show - A count of the number of times we get a residual * count - this should indicate someone issuing reads larger than the * block size on tape. * @dev: struct device * @attr: attribute structure * @buf: buffer to return formatted data in
*/ static ssize_t resid_cnt_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct st_modedef *STm = dev_get_drvdata(dev);
/* Try to fault in all of the necessary pages */ /* rw==READ means read from drive, write into memory area */
res = pin_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0,
pages);
/* Errors and no page mapped should return here */ if (res < nr_pages) goto out_unmap;
for (i=0; i < nr_pages; i++) { /* FIXME: flush superflous for rw==READ, * probably wrong function for rw==WRITE
*/
flush_dcache_page(pages[i]);
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.122Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.