]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Updated osst driver for 2.6.x
authorJames Bottomley <jejb@raven.il.steeleye.com>
Tue, 30 Dec 2003 05:24:55 +0000 (23:24 -0600)
committerJames Bottomley <jejb@raven.il.steeleye.com>
Tue, 30 Dec 2003 05:24:55 +0000 (23:24 -0600)
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)

drivers/scsi/osst.c
drivers/scsi/osst.h
drivers/scsi/osst_options.h

index 6f31649c2c8be9021d09056747e77335dbb9e0bb..3c793cbe6671c465ff913d75b799b64b58c14762 100644 (file)
   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)*/
@@ -846,9 +846,6 @@ static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeo
        /* 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;
@@ -1279,14 +1276,14 @@ static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request **
        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;
@@ -1472,7 +1469,7 @@ static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
 {
        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;
@@ -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 (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;
@@ -2817,7 +2815,29 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in
        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 */
 
@@ -2935,7 +2955,7 @@ static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
                                        result = (-EIO);
                                }
                        }
-                       STps->drv_block = (-1);
+                       STps->drv_block = (-1);         /* FIXME - even if write recovery succeeds? */
                }
                else {
                        STp->first_frame_position++;
@@ -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 */
        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++;
@@ -4037,8 +4057,8 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
                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;
                }
@@ -4076,6 +4096,23 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
                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 */
@@ -4083,11 +4120,11 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
                 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 */
@@ -4592,22 +4629,7 @@ static int os_scsi_tape_flush(struct file * filp)
                                               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",
@@ -4618,7 +4640,7 @@ static int os_scsi_tape_flush(struct file * filp)
                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) {
@@ -4633,7 +4655,7 @@ static int os_scsi_tape_flush(struct file * filp)
                }
                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;
@@ -4736,6 +4758,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
 #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);
@@ -4812,10 +4835,41 @@ static int osst_ioctl(struct inode * inode,struct file * file,
                        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! */
@@ -4873,11 +4927,15 @@ static int osst_ioctl(struct inode * inode,struct file * file,
                        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;
        }
@@ -5527,37 +5585,37 @@ out_put_disk:
 
 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) 
index 79c7e3a5b36d18ef6a43161a86f1380721aaa72c..7e8e7fb40585ff71cdd4d19de5efe48cc95325ec 100644 (file)
@@ -1,12 +1,11 @@
 /*
- *     $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 <linux/config.h>
 #include <linux/completion.h>
 
-
 /*     FIXME - rename and use the following two types or delete them!
  *              and the types really should go to st.h anyway...
  *     INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
index f8291208ee0c5f2b1fbc578870f0e96610cbea2e..ff1e610946ed74b2b2e29a0af8ba19d89937cee8 100644 (file)
@@ -8,7 +8,7 @@
    Changed (and renamed) for OnStream SCSI drives garloff@suse.de
    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