Ken's Thoughts...
Recent Pictures

 
Wed, 23 Oct 2002

Bad Day
Today was a bad day at work. I didn't get much sleep because I was up late finishing up the st driver patch, and then it was just radically hectic at work. Blech.

Patch is done. I've submitted a note to Theo offering it. We'll see if he bites. Here it is:

--- /usr/src/sys/scsi/t/st.c	Sun Oct 20 16:24:21 2002
+++ /usr/src/sys/scsi/st.c	Wed Oct 23 14:52:40 2002
@@ -1,4 +1,4 @@
-/*	$OpenBSD: st.c,v 1.29 2001/06/22 14:35:43 deraadt Exp $	*/
+/*	$OpenBSD: st.c,v 1.29 2002/23/10 sallot Exp $	        */
 /*	$NetBSD: st.c,v 1.71 1997/02/21 23:03:49 thorpej Exp $	*/
 
 /*
@@ -54,6 +54,12 @@
  * to be depending on whether we expect to retension or not.
  */
 
+/* 
+ * filenumber/block support added for fsf/bsf, open, close, write, read, and eom.
+ *
+ */
+
+
 #include 
 #include 
 #include 
@@ -81,6 +87,11 @@
 #define STUNIT(z)	((minor(z) >> 4)       )
 #define CTLMODE	3
 
+#define NORMAL_MODE     0
+#define NOREW_MODE      1
+#define EJECT_MODE      2
+#define CTRL_MODE       3
+
 #define	ST_IO_TIME	(3 * 60 * 1000)		/* 3 minutes */
 #define	ST_CTL_TIME	(30 * 1000)		/* 30 seconds */
 #define	ST_SPC_TIME	(4 * 60 * 60 * 1000)	/* 4 hours */
@@ -107,6 +118,9 @@
 #define	ST_Q_IGNORE_LOADS	0x0004
 #define	ST_Q_BLKSIZE		0x0008	/* variable-block media_blksize > 0 */
 #define	ST_Q_UNIMODAL		0x0010	/* unimode drive rejects mode select */
+#define ST_Q_NOPREVENT          0x0020  /* does not support PREVENT */
+#define ST_Q_ERASE_NOIMM        0x0040  /* drive rejects ERASE/w Immed bit */
+#define ST_Q_NOFILEMARKS        0x0080  /* can only write 0 filemarks */
 	u_int page_0_size;
 #define	MAX_PAGE_0_SIZE	64
 	struct modes modes[4];
@@ -259,6 +273,12 @@
 	u_int last_dsty;	/* last density opened                */
 	short mt_resid;		/* last (short) resid                 */
 	short mt_erreg;		/* last error (sense key) seen        */
+        /* relative to beginning of tape */
+        daddr_t fileno;         /* current file number */
+	daddr_t blkno;
+        int32_t last_io_resid;
+        int32_t last_ctl_resid;
+
 /*--------------------device/scsi parameters----------------------------------*/
 	struct scsi_link *sc_link;	/* our link to the adpter etc.        */
 /*--------------------parameters reported by the device ----------------------*/
@@ -340,11 +360,15 @@
 #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_EARLYWARN    0x2000  /* Do (deferred) EOM for variable mode */
+
+#define ST_POSUPDATED   0x8000  /* tape position has been updated */
 
 #define	ST_PER_ACTION	(ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
 #define	ST_PER_MOUNT	(ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
 			 ST_FIXEDBLOCKS | ST_READONLY | ST_FM_WRITTEN | \
-			 ST_2FM_AT_EOD | ST_PER_ACTION)
+			 ST_2FM_AT_EOD | ST_PER_ACTION | ST_EARLYWARN)
+#define ST_INIT_FLAGS    ST_EARLYWARN
 
 struct scsi_inquiry_pattern st_patterns[] = {
 	{T_SEQUENTIAL, T_REMOV,
@@ -388,6 +412,8 @@
 	sc_link->device_softc = st;
 	sc_link->openings = 1;
 
+	st->flags = ST_INIT_FLAGS;
+
 	/*
 	 * Check if the drive is a known criminal and take
 	 * Any steps needed to bring it into line
@@ -558,7 +584,8 @@
 	 * mount session.
 	 */
 	if (!(st->flags & ST_MOUNTED)) {
-		st_mount_tape(dev, flags);
+		if ((error = st_mount_tape(dev, flags)) !=0 )
+                        goto bad;
 		st->last_dsty = dsty;
 	}
 
@@ -590,30 +617,80 @@
 	int mode;
 	struct proc *p;
 {
+        int stxx, error=0;
 	struct st_softc *st = st_cd.cd_devs[STUNIT(dev)];
+	struct scsi_link *sclink = st->sc_link;
+	
+	
+	/*
+	 * Make sure that a tape opened in write-only mode will have
+	 * file marks written on it when closed, even if not written to.
+	 *
+	 * This is for SUN compatibility. Actually, the Sun way of
+	 * things is to:
+	 *
+	 *	only write filemarks if there are fmks to be written and
+	 *   		- open for write (possibly read/write)
+	 *		- the last operation was a write
+	 * 	or:
+	 *		- opened for wronly
+	 *		- no data was written (including filemarks)
+	 */
+
+	stxx = st->flags & (ST_WRITTEN | ST_FM_WRITTEN);
+	if (((flags & FWRITE) && stxx == ST_WRITTEN) ||
+	    ((flags & O_ACCMODE) == FWRITE && stxx == 0)) {
+		int nm;
+		error = st_check_eod(st, FALSE, &nm, 0);
+	}
 
-	SC_DEBUG(st->sc_link, SDEV_DB1, ("closing\n"));
-	if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
-		st_write_filemarks(st, 1, 0);
 	switch (STMODE(dev)) {
-	case 0:		/* normal */
+	case NORMAL_MODE:
 		st_unmount(st, NOEJECT, DOREWIND);
 		break;
-	case 3:		/* eject, no rewind */
-		st_unmount(st, EJECT, NOREWIND);
-		break;
-	case 1:		/* no rewind */
-		/* leave mounted unless media seems to have been removed */
-		if (!(st->sc_link->flags & SDEV_MEDIA_LOADED))
-			st_unmount(st, NOEJECT, NOREWIND);
+	case NOREW_MODE:
+	case CTRL_MODE:
+		/*
+		 * Leave mounted unless media seems to have been removed.
+		 *
+		 * Otherwise, if we're to terminate a tape with more than one
+		 * filemark [ and because we're not rewinding here ], backspace
+		 * one filemark so that later appends will see an unbroken
+		 * sequence of:
+		 *
+		 *	file - FMK - file - FMK ... file - FMK FMK (EOM)
+		 */
+		if ((sclink->flags & SDEV_MEDIA_LOADED) == 0) {
+			st_unmount(st, NOEJECT,DOREWIND);
+		} else if (error == 0) {
+			/*
+			 * ST_WRITTEN was preserved from above.
+			 *
+			 * All we need to know here is:
+			 *
+			 *	Were we writing this tape and was the last
+			 *	operation a write?
+			 *
+			 *	Are there supposed to be 2FM at EOD?
+			 *
+			 * If both statements are true, then we backspace
+			 * one filemark.
+			 */
+			stxx |= (st->flags & ST_2FM_AT_EOD);
+			if ((flags & FWRITE) != 0 &&
+			    (stxx == (ST_2FM_AT_EOD|ST_WRITTEN))) {
+				error = st_space(st, -1, SP_FILEMARKS, 0);
+			}
+		}
 		break;
-	case 2:		/* rewind, eject */
-		st_unmount(st, EJECT, DOREWIND);
+	case EJECT_MODE:
+		st_unmount(st, EJECT,DOREWIND);
 		break;
 	}
-	st->sc_link->flags &= ~SDEV_OPEN;
 
-	return 0;
+	sclink->flags &= ~SDEV_OPEN;
+
+	return (error);
 }
 
 /*
@@ -715,6 +792,7 @@
 	st->flags &= ~ST_NEW_MOUNT;
 	st->flags |= ST_MOUNTED;
 	sc_link->flags |= SDEV_MEDIA_LOADED;	/* move earlier? */
+        st->blkno = st->fileno = (daddr_t) 0;
 
 	return 0;
 }
@@ -741,8 +819,12 @@
 		st_rewind(st, 0, SCSI_IGNORE_NOT_READY);
 	scsi_prevent(sc_link, PR_ALLOW,
 	    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY);
-	if (eject)
+	if (eject) {
 		st_load(st, LD_UNLOAD, SCSI_IGNORE_NOT_READY);
+                st->blkno = st->fileno = (daddr_t) -1;
+	} else {
+	  st->blkno = st->fileno = (daddr_t) 0;
+        }
 	st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT);
 	sc_link->flags &= ~SDEV_MEDIA_LOADED;
 }
@@ -1065,6 +1147,8 @@
 			_lto3b(bp->b_bcount / st->blksize, cmd.len);
 		} else
 			_lto3b(bp->b_bcount, cmd.len);
+                /* clear position updated indicator */
+                st->flags &= ~ST_POSUPDATED;
 
 		/*
 		 * go ask the adapter to do all this for us
@@ -1113,7 +1197,7 @@
 	struct proc *p;
 {
 	int error = 0;
-	int unit;
+	int unit,count;
 	int number, nmarks, dsty;
 	int flags;
 	struct st_softc *st;
@@ -1156,6 +1240,8 @@
 		g->mt_mdensity[1] = st->modes[1].density;
 		g->mt_mdensity[2] = st->modes[2].density;
 		g->mt_mdensity[3] = st->modes[3].density;
+		g->mt_fileno = st->fileno;
+		g->mt_blkno = st->blkno;
 		if (st->flags & ST_READONLY)
 			g->mt_dsreg |= MT_DS_RDONLY;
 		if (st->flags & ST_MOUNTED)
@@ -1183,11 +1269,11 @@
 		case MTBSF:	/* backward space file */
 			number = -number;
 		case MTFSF:	/* forward space file */
-			error = st_check_eod(st, FALSE, &nmarks, flags);
-			if (!error)
-				error = st_space(st, number - nmarks,
-				    SP_FILEMARKS, flags);
-			break;
+                       error = st_check_eod(st, FALSE, &nmarks, flags);
+                        if (!error)
+                                error = st_space(st, number - nmarks,
+                                    SP_FILEMARKS, flags);
+                        break;
 		case MTBSR:	/* backward space record */
 			number = -number;
 		case MTFSR:	/* forward space record */
@@ -1208,10 +1294,27 @@
 			if (!error)
 				error = st_load(st, LD_LOAD, flags);
 			break;
-		case MTEOM:	/* forward space to end of media */
-			error = st_check_eod(st, FALSE, &nmarks, flags);
-			if (!error)
-				error = st_space(st, 1, SP_EOM, flags);
+		case MTEOM:   /* rather than call SP_EOM and lose
+			       * the file count, we'll just FSF once
+			       * per file until we reach the end of the
+			       * tape.  
+			       */ 
+		        error=0;
+			count=0;
+			while ( (error==0) && (count<2000) ) { 
+			   /* do we think there'll be more than 2k filesets on a tape??  god I hope not */ 
+		  	   error = st_check_eod(st, FALSE, &nmarks, flags);
+			   if (!error)
+				error = st_space(st, 1, SP_FILEMARKS, flags);
+			   count++;
+			}
+			if (error==EIO)   /* 
+					   * good, we hit the end of the tape, BUT
+					   * we don't want to produce an error output
+					   * just for doing what we're supposed to..
+					   *
+					   */
+			  error=0;
 			break;
 		case MTCACHE:	/* enable controller cache */
 			st->flags &= ~ST_DONTBUFFER;
@@ -1575,7 +1678,7 @@
 {
 	struct scsi_space cmd;
 	int error;
-
+	
 	switch (what) {
 	case SP_BLKS:
 		if (st->flags & ST_PER_ACTION) {
@@ -1603,7 +1706,7 @@
 		}
 		break;
 	case SP_FILEMARKS:
-		if (st->flags & ST_EIO_PENDING) {
+	  if (st->flags & ST_EIO_PENDING) { /* check scsi_base */
 			if (number > 0) {
 				/* pretend we just discovered the error */
 				st->flags &= ~ST_EIO_PENDING;
@@ -1641,8 +1744,47 @@
 	cmd.byte2 = what;
 	_lto3b(number, cmd.number);
 
-	return scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
+	st->flags &= ~ST_POSUPDATED;
+	st->last_ctl_resid = 0;
+
+        error=scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
 	    sizeof(cmd), 0, 0, 0, ST_SPC_TIME, NULL, flags);
+
+         if ( (error == 0) || ((error==EIO) && (number<0)) ) {
+	       /* requests still in command queue */
+               if (number>0) { /* we're counting forward */
+                   number = number - st->last_ctl_resid; 
+		} else if (number<0) {  /* we're counting down sir! */
+		  number = number + st->last_ctl_resid;
+		}
+		if (what == SP_BLKS) {
+			if (st->blkno != -1) {
+				st->blkno += number;
+			}
+		} else if (what == SP_FILEMARKS) {  /* was != -1 */
+			if (st->fileno > -1) {
+                                st->fileno += number;
+				if (number > 0) {
+	  				st->blkno = 0;
+				} else if (number < 0) {
+					st->blkno = -1;
+				}
+			}
+		} else if (what == SP_EOM) { 
+			/*
+			 * This loses us relative position. 
+			 * But, we should never be here.
+			 */
+		  	      	st->fileno = st->blkno = -1;  
+		}
+		if (st->flags & ST_POSUPDATED) { /* if we're here, there's an error.  most likely end of tape data */
+		  error=EIO;
+		}
+
+	 }
+
+	return (error);
+
 }
 
 /*
@@ -1654,6 +1796,7 @@
 	int flags;
 	int number;
 {
+        int error;
 	struct scsi_write_filemarks cmd;
 
 	/*
@@ -1680,8 +1823,13 @@
 	cmd.opcode = WRITE_FILEMARKS;
 	_lto3b(number, cmd.number);
 
-	return scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
+	error=scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
 	    sizeof(cmd), 0, 0, 0, ST_IO_TIME * 4, NULL, flags);
+        if (error == 0 && st->fileno != -1) {
+		st->fileno += number;
+	}
+	return (error);
+
 }
 
 /*
@@ -1778,9 +1926,20 @@
 	cmd.opcode = REWIND;
 	cmd.byte2 = immediate;
 
-	return scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
+	error=scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
 	    sizeof(cmd), 0, 0, ST_RETRIES,
 	    immediate ? ST_CTL_TIME: ST_SPC_TIME, NULL, flags);
+        if (error) {
+		printf("%s: error %d trying to rewind\n",
+		    st->sc_dev.dv_xname, error);
+		/* lost position */
+		st->fileno = st->blkno = -1;
+	} else {
+		st->fileno = st->blkno = 0;
+	}
+	return (error);
+
+
 }
 
 /*
@@ -1806,19 +1965,39 @@
 		info = _4btol(sense->info);
 	else
 		info = xs->datalen;	/* bad choice if fixed blocks */
-	if ((sense->error_code & SSD_ERRCODE) != 0x70)
-		return SCSIRET_CONTINUE; /* let the generic code handle it */
+
+	if ((sense->error_code & SSD_ERRCODE) != 0x70) {
+
+	  return SCSIRET_CONTINUE; /* let the generic code handle it */
+	}
+
+        xs->resid = info;
+
 	if (st->flags & ST_FIXEDBLOCKS) {
-		xs->resid = info * st->blksize;
+	  if (bp) {
+		     xs->resid *=  st->blksize;
+                     st->last_io_resid = xs->resid;
+	  } else {
+	             st->last_ctl_resid = xs->resid;
+	  }
+
 		if (sense->flags & SSD_EOM) {
-			st->flags |= ST_EIO_PENDING;
-			if (bp)
+	  	        st->flags |= ST_EIO_PENDING;
+ 			if (bp) {
 				bp->b_resid = xs->resid;
+                                st->last_io_resid = xs->resid;
+                        } else {
+			        st->last_ctl_resid = xs->resid;
+                        }
 		}
 		if (sense->flags & SSD_FILEMARK) {
 			st->flags |= ST_AT_FILEMARK;
-			if (bp)
+			if (bp) {
 				bp->b_resid = xs->resid;
+				st->last_io_resid = xs->resid;
+                        } else {
+			        st->last_ctl_resid = xs->resid;
+                        }
 		}
 		if (sense->flags & SSD_ILI) {
 			st->flags |= ST_EIO_PENDING;
@@ -1840,6 +2019,19 @@
 			    !(sc_link->flags & SDEV_MEDIA_LOADED))
 				st->blksize -= 512;
 		}
+		if (sense->flags & SSD_EOM) {
+		  st->flags |= ST_EIO_PENDING;
+		  if (bp) {
+				/*
+				 * Grotesque as it seems, the few times
+				 * I've actually seen a non-zero resid,
+				 * the tape drive actually lied and had
+				 * written all the data!
+				 */
+	
+		    bp->b_resid = 0;
+		  }
+		}
 		/*
 		 * If no data was tranfered, do it immediatly
 		 */
@@ -1853,20 +2045,36 @@
 			}
 		}
 	} else {		/* must be variable mode */
-		xs->resid = xs->datalen;	/* to be sure */
-		if (sense->flags & SSD_EOM)
+
+		if (bp) {
+		  st->last_io_resid = xs->resid;
+		} else {
+		  st->last_ctl_resid = xs->resid;
+		}
+
+		if (sense->flags & SSD_EOM) {
 			return EIO;
+		}
+
+		/* xs->resid = xs->datalen; */	/* to be sure we've lost our mind.. */
+
 		if (sense->flags & SSD_FILEMARK) {
 			if (bp)
 				bp->b_resid = bp->b_bcount;
+			if (st->fileno != (daddr_t) -1) {
+			  st->fileno++;
+			  st->blkno=0;
+			  st->flags |= ST_POSUPDATED;
+			}
 			return 0;
 		}
+
 		if (sense->flags & SSD_ILI) {
 			if (info < 0) {
 				/*
 				 * the record was bigger than the read
 				 */
-				if ((xs->flags & SCSI_SILENT) == 0)
+				if ((xs->flags & SCSI_SILENT) == 0) 
 					printf("%s: %d-byte record too big\n",
 					    st->sc_dev.dv_xname,
 					    xs->datalen - info);
@@ -1882,8 +2090,15 @@
 					    xs->datalen);
 					return (EIO);
 				}
+			} else {
+			  if (st->blkno != (daddr_t) -1) {
+			    st->blkno++;
+			    st->flags |= ST_POSUPDATED;
+			  }
 			}
-			xs->resid = info;
+			/* let's go ahead and corrupt the results why don't we?? */
+			/*			xs->resid=info; */
+
 			if (bp)
 				bp->b_resid = info;
 			return 0;
@@ -1892,6 +2107,7 @@
 	key = sense->flags & SSD_KEY;
 
 	if (key == 0x8) {
+	  printf("key = 0x8\n");
 		/*
 		 * This quirk code helps the drive read the
 		 * first tape block, regardless of format.  That
@@ -1905,13 +2121,28 @@
 		} else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) {
 			st->flags |= ST_BLANK_READ;
 			xs->resid = xs->datalen;
+			if (st->blkno != (daddr_t) -1) {
+			  if (st->blksize>0) {
+			    st->blkno += (xs->datalen / st->blksize);
+			    st->flags |= ST_POSUPDATED;
+			  }
+                        }
 			if (bp) {
 				bp->b_resid = xs->resid;
 				/* return an EOF */
 			}
+			/* lost position */
+			st->fileno = st->blkno = -1;
 			return 0;
 		}
 	}
+
+	  /* trap this before it gets ugly. */
+      	if (sense->error_code & SSD_EOM) {
+  	     st->flags &= ~ST_EIO_PENDING;
+	     st->flags |= ST_POSUPDATED;
+	}
+
 	return SCSIRET_CONTINUE;
 }
 
@@ -1981,3 +2212,4 @@
 	/* Not implemented. */
 	return ENXIO;
 }
+

Well, Jim Greenlee's in town. I'm supposed to grab dinner with him, so I better call it a night..

Posted at: 22:49 on 23/10/2002   [ /code ] #


Older articles (2024): [ 2002 ]  [ 2003 ]  [ 2004 ]  [ 2005 ]  [ 2006 ]  [ 2007 ]  [ 2008 ]  [ 2009 ]  [ 2010 ]  [ 2011 ]  [ 2012 ]  [ 2013 ]  [ 2014 ]  [ 2015 ]  [ 2016 ]  [ 2017 ]  [ 2018 ]  [ 2019 ]  [ 2020 ]  [ 2021 ]  [ 2022 ]  [ 2023 ]  [ 2024 ]  


 
Articles
diary
eassays
travel
code

My photo album
My resume

Presentations and Papers

SAP Filtering 1998
Border Manager 1999
Astronomy Status 2002
Astronomy Update 2003
Linux on a CTX FC2A300
Honeynet Challenge entry