Commit a047e289 authored by James Bottomley's avatar James Bottomley

[PATCH] Updated osst driver for 2.6.x

From: Willem Riede <wrlk@riede.org>

Brings 2.6.x version of osst up to par with the 2.4.y version.
Except for the /proc changes
Tested against released 2.6.0 kernel.

Changes from what's in the kernel tree today:

- Fixes bug that files shorter than one 32K frame don't get written.
- Fix a memory alloc/free mismatch that could have made your kernel unstable after rmmod osst.
- Fix a number of tape (re)positioning bugs around filemarks that affected Amanda, Arkeia and
  Storix backup software.
- Rationalize module parameters.
- Fix time-out skipping to EOD
- Write FM+EOD+Header-update when file write terminated by ioctl
- Follow standard Unix behavior for read at EOD (return zero bytes read twice then error)
- Implement SETBLK ioctl (allowed before first write only)
parent 0f535a6a
...@@ -16,15 +16,15 @@ ...@@ -16,15 +16,15 @@
Copyright 1992 - 2002 Kai Makisara / Willem Riede Copyright 1992 - 2002 Kai Makisara / Willem Riede
email Kai.Makisara@metla.fi / osst@riede.org email Kai.Makisara@metla.fi / osst@riede.org
$Header: /home/cvsroot/Driver/osst.c,v 1.68 2002/12/23 16:33:36 riede Exp $ $Header: /cvsroot/osst/Driver/osst.c,v 1.70 2003/12/23 14:22:12 wriede Exp $
Microscopic alterations - Rik Ling, 2000/12/21 Microscopic alterations - Rik Ling, 2000/12/21
Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
Some small formal changes - aeb, 950809 Some small formal changes - aeb, 950809
*/ */
static const char * cvsid = "$Id: osst.c,v 1.68 2002/12/23 16:33:36 riede Exp $"; static const char * cvsid = "$Id: osst.c,v 1.70 2003/12/23 14:22:12 wriede Exp $";
const char * osst_version = "0.99.0"; const char * osst_version = "0.99.1";
/* The "failure to reconnect" firmware bug */ /* The "failure to reconnect" firmware bug */
#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
...@@ -846,9 +846,6 @@ static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeo ...@@ -846,9 +846,6 @@ static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeo
/* TODO: Error handling */ /* TODO: Error handling */
if (STp->poll) if (STp->poll)
retval = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout); retval = osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout);
#if 0// DEBUG
printk ("osst_read: wait for frame returned %i\n", retval);
#endif
memset(cmd, 0, MAX_COMMAND_SIZE); memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_6; cmd[0] = READ_6;
...@@ -2189,6 +2186,7 @@ static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, in ...@@ -2189,6 +2186,7 @@ static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, in
if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) { if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
if (osst_set_frame_position(STp, aSRpnt, ppos, 0)) if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
printk(KERN_WARNING "%s:W: Couldn't position tape\n", name); printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
if (osst_initiate_read (STp, aSRpnt)) { if (osst_initiate_read (STp, aSRpnt)) {
printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name); printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
return 0; return 0;
...@@ -2817,7 +2815,29 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in ...@@ -2817,7 +2815,29 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in
return result; return result;
} }
static int osst_write_trailer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int leave_at_EOT)
{
ST_partstat * STps = &(STp->ps[STp->partition]);
int result = 0;
if (STp->write_type != OS_WRITE_NEW_MARK) {
/* true unless the user wrote the filemark for us */
result = osst_flush_drive_buffer(STp, aSRpnt);
if (result < 0) goto out;
result = osst_write_filemark(STp, aSRpnt);
if (result < 0) goto out;
if (STps->drv_file >= 0)
STps->drv_file++ ;
STps->drv_block = 0;
}
result = osst_write_eod(STp, aSRpnt);
osst_write_header(STp, aSRpnt, leave_at_EOT);
STps->eof = ST_FM;
out:
return result;
}
/* osst versions of st functions - augmented and stripped to suit OnStream only */ /* osst versions of st functions - augmented and stripped to suit OnStream only */
...@@ -2935,7 +2955,7 @@ static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt) ...@@ -2935,7 +2955,7 @@ static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
result = (-EIO); result = (-EIO);
} }
} }
STps->drv_block = (-1); STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
} }
else { else {
STp->first_frame_position++; STp->first_frame_position++;
...@@ -3628,7 +3648,7 @@ static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *p ...@@ -3628,7 +3648,7 @@ static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *p
/* Change the eof state if no data from tape or buffer */ /* Change the eof state if no data from tape or buffer */
if (total == 0) { if (total == 0) {
if (STps->eof == ST_FM_HIT) { if (STps->eof == ST_FM_HIT) {
STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
STps->drv_block = 0; STps->drv_block = 0;
if (STps->drv_file >= 0) if (STps->drv_file >= 0)
STps->drv_file++; STps->drv_file++;
...@@ -4037,8 +4057,8 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -4037,8 +4057,8 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
if (debugging) if (debugging)
printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name); printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
#endif #endif
osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0); if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
if (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0) { (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
ioctl_result = -EIO; ioctl_result = -EIO;
goto os_bypass; goto os_bypass;
} }
...@@ -4076,6 +4096,23 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -4076,6 +4096,23 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
break; break;
case MTSETBLK: /* Set block length */ case MTSETBLK: /* Set block length */
if ((STps->drv_block == 0 ) &&
!STp->dirty &&
((STp->buffer)->buffer_bytes == 0) &&
((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
!(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
/*
* Only allowed to change the block size if you opened the
* device at the beginning of a file before writing anything.
* Note, that when reading, changing block_size is futile,
* as the size used when writing overrides it.
*/
STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
name, STp->block_size);
return 0;
}
case MTSETDENSITY: /* Set tape density */ case MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */ case MTSETDRVBUFFER: /* Set drive buffering */
case SET_DENS_AND_BLK: /* Set density and block size */ case SET_DENS_AND_BLK: /* Set density and block size */
...@@ -4084,10 +4121,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -4084,10 +4121,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
return (-EIO); /* Not allowed if data in buffer */ return (-EIO); /* Not allowed if data in buffer */
if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
(arg & MT_ST_BLKSIZE_MASK) != 0 && (arg & MT_ST_BLKSIZE_MASK) != 0 &&
((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
(arg & MT_ST_BLKSIZE_MASK) > STp->max_block || printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
(arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) { name, (int)(arg & MT_ST_BLKSIZE_MASK),
printk(KERN_WARNING "%s:W: Illegal block size.\n", name); (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
return (-EINVAL); return (-EINVAL);
} }
return 0; /* FIXME silently ignore if block size didn't change */ return 0; /* FIXME silently ignore if block size didn't change */
...@@ -4592,22 +4629,7 @@ static int os_scsi_tape_flush(struct file * filp) ...@@ -4592,22 +4629,7 @@ static int os_scsi_tape_flush(struct file * filp)
name, STp->nbr_waits, STp->nbr_finished); name, STp->nbr_waits, STp->nbr_finished);
} }
#endif #endif
if (STp->write_type != OS_WRITE_NEW_MARK) { result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
/* true unless the user wrote the filemark for us */
result = osst_flush_drive_buffer(STp, &SRpnt);
if (result < 0) goto out;
result = osst_write_filemark(STp, &SRpnt);
if (result < 0) goto out;
if (STps->drv_file >= 0)
STps->drv_file++ ;
STps->drv_block = 0;
}
result = osst_write_eod(STp, &SRpnt);
osst_write_header(STp, &SRpnt, !(STp->rew_at_close));
STps->eof = ST_FM;
#if DEBUG #if DEBUG
if (debugging) if (debugging)
printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n", printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
...@@ -4736,6 +4758,7 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4736,6 +4758,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
#endif #endif
if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
struct mtop mtc; struct mtop mtc;
int auto_weof = 0;
if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
retval = (-EINVAL); retval = (-EINVAL);
...@@ -4812,10 +4835,41 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4812,10 +4835,41 @@ static int osst_ioctl(struct inode * inode,struct file * file,
STp->device->was_reset = 0; STp->device->was_reset = 0;
} }
if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM && if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK && mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
/*
* The user tells us to move to another position on the tape.
* If we were appending to the tape content, that would leave
* the tape without proper end, in that case write EOD and
* update the header to reflect its position.
*/
#if DEBUG
printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
STp->logical_blk_num, STps->drv_file, STps->drv_block );
#endif
if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
!(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
i = osst_write_trailer(STp, &SRpnt,
!(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
#if DEBUG
printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
#endif
if (i < 0) {
retval = i;
goto out;
}
}
STps->rw = ST_IDLE;
}
if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
do_door_lock(STp, 0); /* Ignore result! */ do_door_lock(STp, 0); /* Ignore result! */
...@@ -4874,10 +4928,14 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4874,10 +4928,14 @@ static int osst_ioctl(struct inode * inode,struct file * file,
goto out; goto out;
} }
if (auto_weof)
cross_eof(STp, &SRpnt, FALSE);
if (mtc.mt_op == MTCOMPRESSION) if (mtc.mt_op == MTCOMPRESSION)
retval = -EINVAL /*osst_compression(STp, (mtc.mt_count & 1))*/; retval = -EINVAL; /* OnStream drives don't have compression hardware */
else else
/* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
* MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count); retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
goto out; goto out;
} }
......
/* /*
* $Header: /home/cvsroot/Driver/osst.h,v 1.12 2001/10/11 00:30:15 riede Exp $ * $Header: /cvsroot/osst/Driver/osst.h,v 1.14 2003/12/14 14:34:38 wriede Exp $
*/ */
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/completion.h> #include <linux/completion.h>
/* FIXME - rename and use the following two types or delete them! /* FIXME - rename and use the following two types or delete them!
* and the types really should go to st.h anyway... * and the types really should go to st.h anyway...
* INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
Changed (and renamed) for OnStream SCSI drives garloff@suse.de Changed (and renamed) for OnStream SCSI drives garloff@suse.de
2000-06-21 2000-06-21
$Header: /home/cvsroot/Driver/osst_options.h,v 1.5 2001/01/07 22:19:15 riede Exp $ $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $
*/ */
#ifndef _OSST_OPTIONS_H #ifndef _OSST_OPTIONS_H
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment