The diff below brings a bunch of improvements, mostly from Net/FreeBSD,
to the scsi tape driver st(4). In particular, running btape now
reports (for me) no errors no matter which combination of

Hardware End of Medium =
Fast Forward Space File = 

settings are used. I'm told this should significantly improve the
speed of modern drives like LTO-3 for Bacula by allowing 'yes' for
both.

Tests sought to confirm/refute this, and of course spot any regressions
in other tape uses! Fixes/further improvements and comments always
welcome.

.... Ken

Index: scsi_all.h
===================================================================
RCS file: /cvs/src/sys/scsi/scsi_all.h,v
retrieving revision 1.53
diff -u -p -u -p -r1.53 scsi_all.h
--- scsi_all.h  8 Jul 2011 08:13:19 -0000       1.53
+++ scsi_all.h  11 May 2013 10:53:00 -0000
@@ -378,6 +378,11 @@ struct scsi_sense_data {
 /* Additional sense code info */
 #define ASC_ASCQ(ssd)  ((ssd->add_sense_code << 8) | ssd->add_sense_code_qual)
 
+#define SENSE_FILEMARK_DETECTED                        0x0001
+#define SENSE_END_OF_MEDIUM_DETECTED           0x0002
+#define SENSE_SETMARK_DETECTED                 0x0003
+#define SENSE_BEGINNING_OF_MEDIUM_DETECTED     0x0004
+#define SENSE_END_OF_DATA_DETECTED             0x0005
 #define SENSE_NOT_READY_BECOMING_READY         0x0401
 #define SENSE_NOT_READY_INIT_REQUIRED          0x0402
 #define SENSE_NOT_READY_FORMAT                 0x0404
Index: st.c
===================================================================
RCS file: /cvs/src/sys/scsi/st.c,v
retrieving revision 1.121
diff -u -p -u -p -r1.121 st.c
--- st.c        3 Jul 2011 15:47:18 -0000       1.121
+++ st.c        12 May 2013 02:24:16 -0000
@@ -208,6 +208,7 @@ struct st_softc {
        u_int32_t media_density;        /* this is what it said when asked    */
        int media_fileno;               /* relative to BOT. -1 means unknown. */
        int media_blkno;                /* relative to BOF. -1 means unknown. */
+       int media_eom;                  /* relative to BOT. -1 means unknown. */
 
        u_int drive_quirks;     /* quirks of this drive               */
 
@@ -265,19 +266,23 @@ struct cfdriver st_cd = {
 #define        ST_FIXEDBLOCKS  0x0008
 #define        ST_AT_FILEMARK  0x0010
 #define        ST_EIO_PENDING  0x0020  /* we couldn't report it then (had 
data) */
+#define        ST_EOM_PENDING  0x0040  /* we couldn't report it then (had 
data) */
+#define ST_EOD_DETECTED        0x0080
 #define        ST_FM_WRITTEN   0x0100  /*
                                 * EOF file mark written  -- used with
                                 * ~ST_WRITTEN to indicate that multiple file
                                 * marks have been written
                                 */
-#define        ST_DYING        0x40    /* dying, when deactivated */
 #define        ST_BLANK_READ   0x0200  /* BLANK CHECK encountered already */
 #define        ST_2FM_AT_EOD   0x0400  /* write 2 file marks at EOD */
 #define        ST_MOUNTED      0x0800  /* Device is presently mounted */
 #define        ST_DONTBUFFER   0x1000  /* Disable buffering/caching */
 #define ST_WAITING     0x2000
+#define        ST_DYING        0x4000  /* dying, when deactivated */
+#define ST_BOD_DETECTED        0x8000
 
-#define        ST_PER_ACTION   (ST_AT_FILEMARK | ST_EIO_PENDING | 
ST_BLANK_READ)
+#define        ST_PER_ACTION   (ST_AT_FILEMARK | ST_EIO_PENDING | 
ST_EOM_PENDING | \
+                        ST_BLANK_READ)
 
 #define stlookup(unit) (struct st_softc *)device_lookup(&st_cd, (unit))
 
@@ -335,6 +340,7 @@ stattach(struct device *parent, struct d
        /* Start up with media position unknown. */
        st->media_fileno = -1;
        st->media_blkno = -1;
+       st->media_eom = -1;
 
        /*
         * Reset the media loaded flag, sometimes the data
@@ -660,6 +666,9 @@ st_mount_tape(dev_t dev, int flags)
            SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY);
        st->flags |= ST_MOUNTED;
        sc_link->flags |= SDEV_MEDIA_LOADED;    /* move earlier? */
+       st->media_fileno = 0;
+       st->media_blkno = 0;
+       st->media_eom = -1;
 
 done:
        device_unref(&st->sc_dev);
@@ -927,7 +936,8 @@ ststart(struct scsi_xfer *xs)
                }
 
                /*
-                * only FIXEDBLOCK devices have pending operations
+                * Only FIXEDBLOCK devices have pending I/O or space
+                * operations.
                 */
                if (st->flags & ST_FIXEDBLOCKS) {
                        /*
@@ -962,26 +972,27 @@ ststart(struct scsi_xfer *xs)
                                        continue;       /* seek more work */
                                }
                        }
-                       /*
-                        * If we are at EIO (e.g. EOM) but have not reported it
-                        * yet then we should report it now
-                        */
+               }
+
+               /*
+                * If we are at EIO or EOM but have not reported it
+                * yet then we should report it now.
+                */
+               if (st->flags & (ST_EOM_PENDING | ST_EIO_PENDING)) {
+                       bp->b_resid = bp->b_bcount;
                        if (st->flags & ST_EIO_PENDING) {
-                               bp->b_resid = bp->b_bcount;
                                bp->b_error = EIO;
                                bp->b_flags |= B_ERROR;
-                               st->flags &= ~ST_EIO_PENDING;
-                               s = splbio();
-                               biodone(bp);
-                               splx(s);
-                               continue;       /* seek more work */
                        }
+                       st->flags &= ~(ST_EOM_PENDING | ST_EIO_PENDING);
+                       s = splbio();
+                       biodone(bp);
+                       splx(s);
+                       continue;       /* seek more work */
                }
-
                break;
        }
 
-
        /*
         *  Fill out the scsi command
         */
@@ -1667,7 +1678,7 @@ st_space(struct st_softc *st, int number
                                        st->flags &= ~ST_BLANK_READ;
                                        return EIO;
                                }
-                               st->flags &= ~ST_EIO_PENDING;
+                               st->flags &= ~(ST_EIO_PENDING | ST_EOM_PENDING);
                        }
                }
                break;
@@ -1693,6 +1704,11 @@ st_space(struct st_softc *st, int number
                }
                break;
        case SP_EOM:
