Copyright 1992 - 2002 Kai Makisara / Willem Riede
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
Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
Some small formal changes - aeb, 950809
*/
-static const char * cvsid = "$Id: osst.c,v 1.68 2002/12/23 16:33:36 riede Exp $";
-const char * osst_version = "0.99.0";
+static const char * cvsid = "$Id: osst.c,v 1.70 2003/12/23 14:22:12 wriede Exp $";
+const char * osst_version = "0.99.1";
/* The "failure to reconnect" firmware bug */
#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
/* TODO: Error handling */
if (STp->poll)
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);
cmd[0] = READ_6;
Scsi_Request * SRpnt = * aSRpnt;
unsigned char * buffer, * p;
unsigned char cmd[MAX_COMMAND_SIZE];
- int flag, new_frame, i;
- int nframes = STp->cur_frames;
- int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
+ int flag, new_frame, i;
+ int nframes = STp->cur_frames;
+ int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+ int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
- (nframes + pending - 1);
- int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
+ int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
- (nframes + pending - 1) * blks_per_frame;
- char * name = tape_name(STp);
+ char * name = tape_name(STp);
unsigned long startwait = jiffies;
#if DEBUG
int dbg = debugging;
{
unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request * SRpnt;
- char * name = tape_name(STp);
+ char * name = tape_name(STp);
int expected = 0;
int attempts = 1000 / skip;
int flag = 1;
if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
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)) {
printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
return 0;
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;
+}
\f
/* osst versions of st functions - augmented and stripped to suit OnStream only */
result = (-EIO);
}
}
- STps->drv_block = (-1);
+ STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
}
else {
STp->first_frame_position++;
/* Change the eof state if no data from tape or buffer */
if (total == 0) {
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;
if (STps->drv_file >= 0)
STps->drv_file++;
if (debugging)
printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
#endif
- osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
- if (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0) {
+ if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
+ (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
ioctl_result = -EIO;
goto os_bypass;
}
break;
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 MTSETDRVBUFFER: /* Set drive buffering */
case SET_DENS_AND_BLK: /* Set density and block size */
if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
return (-EIO); /* Not allowed if data in buffer */
if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
- (arg & MT_ST_BLKSIZE_MASK) != 0 &&
- ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
- (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
- (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) {
- printk(KERN_WARNING "%s:W: Illegal block size.\n", name);
+ (arg & MT_ST_BLKSIZE_MASK) != 0 &&
+ (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
+ printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
+ name, (int)(arg & MT_ST_BLKSIZE_MASK),
+ (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
return (-EINVAL);
}
return 0; /* FIXME silently ignore if block size didn't change */
name, STp->nbr_waits, STp->nbr_finished);
}
#endif
- if (STp->write_type != OS_WRITE_NEW_MARK) {
- /* 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;
-
+ result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
#if DEBUG
if (debugging)
printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
STps = &(STp->ps[STp->partition]);
if (!STm->sysv || STps->rw != ST_READING) {
if (STp->can_bsr)
- result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
+ result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
else if (STps->eof == ST_FM_HIT) {
result = cross_eof(STp, &SRpnt, FALSE);
if (result) {
}
else if ((STps->eof == ST_NOEOF &&
!(result = cross_eof(STp, &SRpnt, TRUE))) ||
- STps->eof == ST_FM_HIT) {
+ STps->eof == ST_FM_HIT) {
if (STps->drv_file >= 0)
STps->drv_file++;
STps->drv_block = 0;
#endif
if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
struct mtop mtc;
+ int auto_weof = 0;
if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
retval = (-EINVAL);
STp->device->was_reset = 0;
}
- if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
- mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK &&
- mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
- STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
+ if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
+ mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
+ mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
+ 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)
do_door_lock(STp, 0); /* Ignore result! */
retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
goto out;
}
-
+
+ if (auto_weof)
+ cross_eof(STp, &SRpnt, FALSE);
+
if (mtc.mt_op == MTCOMPRESSION)
- retval = -EINVAL /*osst_compression(STp, (mtc.mt_count & 1))*/;
+ retval = -EINVAL; /* OnStream drives don't have compression hardware */
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);
goto out;
}
static int osst_remove(struct device *dev)
{
- Scsi_Device * SDp = to_scsi_device(dev);
- OS_Scsi_Tape * tpnt;
- int i, mode;
-
- if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
- return 0;
-
- write_lock(&os_scsi_tapes_lock);
- for(i=0; i < osst_max_dev; i++) {
- if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
- tpnt->device = NULL;
- for (mode = 0; mode < ST_NBR_MODES; ++mode) {
- devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
- devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
- }
- devfs_unregister_tape(tpnt->drive->number);
- put_disk(tpnt->drive);
- os_scsi_tapes[i] = NULL;
- osst_nr_dev--;
- write_unlock(&os_scsi_tapes_lock);
- if (tpnt->header_cache != NULL) vfree(tpnt->header_cache);
- if (tpnt->buffer) {
- normalize_buffer(tpnt->buffer);
- kfree(tpnt->buffer);
- }
- kfree(tpnt);
+ Scsi_Device * SDp = to_scsi_device(dev);
+ OS_Scsi_Tape * tpnt;
+ int i, mode;
+
+ if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
return 0;
+
+ write_lock(&os_scsi_tapes_lock);
+ for(i=0; i < osst_max_dev; i++) {
+ if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
+ tpnt->device = NULL;
+ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+ devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
+ devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
+ }
+ devfs_unregister_tape(tpnt->drive->number);
+ put_disk(tpnt->drive);
+ os_scsi_tapes[i] = NULL;
+ osst_nr_dev--;
+ write_unlock(&os_scsi_tapes_lock);
+ if (tpnt->header_cache != NULL) vfree(tpnt->header_cache);
+ if (tpnt->buffer) {
+ normalize_buffer(tpnt->buffer);
+ kfree(tpnt->buffer);
+ }
+ kfree(tpnt);
+ return 0;
+ }
}
- }
- write_unlock(&os_scsi_tapes_lock);
- return 0;
+ write_unlock(&os_scsi_tapes_lock);
+ return 0;
}
static int __init init_osst(void)