+               if (st->flags & ST_EOM_PENDING) {
+                       /* We are already there. */
+                       st->flags &= ~ST_EOM_PENDING;
+                       return (0);
+               }
                if (st->flags & ST_EIO_PENDING) {
                        /* pretend we just discovered the error */
                        st->flags &= ~ST_EIO_PENDING;
@@ -1706,11 +1722,8 @@ st_space(struct st_softc *st, int number
                return 0;
 
        xs = scsi_xs_get(st->sc_link, flags);
-       if (xs == NULL) {
-               st->media_fileno = -1;
-               st->media_blkno = -1;
+       if (xs == NULL)
                return (ENOMEM);
-       }
 
        cmd = (struct scsi_space *)xs->cmd;
        cmd->opcode = SPACE;
@@ -1719,6 +1732,8 @@ st_space(struct st_softc *st, int number
        xs->cmdlen = sizeof(*cmd);
        xs->timeout = ST_SPC_TIME;
 
+       CLR(st->flags, ST_EOD_DETECTED);
+
        error = scsi_xs_sync(xs);
        scsi_xs_put(xs);
 
@@ -1736,10 +1751,22 @@ st_space(struct st_softc *st, int number
                        break;
                case SP_FILEMARKS:
                        if (st->media_fileno != -1) {
-                               st->media_fileno += number;
+                               if (!ISSET(st->flags, ST_EOD_DETECTED))
+                                       st->media_fileno += number;
+                               if (st->media_fileno > st->media_eom)
+                                       st->media_eom = st->media_fileno;
                                st->media_blkno = 0;
                        }
                        break;
+               case SP_EOM:
+                       if (st->media_eom != -1) {
+                               st->media_fileno = st->media_eom;
+                               st->media_blkno = 0;
+                       } else {
+                               st->media_fileno = -1;
+                               st->media_blkno = -1;
+                       }
+                       break;
                default:
                        st->media_fileno = -1;
                        st->media_blkno = -1;
@@ -1764,11 +1791,9 @@ st_write_filemarks(struct st_softc *st, 
                return (EINVAL);
 
        xs = scsi_xs_get(st->sc_link, flags);
-       if (xs == NULL) {
-               st->media_fileno = -1;
-               st->media_blkno = -1;
+       if (xs == NULL)
                return (ENOMEM);
-       }
+
        xs->cmdlen = sizeof(*cmd);
        xs->timeout = ST_IO_TIME * 4;
 
@@ -1797,8 +1822,10 @@ st_write_filemarks(struct st_softc *st, 
        if (error != 0) {
                st->media_fileno = -1;
                st->media_blkno = -1;
+               st->media_eom = -1;
        } else if (st->media_fileno != -1) {
                st->media_fileno += number;
+               st->media_eom = st->media_fileno;
                st->media_blkno = 0;
        }
 
@@ -1847,6 +1874,7 @@ st_load(struct st_softc *st, u_int type,
 
        st->media_fileno = -1;
        st->media_blkno = -1;
+       st->media_eom = -1;
 
        if (type != LD_LOAD) {
                error = st_check_eod(st, FALSE, &nmarks, flags);
@@ -1927,16 +1955,19 @@ st_interpret_sense(struct scsi_xfer *xs)
 {
        struct scsi_sense_data *sense = &xs->sense;
        struct scsi_link *sc_link = xs->sc_link;
+       struct scsi_space *space;
        struct st_softc *st = sc_link->device_softc;
        u_int8_t serr = sense->error_code & SSD_ERRCODE;
        u_int8_t skey = sense->flags & SSD_KEY;
-       int32_t resid;
+       int32_t resid, info, number;
        int datalen;
 
        if (((sc_link->flags & SDEV_OPEN) == 0) ||
            (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
                return (scsi_interpret_sense(xs));
 
+       info = (int32_t)_4btol(sense->info);
+
        switch (skey) {
 
        /*
@@ -1963,12 +1994,32 @@ st_interpret_sense(struct scsi_xfer *xs)
                        return (scsi_delay(xs, 1));
                default:
                        return (scsi_interpret_sense(xs));
-       }
+               }
+               break;
+       case SKEY_BLANK_CHECK:
+               if (sense->error_code & SSD_ERRCODE_VALID &&
+                   xs->cmd->opcode == SPACE) {
+                       switch (ASC_ASCQ(sense)) {
+                       case SENSE_END_OF_DATA_DETECTED:
+                               st->flags |= ST_EOD_DETECTED;
+                               space = (struct scsi_space *)xs->cmd;
+                               number = _3btol(space->number);
+                               st->media_fileno = number - info;
+                               st->media_eom = st->media_fileno;
+                               return (0);
+                       case SENSE_BEGINNING_OF_MEDIUM_DETECTED:
+                               /* Standard says: Position is undefined! */
+                               st->flags |= ST_BOD_DETECTED;
+                               st->media_fileno = -1;
+                               st->media_blkno = -1;
+                               return (0);
+                       }
+               }
+               break;
        case SKEY_NO_SENSE:
        case SKEY_RECOVERED_ERROR:
        case SKEY_MEDIUM_ERROR:
        case SKEY_VOLUME_OVERFLOW:
-       case SKEY_BLANK_CHECK:
                break;
        default:
                return (scsi_interpret_sense(xs));
@@ -1982,7 +2033,7 @@ st_interpret_sense(struct scsi_xfer *xs)
         */
        datalen = xs->datalen;
        if (sense->error_code & SSD_ERRCODE_VALID) {
-               xs->resid = resid = (int32_t)_4btol(sense->info);
+               xs->resid = resid = info;
                if (st->flags & ST_FIXEDBLOCKS) {
                        xs->resid *= st->blksize;
                        datalen /= st->blksize;
@@ -2000,6 +2051,8 @@ st_interpret_sense(struct scsi_xfer *xs)
        if (sense->flags & SSD_FILEMARK) {
                if (st->media_fileno != -1) {
                        st->media_fileno++;
+                       if (st->media_fileno > st->media_eom)
+                               st->media_eom = st->media_fileno;
                        st->media_blkno = 0;
                }
                if ((st->flags & ST_FIXEDBLOCKS) == 0)
@@ -2008,9 +2061,10 @@ st_interpret_sense(struct scsi_xfer *xs)
        }
 
        if (sense->flags & SSD_EOM) {
-               if ((st->flags & ST_FIXEDBLOCKS) == 0)
-                       return EIO;
-               st->flags |= ST_EIO_PENDING;
+               st->flags |= ST_EOM_PENDING;
+               xs->resid = 0;
+               if (st->flags & ST_FIXEDBLOCKS)
+                       return (0);
        }
 
        if (sense->flags & SSD_ILI) {
@@ -2059,6 +2113,7 @@ st_interpret_sense(struct scsi_xfer *xs)
                        st->blksize -= 512;
                } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) {
                        st->flags |= ST_BLANK_READ;
+                       st->flags |= ST_EOM_PENDING;
                        xs->resid = xs->datalen;
                        return (0);
                }

Reply via email to