*BSD News Article 58338


Return to BSD News archive

Newsgroups: comp.bugs.2bsd
Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!news.mel.connect.com.au!munnari.OZ.AU!news.ecn.uoknor.edu!news.cis.okstate.edu!news.ksu.ksu.edu!news.mid.net!crcnews.unl.edu!newspump.wustl.edu!news.ecn.bgu.edu!vixen.cso.uiuc.edu!newsfeed.internetmci.com!in1.uu.net!news.new-york.net!wlbr!sms
From: sms@wlv.iipo.gtegsc.com (Steven M. Schultz)
Subject: TU81 bug,statfs(2)+fstatfs(2)+getfsstat(2) missing, More (#286 4 of 4)
Sender: news@wlbr.iipo.gtegsc.com (Steven M. Schultz)
Organization: GTE Government Systems, Thousand Oaks CA USA
Message-ID: <DKAHFL.9oq@wlbr.iipo.gtegsc.com>
X-Nntp-Posting-Host: wlv.iipo.gtegsc.com
Date: Thu, 28 Dec 1995 09:09:20 GMT
Lines: 2768

Subject: TU81 bug,statfs(2)+fstatfs(2)+getfsstat(2) missing, More (#286 4 of 4)
Index:	sys/pdpuba,pdp,sys 2.11BSD

Description:
	See #283.

Repeat-By:
	See #283.

Fix:
	This is #286, part 4 of 4.  Refer to #283 for installation instructions.

	The following files are modified by this part of the update kit:

/usr/src/sys/pdpuba/tmscp.c
/usr/src/sys/pdpuba/tmscpreg.h
/VERSION

--------------------------cut here---------------------------
*** /usr/src/sys/pdpuba/tmscp.c.old	Fri Dec  9 23:10:39 1994
--- /usr/src/sys/pdpuba/tmscp.c	Fri Dec 22 20:49:26 1995
***************
*** 1,5 ****
! /*	@(#)tmscp.c	1.4 (2.11BSD GTE) 12/9/94 */
  
  #if	!defined(lint) && defined(DOSCCS)
  static	char	*sccsid = "@(#)tmscp.c	1.24	(ULTRIX)	1/21/86";
  #endif
--- 1,7 ----
! #define	TMSDEBUG	1
  
+ /*	@(#)tmscp.c	1.5 (2.11BSD GTE) 1995/12/08 */
+ 
  #if	!defined(lint) && defined(DOSCCS)
  static	char	*sccsid = "@(#)tmscp.c	1.24	(ULTRIX)	1/21/86";
  #endif
***************
*** 31,36 ****
--- 33,60 ----
   * tmscp.c - TMSCP (TK50/TU81) tape device driver
   * 
   * Modification History:
+  *
+  * 14-Dec-95 - sms@wlv...
+  *	Success!  But the size of the driver is even more of a problem now.
+  *	If the crash dump option is defined the driver could exceed the max
+  *	size permitted for an overlay.  The 'tmsdump' routine was moved to
+  *	a separate file.  This driver almost always must be in an overlay 
+  *	by itself now.
+  *
+  * 08-Dec-95 - sms@wlv...
+  *	Begin serious surgery on this driver.  The goals are: 1) to correctly
+  *	handle TU81/81+ drives (do not set density unless at BOT), 2) support
+  *	use of the cache on drives which implement it (TU81+), 3) improve 
+  *	error detection and reporting, 4) improve readability by replacing
+  *	multipage 'switch' statements with calls to functions, 5) make it
+  *	easier to add new capabilities and fix problems without wholescale
+  *	changes again.
+  *
+  * 30-Nov-95 - sms@wlv...
+  *	Experiment to see if M_MD_IMMED being set for the rewind on close
+  *	obviates the need for skipping the iowait().  Success - only 2 ticks
+  *	elapse doing the iowait!.
+  *
   * 02-Jan-93 - sms@wlv. [2.11BSD]
   *	Remove unibus map ifdefs and rely on run time testing of 'ubmap' which
   * 	does the right thing and makes kernels easier to move between machines.
***************
*** 187,200 ****
  #include "uio.h"
  #include "tty.h"
  #include "uba.h"
  
- #define	TMS_PRI	LOG_INFO
- 
- #define NRSPL2  3               /* log2 number of response packets */
- #define NCMDL2  3               /* log2 number of command packets */
- #define NRSP    (1<<NRSPL2)
- #define NCMD    (1<<NCMDL2)
- 
  #include "tmscpreg.h"
  #include "../pdp/tmscp.h"
  #include "../machine/seg.h"
--- 211,218 ----
  #include "uio.h"
  #include "tty.h"
  #include "uba.h"
+ #include "kernel.h"
  
  #include "tmscpreg.h"
  #include "../pdp/tmscp.h"
  #include "../machine/seg.h"
***************
*** 214,279 ****
  /* HI */    {0,M_TF_800,M_TF_PE,M_TF_PE,M_TF_GCR,M_TF_GCR,M_TF_GCR,M_TF_GCR}
  		};
  
! /* Software state per controller */
  
- struct tmscp_softc {
- 	struct	tmscpdevice *sc_addr;	/* controller CSR address */
- 	short   sc_state;       /* state of controller */
- 	short	sc_ivec;        /* interrupt vector address */
- 	short	sc_unit;	/* CONTROLLER number - NOT drive unit # */
- 	short   sc_credits;     /* transfer credits */
- 	short   sc_lastcmd;     /* pointer into command ring */
- 	short   sc_lastrsp;     /* pointer into response ring */
- 	struct	buf sc_cmdbuf;	/* internal command buffer */
- 	struct	buf sc_ctab;	/* controller queue */
- 	struct	buf sc_wtab;	/* I/O wait queue for controller */
- 	struct	tmscp *sc_com;	/* communications area pointer */
- 	struct	tms_info *sc_drives[4];	/* pointers to per drive info */
- } tmscp_softc[NTMSCP];
- 
- #define	RINGBASE	(4 * sizeof (short))
- 
- struct tmscp {
- 	struct tmscpca	tmscp_ca;         /* communications area */
- 	struct mscp	tmscp_rsp[NRSP];  /* response packets */
- 	struct mscp	tmscp_cmd[NCMD];  /* command packets */
- };					  /* 1896 bytes per controller! */
- 
  	memaddr	tmscp[NTMSCP];		/* click addresses of ctrl comm area */
  
  /*
!  * Per drive-unit info
!  */
! struct tms_info {
! 	daddr_t		tms_dsize;	/* Max user size from online pkt */
! 	long		tms_type;	/* Drive type field  */
! 	int		tms_resid;	/* residual from last xfer */
! 	u_char		tms_endcode;	/* last command endcode */
! 	u_char		tms_flags;	/* last command end flags */
! 	unsigned	tms_status;	/* Command status from last command */
! 	char		tms_openf;	/* lock against multiple opens */
! 	char		tms_lastiow;	/* last op was a write */
! 	char		tms_serex;	/* set when serious exception occurs */
! 	char		tms_clserex;	/* set when serex being cleared by no-op */
! 	short		tms_fmtmenu;	/* the unit's format (density) menu */
! 	short		tms_unitflgs;	/* unit flag parameters */
! 	short		tms_format;	/* the unit's current format (density) */
! 	struct tty	*tms_ttyp;	/* record user's tty for errors */
! 	struct	buf	tms_dtab;	/* I/O tape drive queues */
! 	short		tms_online;	/* 0=available, 1=online, -1=offline */
! } tms_info[NTMS];
  
! /* Bits in minor device */
! #define	TMSUNIT(dev)	(minor(dev)&03)
! #define	TMSCTLR(dev)	((minor(dev) >> 6) & 3)
! #define	TMSDENS(dev)	((minor(dev) >> 3) & 3)
! #define	FMTMASK		(M_TF_800|M_TF_PE|M_TF_GCR)	/* = 7 */
  
- #define	T_NOREWIND	04
- 
- /* Size to map in when mapping a controller's command packet area */
- #define	MAPBUFDESC	(((btoc(sizeof (struct tmscp)) - 1) << 8) | RW)
- 
  /*
   * Internal (ioctl) command codes (these must also be declared in the
   * tmscpioctl routine).  These correspond to ioctls in mtio.h
--- 232,261 ----
  /* HI */    {0,M_TF_800,M_TF_PE,M_TF_PE,M_TF_GCR,M_TF_GCR,M_TF_GCR,M_TF_GCR}
  		};
  
! struct	tmscp_softc tmscp_softc[NTMSCP];	/* Controller info */
! struct	tms_info tms_info[NTMS];		/* Drive info */
  
  	memaddr	tmscp[NTMSCP];		/* click addresses of ctrl comm area */
  
  /*
!  * Bit definitions for Tflags word above.  These take the place of several
!  * individual structure members in tms_info.
! */
  
! #define	_SEREX		0x0001		/* Serious Exception exists */
! #define	_CLSEREX	0x0002		/* Do Clear Serious Exception */
! #define	_EOM		0x0004		/* At End Of Media */
! #define	_BOM		0x0008		/* At Beginning Of Media */
! #define	_WRITTEN	0x0010		/* Tape has been Written */
! #define	_LOST		0x0020		/* Position lost error happened */
! #define	_BUFMARK	0x0040		/* Encountered a tape mark */
! #define	_HASCACHE	0x0080		/* Drive has cache capability */
! #define	_CACHE_ON	0x0100		/* Cache enabled */
! #define	_CACHE_LOST	0x0200		/* Cache data loss has happened */
! #define	_CACHE_WRITTEN	0x0400		/* Cache has been written */
! #define	_INUSE		0x0800		/* Drive is in use */
! #define	_ONLINE		0x1000		/* Drive is online */
  
  /*
   * Internal (ioctl) command codes (these must also be declared in the
   * tmscpioctl routine).  These correspond to ioctls in mtio.h
***************
*** 288,296 ****
  #define TMS_SENSE	7		/* noop - do a get unit status */
  #define TMS_CACHE	8		/* enable cache */
  #define TMS_NOCACHE	9		/* disable cache */
  /* These go last: after all real mt cmds, just bump the numbers up */
! #define TMS_CSE		10		/* clear serious exception */
! #define TMS_SETDENSITY	11		/* set unit density */
  
  /*
   * Controller states
--- 270,279 ----
  #define TMS_SENSE	7		/* noop - do a get unit status */
  #define TMS_CACHE	8		/* enable cache */
  #define TMS_NOCACHE	9		/* disable cache */
+ #define	TMS_FLUSH	10		/* flush cache */
  /* These go last: after all real mt cmds, just bump the numbers up */
! #define TMS_CSE		11		/* clear serious exception */
! #define TMS_SETDENSITY	12		/* set unit density */
  
  /*
   * Controller states
***************
*** 302,311 ****
  #define S_SCHAR 4               /* doing "set controller characteristics" */
  #define S_RUN   5               /* running */
  
! static	char *tmscpstepfailed = "step%d init failed: sa 0x%x\n";
! static	char *tmscpfatalerr = "tms%d,%d: fatal error 0%o\n";
  
! int     tmscperror = 0;		/* causes hex dump of packets */
  int	tmscp_cp_wait = 0;	/* Something to wait on for command */
  				/* packets and or credits. */
  int	wakeup();
--- 285,294 ----
  #define S_SCHAR 4               /* doing "set controller characteristics" */
  #define S_RUN   5               /* running */
  
! static	char *tmscpstepfailed = "step%d init failed: sa %x\n";
! 	char *tmscpfatalerr = "tms%d,%d: fatal error %x\n";
  
! int     tmscperror = 0;		/* enable last failed packet return */
  int	tmscp_cp_wait = 0;	/* Something to wait on for command */
  				/* packets and or credits. */
  int	wakeup();
***************
*** 312,322 ****
  extern	int	hz;		/* Should find the right include */
  extern	long	_iomap();
  
! #ifdef	TMSCP_DEBUG
! #define printd if (tmscpdebug) printf
! int tmscpdebug = 1;
! #define	printd10 if(tmscpdebug >= 10) printf
! #endif 
  
  struct  mscp *tmscpgetcp();
  
--- 295,309 ----
  extern	int	hz;		/* Should find the right include */
  extern	long	_iomap();
  
! /*
!  * Most of these only take effect when TMSDEBUG is defined.
!  *
!  * Bit 0 = print all non-successful response packets _except_ hitting a
!  *	   tapemark (which really isn't an error).
!  * Bit 1 = print datagram arrival message.
!  * Bit 2 = print status of all response packets except datagrams.
! */
! int	tmscpprintf = 1;
  
  struct  mscp *tmscpgetcp();
  
***************
*** 368,380 ****
  	register struct tms_info *p;
  
  	for (i = NTMS, p = tms_info; i--; p++) {
! 		if (p->tms_online == 0)
  			return(p);
  	}
! 	log(TMS_PRI, "tms: no drive descriptors\n");
  	return(NULL);
  }
  
  /*
   * TMSCP interrupt routine.
   */
--- 355,388 ----
  	register struct tms_info *p;
  
  	for (i = NTMS, p = tms_info; i--; p++) {
! 		if ((p->Tflags & _INUSE) == 0)
  			return(p);
  	}
! 	log(LOG_INFO, "tms: !drives\n");
  	return(NULL);
  }
  
+ static int
+ wait_step(mask, good, csr, sc)
+ 	u_short mask, good;
+ 	register struct tmscpdevice *csr;
+ 	register struct	tmscp_softc *sc;
+ 	{
+ 	register int i;
+ 
+ 	for	(i = 0; i < 150; i++)
+ 		{
+ 		if	((csr->tmscpsa & mask) == good)
+ 			return(0);
+ 		delay(10000L);		/* still in step - wait 1/100 sec */
+ 		}
+ 	sc->sc_state = S_IDLE;
+ 	sc->sc_ctab.b_active = 0;
+ 	log(LOG_INFO, tmscpstepfailed, sc->sc_state, csr->tmscpsa);
+ 	wakeup((caddr_t)&sc->sc_ctab);
+ 	return(-1);
+ 	}
+ 
  /*
   * TMSCP interrupt routine.
   */
***************
*** 383,389 ****
  {
  	register struct tmscpdevice *tmscpaddr;
  	struct buf *bp;
! 	register int i;
  	register struct tmscp_softc *sc = &tmscp_softc[dev];
  	register struct tmscp *tm = sc->sc_com;
  	struct mscp *mp;
--- 391,397 ----
  {
  	register struct tmscpdevice *tmscpaddr;
  	struct buf *bp;
! 	int	i;
  	register struct tmscp_softc *sc = &tmscp_softc[dev];
  	register struct tmscp *tm = sc->sc_com;
  	struct mscp *mp;
***************
*** 390,398 ****
  	segm seg5;
  
  	tmscpaddr = sc->sc_addr;
- #ifdef TMSCP_DEBUG
- 	printd10("tmscpintr: state %d, tmscpsa %o\n", sc->sc_state, tmscpaddr->tmscpsa);
- #endif	
  
  	/*
  	 * How the interrupt is handled depends on the state of the controller.
--- 398,403 ----
***************
*** 400,406 ****
  	switch (sc->sc_state) {
  
  	case S_IDLE:
! 		printf("tms%d: random intr ignored\n", dev);
  		return;
  
  	/* Controller was in step 1 last, see if its gone to step 2 */
--- 405,411 ----
  	switch (sc->sc_state) {
  
  	case S_IDLE:
! 		log(LOG_INFO, "tms%d: random intr\n", dev);
  		return;
  
  	/* Controller was in step 1 last, see if its gone to step 2 */
***************
*** 407,432 ****
  	case S_STEP1:
  #		define STEP1MASK 0174377
  #		define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
! 		for (i = 0; i < 150; i++)
! 			{
! 			if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
! 				{ /* still in step 1 (wait 1/100 sec) */
! 				delay(10000L);
! #ifdef TMSCP_DEBUG
! 				printd("still in step 1, delaying\n");
! #endif
! 				}
! 			else
! 				break;
! 			}
! 		if (i > 149)
! 			{
! 			sc->sc_state = S_IDLE;
! 			sc->sc_ctab.b_active = 0;
! 			printf(tmscpstepfailed,sc->sc_state,tmscpaddr->tmscpsa);
! 			wakeup((caddr_t)&sc->sc_ctab);
  			return;
- 			}
  		tmscpaddr->tmscpsa = (short)sc->sc_ctab.b_un.b_addr;
  		sc->sc_state = S_STEP2;
  		return;
--- 412,420 ----
  	case S_STEP1:
  #		define STEP1MASK 0174377
  #		define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
! 
! 		if	(wait_step(STEP1MASK, STEP1GOOD, tmscpaddr, sc) < 0)
  			return;
  		tmscpaddr->tmscpsa = (short)sc->sc_ctab.b_un.b_addr;
  		sc->sc_state = S_STEP2;
  		return;
***************
*** 435,460 ****
  	case S_STEP2:
  #		define STEP2MASK 0174377
  #		define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4))
! 		for (i = 0; i < 150; i++)
! 			{
! 			if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
! 				{ /* still in step 2 (wait 1/100 sec) */
! 				delay(10000L);
! #ifdef TMSCP_DEBUG
! 				printd("still in step 2, delaying\n");
! #endif
! 				}
! 			else
! 				break;
! 			}
! 		if (i > 149)
! 			{
! 			sc->sc_state = S_IDLE;
! 			sc->sc_ctab.b_active = 0;
! 			printf(tmscpstepfailed,sc->sc_state,tmscpaddr->tmscpsa);
! 			wakeup((caddr_t)&sc->sc_ctab);
  			return;
- 			}
  		tmscpaddr->tmscpsa = sc->sc_ctab.b_xmem;
  		sc->sc_state = S_STEP3;
  		return;
--- 423,431 ----
  	case S_STEP2:
  #		define STEP2MASK 0174377
  #		define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4))
! 
! 		if	(wait_step(STEP2MASK, STEP2GOOD, tmscpaddr, sc) < 0)
  			return;
  		tmscpaddr->tmscpsa = sc->sc_ctab.b_xmem;
  		sc->sc_state = S_STEP3;
  		return;
***************
*** 463,502 ****
  	case S_STEP3:
  #		define STEP3MASK 0174000
  #		define STEP3GOOD TMSCP_STEP4
! 		for (i = 0; i < 150; i++)
! 			{
! 			if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
! 				{ /* still in step 3 (wait 1/100 sec) */
! 				delay(10000L);
! #ifdef TMSCP_DEBUG
! 				printd("still in step 3, delaying\n");
! #endif
! 				}
! 			else
! 				break;
! 			}
! 		if (i > 149)
! 			{
! 			sc->sc_state = S_IDLE;
! 			sc->sc_ctab.b_active = 0;
! 			printf(tmscpstepfailed,sc->sc_state,tmscpaddr->tmscpsa);
! 			wakeup((caddr_t)&sc->sc_ctab);
  			return;
- 			}
  		/*
  		 * Get microcode version and model number of controller;
  		 * Signal initialization complete (_GO) (to the controller);
- 		 *    ask for Last Fail response if tmscperror is set;
  		 * Set state to "set controller characteristics".
  		 */
  		i = tmscpaddr->tmscpsa;
! 		tmscpaddr->tmscpsa = TMSCP_GO | (tmscperror? TMSCP_LF : 0);
  		sc->sc_state = S_SCHAR;
- #ifdef TMSCP_DEBUG
- 		printd("tmscpintr: completed state %d \n", sc->sc_state);
- 		printd("tmscp%d Version: %d model %d\n", dev, i & 0xf, (i >> 4) & 0xf);
- #endif
  
  	    /*
  	     * Initialize the data structures (response and command queues).
  	     */
--- 434,454 ----
  	case S_STEP3:
  #		define STEP3MASK 0174000
  #		define STEP3GOOD TMSCP_STEP4
! 
! 		if	(wait_step(STEP3MASK, STEP3GOOD, tmscpaddr, sc) < 0)
  			return;
  		/*
  		 * Get microcode version and model number of controller;
  		 * Signal initialization complete (_GO) (to the controller);
  		 * Set state to "set controller characteristics".
  		 */
  		i = tmscpaddr->tmscpsa;
! 		tmscpaddr->tmscpsa = TMSCP_GO | TMSCP_LF;
  		sc->sc_state = S_SCHAR;
  
+ 		log(LOG_INFO, "tms%d Ver %d Mod %d\n", dev, i & 0xf,
+ 			(i >> 4) & 0xf);
+ 
  	    /*
  	     * Initialize the data structures (response and command queues).
  	     */
***************
*** 533,539 ****
  		break;
  
  	default:
! 	    printf("tms%d: intr unknown state %d ignored\n",dev,sc->sc_state);
  	    return;
  	}	/* end switch */
  
--- 485,491 ----
  		break;
  
  	default:
! 	    log(LOG_INFO, "tms%d: state %d\n", dev, sc->sc_state);
  	    return;
  	}	/* end switch */
  
***************
*** 547,553 ****
  	 */
  	if (tmscpaddr->tmscpsa&TMSCP_ERR)
  		{
! 		printf(tmscpfatalerr, dev, sc->sc_unit, tmscpaddr->tmscpsa);
  		tmscpaddr->tmscpip = 0;
  		sc->sc_state = S_IDLE;
  		sc->sc_ctab.b_active = 0;
--- 499,505 ----
  	 */
  	if (tmscpaddr->tmscpsa&TMSCP_ERR)
  		{
! 		log(LOG_INFO, tmscpfatalerr, dev, sc->sc_unit, tmscpaddr->tmscpsa);
  		tmscpaddr->tmscpip = 0;
  		sc->sc_state = S_IDLE;
  		sc->sc_ctab.b_active = 0;
***************
*** 584,596 ****
  	/*
  	 * Check for command ring transition. (Should never happen!)
  	 */
! 	if (tm->tmscp_ca.ca_cmdint)
! 		{
! #ifdef TMSCP_DEBUG
! 		printd("tmscpintr: command ring transition\n");
! #endif		
  		tm->tmscp_ca.ca_cmdint = 0;
- 		}
  	restorseg5(seg5);
      	if (tmscp_cp_wait)
  		wakeup((caddr_t)&tmscp_cp_wait);
--- 536,543 ----
  	/*
  	 * Check for command ring transition. (Should never happen!)
  	 */
! 	if	(tm->tmscp_ca.ca_cmdint)
  		tm->tmscp_ca.ca_cmdint = 0;
  	restorseg5(seg5);
      	if (tmscp_cp_wait)
  		wakeup((caddr_t)&tmscp_cp_wait);
***************
*** 616,625 ****
  	struct tmscpdevice *tmscpaddr;
  	int s,i;
  	
- #ifdef TMSCP_DEBUG
- 	printd("tmscpopen %d,%d\n", ctlr, unit);
- 	if (tmscpdebug) delay(10000L);
- #endif
  	if (ctlr >= NTMSCP)
  		return (ENXIO);
  	sc = &tmscp_softc[ctlr];
--- 563,568 ----
***************
*** 629,648 ****
  		tms = getdd();
  		if (!tms)
  			return(ENXIO);
! 		tms->tms_online = -1;
  		sc->sc_drives[unit] = tms;
  	}
! 	if (tms->tms_openf)
  		return(EBUSY);
! 	tms->tms_openf = 1;
! 	tms->tms_ttyp = u.u_ttyp;
  	s = spl5();
  	if (sc->sc_state != S_RUN)
  		{
  		if (sc->sc_state == S_IDLE)
! 			if(!tkini(sc))
  				{
! 				printf("tms%d init failed\n", ctlr);
  				(void) splx(s);
  				return(ENXIO);
  				}
--- 572,591 ----
  		tms = getdd();
  		if (!tms)
  			return(ENXIO);
! 		tms->Tflags &= ~_ONLINE;
  		sc->sc_drives[unit] = tms;
  	}
! 	if	(tms->Tflags & _INUSE)
  		return(EBUSY);
! 	tms->Tflags |= _INUSE;
! 
  	s = spl5();
  	if (sc->sc_state != S_RUN)
  		{
  		if (sc->sc_state == S_IDLE)
! 			if	(!tkini(sc))
  				{
! 				log(LOG_INFO, "tms%d init fail\n", ctlr);
  				(void) splx(s);
  				return(ENXIO);
  				}
***************
*** 651,674 ****
  		 */
  		timeout(wakeup,(caddr_t)&sc->sc_ctab,11*hz);	/* to be sure*/
  		sleep((caddr_t)&sc->sc_ctab, PSWP+1);
! 		if (sc->sc_state != S_RUN)
  			{
  			sc->sc_drives[unit] = NULL;
! 			tms->tms_online = tms->tms_openf = 0;
  			(void) splx(s);
! 			return (EIO);
  			}
  		}
  	/*
! 	 * Check to see if the device is really there.
! 	 * this code was taken from Fred Canters 11 driver
  	 */
  	tmscpaddr = (struct tmscpdevice *) sc->sc_addr;
! 	(void) splx(s);
! 	if(tms->tms_online == -1)
  		{
  		s = spl5();
! 		while ((mp = tmscpgetcp(sc)) == 0)
  			{
  			tmscp_cp_wait++;
  			sleep((caddr_t)&tmscp_cp_wait,PSWP+1);
--- 594,619 ----
  		 */
  		timeout(wakeup,(caddr_t)&sc->sc_ctab,11*hz);	/* to be sure*/
  		sleep((caddr_t)&sc->sc_ctab, PSWP+1);
! 		if	(sc->sc_state != S_RUN)
  			{
  			sc->sc_drives[unit] = NULL;
! 			tms->Tflags &= ~(_INUSE | _ONLINE);
  			(void) splx(s);
! 			return(EIO);
  			}
  		}
+ 	(void) splx(s);
+ 
  	/*
! 	 * If drive is not online get a command packet, sleeping if no
! 	 * controller credits are available at the moment.  Then start
! 	 * the ONLINE process.
  	 */
  	tmscpaddr = (struct tmscpdevice *) sc->sc_addr;
! 	if	(!(tms->Tflags & _ONLINE))
  		{
  		s = spl5();
! 		while	((mp = tmscpgetcp(sc)) == 0)
  			{
  			tmscp_cp_wait++;
  			sleep((caddr_t)&tmscp_cp_wait,PSWP+1);
***************
*** 680,688 ****
  		mp->mscp_unit = unit;		/* unit? */
  		mp->mscp_cmdref = (u_short)&tms->tms_type;
  					    /* need to sleep on something */
- #ifdef TMSCP_DEBUG
- 		printd("tmscpopen: bring unit %d,%d online\n",ctlr, unit);
- #endif	
  		((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN | TMSCP_INT;
  		normalseg5();
  		i = tmscpaddr->tmscpip;
--- 625,630 ----
***************
*** 694,726 ****
  		 */
  		timeout(wakeup,(caddr_t) &tms->tms_type,240 * hz);
  		sleep((caddr_t) &tms->tms_type,PSWP+1);
  		}
! 	if	(tms->tms_online == -1)
  		{
! oops:		tms->tms_online = tms->tms_openf = 0;
  		sc->sc_drives[unit] = NULL;
  		return(ENXIO);  /* Didn't go online */
  		}
! 	/*
! 	 * Get the unit characteristics (GTUNT).  Done here because we
! 	 * do not check for slave units at autoconfigure time.  This really
! 	 * only need be done once, but it's easier to do it on each open.
! 	 * tmscpcommand() is used since the iodone() handling for GTUNT has
! 	 * been fixed.
! 	*/
! 	tms->tms_type = 0;
  	tmscpcommand(dev, TMS_SENSE, 1);
! 	if	(tms->tms_type == 0)
  		goto oops;
! 	tms->tms_lastiow = 0;
! 	/*
! 	 * Set unit density using the density matrix.
! 	 * This is done as an "internal" ioctl command so
! 	 * that the command setup and response handling
! 	 * is done thru "regular" command routines.
! 	 */
  	tmscpcommand(dev, TMS_SETDENSITY, 1);
! 	return (0);
  }
  
  /*
--- 636,673 ----
  		 */
  		timeout(wakeup,(caddr_t) &tms->tms_type,240 * hz);
  		sleep((caddr_t) &tms->tms_type,PSWP+1);
+ 		untimeout(wakeup, &tms->tms_type);
  		}
! 	if	(!(tms->Tflags & _ONLINE))
  		{
! oops:		tms->Tflags = 0;
  		sc->sc_drives[unit] = NULL;
  		return(ENXIO);  /* Didn't go online */
  		}
! /*
!  * Get the unit characteristics (GTUNT).  This 1) Verifies the drive
!  * is really still online and 2) Retrieves information about the drive
!  * such as density choices, cache presence, etc.
! */
! 	tms->tms_flags = 0;
! 	tms->Tflags = _ONLINE | _INUSE;		/* Clear all other flags */
  	tmscpcommand(dev, TMS_SENSE, 1);
! 	if	(!(tms->Tflags & _ONLINE))
  		goto oops;
! 
! /*
!  * Next issue a reposition NOP by spacing forward 0 records.  This returns
!  * the current position (so we can tell if we're at BOT or not) and also 
!  * clears any serious exceptions outstanding.
! */
! 	tmscpcommand(dev, TMS_CSE, 1);
! 
! /*
!  * Now go set the density - the lower level routines set the density if 
!  * the drive is at BOT.
! */
  	tmscpcommand(dev, TMS_SETDENSITY, 1);
! 	return(0);
  }
  
  /*
***************
*** 729,780 ****
   * If tape was open for writing or last operation was
   * a write, then write two EOF's and backspace over the last one.
   * Unless this is a non-rewinding special file, rewind the tape.
!  *
!  * NOTE:
!  *	We want to be sure that any serious exception is cleared on the
!  *	close. A Clear Serious Exception (CSE) modifier is always done on
!  *	the rewind command.  For the non-rewind case we check to see if the
!  *	"serex" field is set in the softc struct; if it is then issue a noop
!  *	command with the CSE modifier.
!  * Make the tape available to others, by clearing openf flag.
!  */
  tmscpclose(dev, flag)
  	register dev_t dev;
  	register flag;
! {
  	struct tmscp_softc *sc;
  	register struct tms_info *tms;
  	int unit = TMSUNIT(dev);
  
- #ifdef TMSCP_DEBUG
- 	printd("tmscpclose: %d,%d\n", TMSCTLR(dev), unit);
- 	if(tmscpdebug)delay(10000L);
- #endif
  	sc = &tmscp_softc[TMSCTLR(dev)];
  	tms = sc->sc_drives[unit];
! 	if (flag == FWRITE || (flag&FWRITE) && tms->tms_lastiow)
  		{
! 		/*	   device, command, count */
! 		tmscpcommand (dev, TMS_WRITM, 1);
! 		tmscpcommand (dev, TMS_WRITM, 1);
! 		tmscpcommand (dev, TMS_BSR, 1);
! 		}
! 	if ((minor(dev)&T_NOREWIND) == 0)
! 		/*
! 		 * Don't hang waiting for rewind complete.
! 		 */
! 		tmscpcommand(dev, TMS_REW, 0);
! 	else
! 		if (tms->tms_serex)
  			{
! #ifdef TMSCP_DEBUG
! 			printd("tmscpclose: clearing serex\n");
! 			if (tmscpdebug)delay(10000L);
! #endif
! 			tmscpcommand(dev, TMS_CSE, 1);
  			}
! 	tms->tms_openf = 0;
! }
  
  /*
   * Execute a command on the tape drive a specified number of times.
--- 676,723 ----
   * If tape was open for writing or last operation was
   * a write, then write two EOF's and backspace over the last one.
   * Unless this is a non-rewinding special file, rewind the tape.
! */
  tmscpclose(dev, flag)
  	register dev_t dev;
  	register flag;
! 	{
  	struct tmscp_softc *sc;
  	register struct tms_info *tms;
  	int unit = TMSUNIT(dev);
  
  	sc = &tmscp_softc[TMSCTLR(dev)];
  	tms = sc->sc_drives[unit];
! 
! 	if	((tms->Tflags & _CACHE_ON) && (tms->Tflags & _CACHE_WRITTEN))
  		{
! /*
!  * A misbehaving application has closed the device without flushing 
!  * the enabled cache by issuing a MTFLUSH - we'll do it for it.
! */
! 		tmscpcommand(dev, TMS_FLUSH, 1);
! 		if	(tms->tms_status != M_ST_SUCC)
  			{
! /*
!  * This is BAD news - the flush didn't work.  The drive is in a serious
!  * exception state, leave that alone for the non-rewind case so that further
!  * operations fail.  About all that can be done now is log the error.
! */
! 			log(LOG_INFO, "tms%d,%d flush fail\n", 
! 					TMSCTLR(dev), unit);
! 			tms->Tflags &= ~_CACHE_WRITTEN;
  			}
! 		}
! 	tms->tms_flags &= ~MTF_CSE;
! 	if	(tms->Tflags & _WRITTEN)
! 		tms_wrteof(dev, tms);
! 	tms->Tflags &= ~(_WRITTEN | _BUFMARK |_INUSE);
! 	if	((dev & T_NOREWIND) == 0)
! 		{
! 		tmscpcommand(dev, TMS_REW, 0);
! 		tms->Tflags &= ~(_LOST | _CLSEREX | _SEREX);
! 		}
! 	return(0);
! 	}
  
  /*
   * Execute a command on the tape drive a specified number of times.
***************
*** 798,809 ****
  	s = spl5();
  	while (bp->b_flags&B_BUSY)
  		{
- 		/*
- 		 * This special check is because B_BUSY never
- 		 * gets cleared in the non-waiting rewind case.
- 		 */
- 		if (bp->b_bcount == 0 && (bp->b_flags&B_DONE))
- 			break;
  		bp->b_flags |= B_WANTED;
  		sleep((caddr_t)bp, PRIBIO);
  		}
--- 741,746 ----
***************
*** 820,831 ****
  	bp->b_resid = com;
  	bp->b_blkno = 0;
  	tmscpstrategy(bp);
! 	/*
! 	 * In case of rewind from close, don't wait.
! 	 * This is the only case where count can be 0.
! 	 */
! 	if (count == 0)
! 		return;
  	iowait(bp);
  	if (bp->b_flags&B_WANTED)
  		wakeup((caddr_t)bp);
--- 757,766 ----
  	bp->b_resid = com;
  	bp->b_blkno = 0;
  	tmscpstrategy(bp);
! /*
!  * It is safe to wait here because the rewind done on a close specifies
!  * the modifier M_MD_IMMED which causes an immediate return.
! */
  	iowait(bp);
  	if (bp->b_flags&B_WANTED)
  		wakeup((caddr_t)bp);
***************
*** 874,881 ****
  	register struct tmscp_softc *sc;
  {
  	register struct mscp *mp = NULL;
! 	struct tmscpca *cp;
! 	register int i;
  	int	s;
  	segm seg5;
  
--- 809,816 ----
  	register struct tmscp_softc *sc;
  {
  	register struct mscp *mp = NULL;
! 	register struct tmscpca *cp;
! 	int	i;
  	int	s;
  	segm seg5;
  
***************
*** 888,902 ****
  	 * until some outstanding commands complete.
  	 */
  	i = sc->sc_lastcmd;
! #ifdef TMSCP_DEBUG
! 	printd10("tmscpgetcp: %d credits remain\n", sc->sc_credits);
! #endif
! 	if(((cp->ca_cmddsc[i].hsh&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) &&
! 	  (sc->sc_credits >= 2))
  		{
  		sc->sc_credits--;       /* This commits to issuing a command */
  		cp->ca_cmddsc[i].hsh &= ~TMSCP_INT;
  		mp = &sc->sc_com->tmscp_cmd[i];
  		mp->mscp_unit = mp->mscp_modifier = 0;
  		mp->mscp_opcode = mp->mscp_flags = 0;
  		mp->mscp_bytecnt = 0;
--- 823,836 ----
  	 * until some outstanding commands complete.
  	 */
  	i = sc->sc_lastcmd;
! 	if	(((cp->ca_cmddsc[i].hsh&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) &&
! 		  (sc->sc_credits >= 2))
  		{
  		sc->sc_credits--;       /* This commits to issuing a command */
  		cp->ca_cmddsc[i].hsh &= ~TMSCP_INT;
  		mp = &sc->sc_com->tmscp_cmd[i];
+ 		mp->mscp_cmdref = 0;
+ 		mp->mscp_mediaid = 0;
  		mp->mscp_unit = mp->mscp_modifier = 0;
  		mp->mscp_opcode = mp->mscp_flags = 0;
  		mp->mscp_bytecnt = 0;
***************
*** 933,943 ****
  
  	while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
  		{
! #ifdef TMSCP_DEBUG
! 		printd("tkini: tmscpsa = 0%o\n",tmscpaddr->tmscpsa);
! 		delay(100000L);
! #endif
! 		if(tmscpaddr->tmscpsa & TMSCP_ERR)
  			return(0);	/* CHECK */
  		}
  	tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
--- 867,873 ----
  
  	while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
  		{
! 		if	(tmscpaddr->tmscpsa & TMSCP_ERR)
  			return(0);	/* CHECK */
  		}
  	tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
***************
*** 967,982 ****
       saveseg5(seg5);		/* save just once at top */
       for(;;)
  	{
! 	if ((dp = sc->sc_ctab.b_actf) == NULL)
  		{
! 		/*
! 		 * Release unneeded UBA resources and return
! 		 * (drive was inactive)
! 		 */
  		sc->sc_ctab.b_active = 0;
  		break;
  		}
! 	if ((bp = dp->b_actf) == NULL)
  		{
  		/*
  		 * No more requests for this drive, remove
--- 897,909 ----
       saveseg5(seg5);		/* save just once at top */
       for(;;)
  	{
! 	if	((dp = sc->sc_ctab.b_actf) == NULL)
  		{
! 		/* (drive was inactive) */
  		sc->sc_ctab.b_active = 0;
  		break;
  		}
! 	if	((bp = dp->b_actf) == NULL)
  		{
  		/*
  		 * No more requests for this drive, remove
***************
*** 985,1015 ****
  		 */
  		dp->b_active = 0;
  		sc->sc_ctab.b_actf = dp->b_forw;
! 		continue;		/* Need to check for loop */
  		}
  	sc->sc_ctab.b_active++;
  	unit = TMSUNIT(bp->b_dev);
  	tmscpaddr = (struct tmscpdevice *)sc->sc_addr;
  	tms = sc->sc_drives[unit];
! 	if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN)
  		{
! 		tprintf(tms->tms_ttyp,
! 		    "tms%d,%d: hard error bn%ld\n", sc->sc_unit, unit,
! 		    bp->b_blkno);
! 		log(TMS_PRI, "tms%d,%d: sa 0%o state %d\n", sc->sc_unit,
  			unit, tmscpaddr->tmscpsa, sc->sc_state);
  		(void)tkini(sc);
  		/* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */
  		break;
  		}
! 	/*
! 	 * Default is that last command was NOT a write command;
! 	 * if a write command is done it will be detected in tmscprsp.
! 	 */
! 	tms->tms_lastiow = 0;
! 	if (tms->tms_online == -1)
! 		{        /* not online */
! 		if ((mp = tmscpgetcp(sc)) == NULL)
  			break;
  		mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
  		mp->mscp_opcode = M_OP_ONLIN;
--- 912,935 ----
  		 */
  		dp->b_active = 0;
  		sc->sc_ctab.b_actf = dp->b_forw;
! 		continue;
  		}
  	sc->sc_ctab.b_active++;
  	unit = TMSUNIT(bp->b_dev);
  	tmscpaddr = (struct tmscpdevice *)sc->sc_addr;
  	tms = sc->sc_drives[unit];
! 	if	((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN)
  		{
! 		log(LOG_INFO, "tms%d,%d: sa %x state %d\n", sc->sc_unit,
  			unit, tmscpaddr->tmscpsa, sc->sc_state);
  		(void)tkini(sc);
  		/* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */
  		break;
  		}
! 
! 	if	(!(tms->Tflags & _ONLINE))
! 		{
! 		if	((mp = tmscpgetcp(sc)) == NULL)
  			break;
  		mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
  		mp->mscp_opcode = M_OP_ONLIN;
***************
*** 1017,1030 ****
  		dp->b_active = 2;
  		sc->sc_ctab.b_actf = dp->b_forw; /* remove from controller q */
  		((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT;
! 		if (tmscpaddr->tmscpsa&TMSCP_ERR)
! 			printf(tmscpfatalerr, sc->sc_unit,
  					TMSUNIT(bp->b_dev), tmscpaddr->tmscpsa);
  		restorseg5(seg5);
  		i = tmscpaddr->tmscpip;
  		continue;
  		}
! 	if ((mp = tmscpgetcp(sc)) == NULL)
  		break;
  	mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
  	mp->mscp_cmdref = (u_short)bp;		/* pointer to get back */
--- 937,950 ----
  		dp->b_active = 2;
  		sc->sc_ctab.b_actf = dp->b_forw; /* remove from controller q */
  		((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT;
! 		if	(tmscpaddr->tmscpsa&TMSCP_ERR)
! 			log(LOG_INFO, tmscpfatalerr, sc->sc_unit,
  					TMSUNIT(bp->b_dev), tmscpaddr->tmscpsa);
  		restorseg5(seg5);
  		i = tmscpaddr->tmscpip;
  		continue;
  		}
! 	if	((mp = tmscpgetcp(sc)) == NULL)
  		break;
  	mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
  	mp->mscp_cmdref = (u_short)bp;		/* pointer to get back */
***************
*** 1034,1044 ****
  	 * tmscp command;  by doing a switch on the "b_resid" field where
  	 * the command mneumonic is stored.
  	 */
! 	if (bp == &sc->sc_cmdbuf)
  		{
- #ifdef TMSCP_DEBUG
- 		printd("tmsstart: doing ioctl cmd %d\n", bp->b_resid);
- #endif
  		/*
  		 * The reccnt and tmkcnt fields are set to zero by the getcp
  		 * routine (as bytecnt and buffer fields).  Thus reccnt and
--- 954,961 ----
  	 * tmscp command;  by doing a switch on the "b_resid" field where
  	 * the command mneumonic is stored.
  	 */
! 	if	(bp == &sc->sc_cmdbuf)
  		{
  		/*
  		 * The reccnt and tmkcnt fields are set to zero by the getcp
  		 * routine (as bytecnt and buffer fields).  Thus reccnt and
***************
*** 1048,1135 ****
  		switch ((int)bp->b_resid) {
  
  		case TMS_WRITM:
! 			mp->mscp_opcode = M_OP_WRITM;
  			break;
  		case TMS_FSF:
! 			mp->mscp_opcode = M_OP_REPOS;
! 			mp->mscp_tmkcnt = bp->b_bcount;
  			break;
  		case TMS_BSF:
! 			mp->mscp_opcode = M_OP_REPOS;
! 			mp->mscp_modifier = M_MD_REVRS;
! 			mp->mscp_tmkcnt = bp->b_bcount;
  			break;
  		case TMS_FSR:
! 			mp->mscp_opcode = M_OP_REPOS;
! 			mp->mscp_modifier = M_MD_OBJCT;
! 			mp->mscp_reccnt = bp->b_bcount;
  			break;
  		case TMS_BSR:
! 			mp->mscp_opcode = M_OP_REPOS;
! 			mp->mscp_modifier = M_MD_REVRS | M_MD_OBJCT;
! 			mp->mscp_reccnt = bp->b_bcount;
  			break;
- 		/*
- 		 * Clear serious exception is done for Rewind & Available cmds
- 		 */
  		case TMS_REW:
! 			mp->mscp_opcode = M_OP_REPOS;
! 			mp->mscp_modifier = M_MD_REWND | M_MD_CLSEX;
! 			if (bp->b_bcount == 0)
! 				mp->mscp_modifier |= M_MD_IMMED;
! 			tms->tms_serex = 0;
  			break;
  		case TMS_OFFL:
! 			mp->mscp_opcode = M_OP_AVAIL;
! 			mp->mscp_modifier = M_MD_UNLOD | M_MD_CLSEX;
! 			tms->tms_serex = 0;
  			break;
  		case TMS_SENSE:
  			mp->mscp_opcode = M_OP_GTUNT;
  			break;
  		case TMS_CACHE:
- 			mp->mscp_opcode = M_OP_STUNT;
  			tms->tms_unitflgs |= M_UF_WBKNV;
! 			mp->mscp_unitflgs = tms->tms_unitflgs;
! 			mp->mscp_format = tms->tms_format;
! 			/* default device dependant parameters */
! 			mp->mscp_mediaid = 0;
  			break;
  		case TMS_NOCACHE:
! 			mp->mscp_opcode = M_OP_STUNT;
! 			tms->tms_unitflgs &= ~(M_UF_WBKNV);
! 			mp->mscp_unitflgs = tms->tms_unitflgs;
! 			mp->mscp_format = tms->tms_format;
! 			/* default device dependant parameters */
! 			mp->mscp_mediaid = 0;
  			break;
  		case TMS_CSE:
! 			/*
! 			 * This is a no-op command. It performs a 
! 			 * clear serious exception only.  (Done on a
! 			 * non-rewinding close after a serious exception.)
! 			 */
! 			mp->mscp_opcode = M_OP_REPOS;
! 			mp->mscp_modifier = M_MD_CLSEX;
! 			tms->tms_serex = 0;
! 			tms->tms_clserex = 1;
  			break;
  		case TMS_SETDENSITY:
! 			/*
! 			 * Set the unit density
! 			 */
! 			mp->mscp_opcode = M_OP_STUNT;
! 			mp->mscp_unitflgs = tms->tms_unitflgs;
! 			mp->mscp_mediaid = 0;	/* default device dependant parameters */
! 			mp->mscp_format = Dmatrix[TMSDENS(bp->b_dev)][tms->tms_fmtmenu & FMTMASK];
! #ifdef	TMSCP_DEBUG
! 			printd("b_dev: 0%o fmtmenu: 0%o format: 0%o\n", bp->b_dev, tms->tms_fmtmenu, mp->mscp_format);
! 			delay(4000000L);
! #endif
! 			tms->tms_format = mp->mscp_format;
  			break;
  		default:
! 			printf("tms%d,%d bad ioctl\n",sc->sc_unit,mp->mscp_unit);
  			/* Need a no-op. Reposition no amount */
  			mp->mscp_opcode = M_OP_REPOS;
  			break;
--- 965,1022 ----
  		switch ((int)bp->b_resid) {
  
  		case TMS_WRITM:
! 			tms_wtm_st(mp, sc, 0);
  			break;
  		case TMS_FSF:
! 			tms_repos_st(mp, sc, 0);
  			break;
  		case TMS_BSF:
! 			tms_repos_st(mp, sc, M_MD_REVRS);
  			break;
  		case TMS_FSR:
! 			tms_reposrec_st(mp, sc, M_MD_OBJCT);
  			break;
  		case TMS_BSR:
! 			tms_reposrec_st(mp, sc, M_MD_OBJCT | M_MD_REVRS);
  			break;
  		case TMS_REW:
! 			if	(bp->b_bcount)
! 				i = M_MD_REWND;
! 			else
! 				i = M_MD_REWND | M_MD_IMMED;
! 			tms_repos_st(mp, sc, i);
  			break;
  		case TMS_OFFL:
! 			tms_avail_st(mp, sc, M_MD_UNLOD);
  			break;
  		case TMS_SENSE:
  			mp->mscp_opcode = M_OP_GTUNT;
  			break;
+ 		case TMS_FLUSH:
+ 			mp->mscp_opcode = M_OP_FLUSH;
+ 			break;
  		case TMS_CACHE:
  			tms->tms_unitflgs |= M_UF_WBKNV;
! 			tms->tms_unitflgs &= ~M_UF_SCCHH;
! 			tms->Tflags |= _CACHE_ON;
! 			tms_stunt_st(mp, sc, 0);
  			break;
  		case TMS_NOCACHE:
! 			tms->tms_unitflgs &= ~M_UF_WBKNV;
! 			tms->tms_unitflgs |= M_UF_SCCHH;
! 			tms->Tflags &= ~_CACHE_ON;
! 			tms_stunt_st(mp, sc, 0);
  			break;
  		case TMS_CSE:
! 			bp->b_bcount = 0;	/* 0 objects to skip */
! 			tms_repos_st(mp, sc, M_MD_OBJCT);
  			break;
  		case TMS_SETDENSITY:
! 			tms->tms_format = Dmatrix[TMSDENS(bp->b_dev)][tms->tms_fmtmenu & FMTMASK];
! 			tms_stunt_st(mp, sc, 0);
  			break;
  		default:
! 			log(LOG_INFO, "tms ioctl %x\n", bp->b_resid);
  			/* Need a no-op. Reposition no amount */
  			mp->mscp_opcode = M_OP_REPOS;
  			break;
***************
*** 1142,1157 ****
  		mp->mscp_buffer_l = (u_short) bp->b_un.b_addr;
  		mp->mscp_buffer_h = bp->b_xmem;
  		}
! 	if (tms->tms_serex == 2)			/* if tape mark read */
  		{
! 		mp->mscp_modifier |= M_MD_CLSEX;	/*  clear serious exc */
! 		tms->tms_serex = 0;
  		}
  	((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT;
- #ifdef TMSCP_DEBUG
- 	printd("tmsstart: opcode 0%o mod %o unit %d cnt %d\n",mp->mscp_opcode,mp->mscp_modifier,mp->mscp_unit,mp->mscp_bytecnt);
- 	if(tmscpdebug)delay(100000L);
- #endif
  	i = tmscpaddr->tmscpip;              /* initiate polling */
  	dp->b_qsize++;
  	/*
--- 1029,1045 ----
  		mp->mscp_buffer_l = (u_short) bp->b_un.b_addr;
  		mp->mscp_buffer_h = bp->b_xmem;
  		}
! 
! 	if	((tms->Tflags & _CACHE_ON) && (mp->mscp_opcode == M_OP_WRITE))
! 		tms->Tflags |= _CACHE_WRITTEN;
! 	if	((tms->Tflags & _BUFMARK) && (mp->mscp_opcode == M_OP_READ) &&
! 		 (tms->Tflags & _CLSEREX))
  		{
! 		tms->Tflags &= ~(_BUFMARK | _CLSEREX);
! 		mp->mscp_modifier |= M_MD_CLSEX;
  		}
+ 
  	((Trl *)mp->mscp_dscptr)->hsh |= TMSCP_OWN|TMSCP_INT;
  	i = tmscpaddr->tmscpip;              /* initiate polling */
  	dp->b_qsize++;
  	/*
***************
*** 1175,1181 ****
  	dp->av_back = bp;
  	if (tmscpaddr->tmscpsa&TMSCP_ERR)
  		{
! 		printf(tmscpfatalerr,sc->sc_unit, 
  			mp->mscp_unit, tmscpaddr->tmscpsa);
  		(void)tkini(sc);
  		break;
--- 1063,1069 ----
  	dp->av_back = bp;
  	if (tmscpaddr->tmscpsa&TMSCP_ERR)
  		{
! 		log(LOG_INFO, tmscpfatalerr,sc->sc_unit, 
  			mp->mscp_unit, tmscpaddr->tmscpsa);
  		(void)tkini(sc);
  		break;
***************
*** 1209,1250 ****
  	register struct mscp *mp;
  	register struct tms_info *tms;
  	struct buf *dp, *bp;
! 	int st;
  
  	mp = &sc->sc_com->tmscp_rsp[i];
  	mp->mscp_header.tmscp_msglen = mscp_msglen;
  	sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf;  /* low 4 bits */
! 	if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10)	/* Check */
  		return;
! #ifdef TMSCP_DEBUG
! 	printd("tmscprsp, opcode 0%o status 0%o\n",mp->mscp_opcode,mp->mscp_status&M_ST_MASK);
! 	printd("  SEG5: 0%o sc: 0%o mp: 0%o i: %d\n",*KDSA5, sc, mp, i);
! #endif	
  	/*
  	 * If it's an error log message (datagram),
  	 * pass it on for more extensive processing.
  	 */
! 	if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10)
! 		{	/* check */
  		tmserror(sc->sc_unit, (struct mslg *)mp);
  		return;
  		}
! 	st = mp->mscp_status&M_ST_MASK;
  	/*
! 	 * The controller interrupts as drive 0.
  	 * This means that you must check for controller interrupts
! 	 * before you check to see if there is a drive 0.
  	 */
! 	if((M_OP_STCON|M_OP_END) == mp->mscp_opcode)
  		{
! 		if (st == M_ST_SUCC)
! 			{
! #ifdef TMSCP_DEBUG
! 			printd("ctlr has %d credits\n", mp->mscp_header.tmscp_credits & 0xf);
! 			printd("ctlr timeout = %d\n", mp->mscp_cnttmo);
! #endif
  			sc->sc_state = S_RUN;
- 			}
  		else
  			sc->sc_state = S_IDLE;
  		sc->sc_ctab.b_active = 0;
--- 1097,1137 ----
  	register struct mscp *mp;
  	register struct tms_info *tms;
  	struct buf *dp, *bp;
! 	int	em_status, em_endcode;
  
  	mp = &sc->sc_com->tmscp_rsp[i];
  	mp->mscp_header.tmscp_msglen = mscp_msglen;
  	sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf;  /* low 4 bits */
! 	if	((mp->mscp_header.tmscp_credits & 0xf0) > 0x10)	/* Check */
  		return;
! 
  	/*
  	 * If it's an error log message (datagram),
  	 * pass it on for more extensive processing.
  	 */
! 	if	((mp->mscp_header.tmscp_credits & 0xf0) == 0x10)
! 		{
  		tmserror(sc->sc_unit, (struct mslg *)mp);
  		return;
  		}
! #ifdef	TMSDEBUG
! 	if	(tmscpprintf & 0x4)
! 		log(LOG_INFO, "tms%d,%d: op %x st %x\n", sc->sc_unit,
! 			mp->mscp_unit,mp->mscp_opcode,
! 			mp->mscp_status & M_ST_MASK);
! #endif
! 
! 	em_status = mp->mscp_status&M_ST_MASK;
! 	em_endcode = mp->mscp_endcode & ~M_OP_END;
  	/*
! 	 * The controller interrupts as any drive.
  	 * This means that you must check for controller interrupts
! 	 * before drive responses.
  	 */
! 	if	(em_endcode == M_OP_STCON)
  		{
! 		if	(em_status == M_ST_SUCC)
  			sc->sc_state = S_RUN;
  		else
  			sc->sc_state = S_IDLE;
  		sc->sc_ctab.b_active = 0;
***************
*** 1251,1313 ****
  		wakeup((caddr_t)&sc->sc_ctab);
  		return;
  		}
! 	if (mp->mscp_unit >= 4)
  		return;
  	tms = sc->sc_drives[mp->mscp_unit];
! 	if (!tms)		/* unopened unit coming online - ignore it */
  		return;
! 	/*
! 	 * Save endcode, endflags, and status for mtioctl get unit status.
! 	 * NOTE: Don't do this on Clear serious exception (reposition no-op);
! 	 *    which is done on close since this would
! 	 *    overwrite the real status we want.
! 	 */
! 	if (tms->tms_clserex != 1)
! 		{
! 		tms->tms_endcode = mp->mscp_opcode;
! 		tms->tms_flags = mp->mscp_flags;
! 		tms->tms_status = st;
! 		}
! 	else tms->tms_clserex = 0;
  
! 	switch (mp->mscp_opcode) {
! 	case M_OP_ONLIN|M_OP_END:
! 		tms->tms_type = mp->mscp_mediaid;
! 		dp = &tms->tms_dtab;
! 		if (st == M_ST_SUCC)
  			{
  			/*
  			 * Link the drive onto the controller queue
  			 */
  			dp->b_forw = NULL;
! 			if (sc->sc_ctab.b_actf == NULL)
  				sc->sc_ctab.b_actf = dp;
  			else
  				sc->sc_ctab.b_actl->b_forw = dp;
  			sc->sc_ctab.b_actl = dp;
- 			tms->tms_online = 1;       /* mark it online */
- 			tms->tms_dsize=(daddr_t)mp->mscp_maxwrt;
- 			/* 
- 			 * This define decodes the Media type identifier
- 			 */
- #ifdef TMSCP_DEBUG
- 			printd("tmscprsp: %d,%d online mediaid 0x%lx format 0x%x\n",
- 				sc->sc_unit, mp->mscp_unit, mp->mscp_mediaid,
- 				mp->mscp_format);
- #endif				
  			dp->b_active = 1;
! 			}	/* end if st == M_ST_SUCC */
  		else 
  			{
! 			if (bp = dp->b_actf)
! 				tprintf(tms->tms_ttyp,
! 				    "tms%d,%d: hard error bn%ld: OFFLINE\n",
! 				    sc->sc_unit, mp->mscp_unit, bp->b_blkno);
! 			else
! 				tprintf(tms->tms_ttyp,
! 				    "tms%d,%d: hard error: OFFLINE\n", 
! 				    sc->sc_unit, mp->mscp_unit);
! 			while (bp = dp->b_actf)
  				{
  				dp->b_actf = bp->av_forw;
  				bp->b_flags |= B_ERROR;
--- 1138,1180 ----
  		wakeup((caddr_t)&sc->sc_ctab);
  		return;
  		}
! 	if	(mp->mscp_unit >= 4)
  		return;
  	tms = sc->sc_drives[mp->mscp_unit];
! 	if	(!tms)		/* unopened unit coming online - ignore it */
  		return;
! 	dp = &tms->tms_dtab;
  
! 	switch (em_endcode) {
! 	case	M_OP_ONLIN:
! 		if	(em_status == M_ST_SUCC || em_status == M_ST_WRTPR)
  			{
+ 			tms->Tflags |= _ONLINE;
+ 			tms->Tflags &= ~_CACHE_WRITTEN;
+ /*
+  * Normally this is done in the 'tms_check_ret' routine.  The ONLIN case is
+  * special (well, ok - weird) in that it was never put on the I/O wait queue.
+  * Thus we need to do this here.
+ */
+ 			tms->tms_endcode = em_endcode;
+ 			tms->tms_status = em_status;
+ 			tms->tms_type = mp->mscp_mediaid;
+ 			tms->tms_unitflgs = mp->mscp_unitflgs;
+ 			tms->tms_format = mp->mscp_format;
  			/*
  			 * Link the drive onto the controller queue
  			 */
  			dp->b_forw = NULL;
! 			if	(sc->sc_ctab.b_actf == NULL)
  				sc->sc_ctab.b_actf = dp;
  			else
  				sc->sc_ctab.b_actl->b_forw = dp;
  			sc->sc_ctab.b_actl = dp;
  			dp->b_active = 1;
! 			}
  		else 
  			{
! 			while	(bp = dp->b_actf)
  				{
  				dp->b_actf = bp->av_forw;
  				bp->b_flags |= B_ERROR;
***************
*** 1314,1460 ****
  				iodone(bp);
  				}
  			}
! 		if(mp->mscp_cmdref!=NULL)
! 			/* Seems to get lost sometimes in uda */
  			wakeup((caddr_t)mp->mscp_cmdref);
! 		break;
  	/*
  	 * The AVAILABLE ATTENTION message occurs when the
! 	 * unit becomes available after loading,
! 	 * marking the unit offline (tms_online = -1) will force an
  	 * online command prior to using the unit.
  	 */
! 	case M_OP_AVATN:
! 		tms->tms_online = -1;
! 		tms->tms_type = mp->mscp_mediaid;
! 		break;
! 	case M_OP_END:
! 		/*
! 		 * An endcode without an opcode (0200) is an invalid command.
! 		 * The mscp specification states that this would be a protocol
! 		 * type error, such as illegal opcodes. The mscp spec. also
! 		 * states that parameter error type of invalid commands should
! 		 * return the normal end message for the command. This does not appear
! 		 * to be the case. An invalid logical block number returned an endcode
! 		 * of 0200 instead of the 0241 (read) that was expected.
! 		 */
! 			
! 		printf("tms%d,%d: invalid cmd endcode = %o status=%o\n",
! 			sc->sc_unit, mp->mscp_unit, mp->mscp_opcode, st);
! common:	/* GTUNT finishes up thru here too */
! 		bp = (struct buf *)mp->mscp_cmdref;
! 		/*
! 		 * Unlink buffer from I/O wait queue.
! 		 * And signal iodone, so the higher level command can exit!
! 		 *
! 		 */
! 		bp->av_back->av_forw = bp->av_forw;
! 		bp->av_forw->av_back = bp->av_back;
! 		dp = &tms->tms_dtab;
! 		dp->b_qsize--;
! 		iodone(bp);
! 		break;
! 	case M_OP_WRITE|M_OP_END:
! 		/* mark the last io op as a write */
! 		tms->tms_lastiow = 1;
! 	case M_OP_READ|M_OP_END:
! 	case M_OP_WRITM|M_OP_END:
! 	case M_OP_REPOS|M_OP_END:
! 	case M_OP_STUNT|M_OP_END:
! 	/*
! 	 * The AVAILABLE message occurs when the mt ioctl "rewoffl" is
! 	 * issued.  For the ioctl, "rewoffl", a tmscp AVAILABLE command is
! 	 * done with the UNLOAD modifier.  This performs a rewind, followed
! 	 * by marking the unit offline.  So mark the unit offline
! 	 * software wise as well (tms->tms_online = -1 and tms_open = 0).
! 	 */
! 	case M_OP_AVAIL|M_OP_END:
! #ifdef TMSCP_DEBUG
! 		printd("tmscprsp: position = %u,%u\n", mp->mscp_lbn_h,mp->mscp_lbn_l);
! #endif
! 		bp = (struct buf *)mp->mscp_cmdref;
! 		/*
! 		 * Unlink buffer from I/O wait queue.
! 		 */
! 		bp->av_back->av_forw = bp->av_forw;
! 		bp->av_forw->av_back = bp->av_back;
! 		dp = &tms->tms_dtab;
! 		dp->b_qsize--;
! 		if (st == M_ST_OFFLN || st == M_ST_AVLBL)
! 			{
! 			tms->tms_online = -1;       /* mark unit offline */
! 			tms->tms_openf = 0;
! 			tms->tms_type = mp->mscp_mediaid;
! 			/*
! 			 * Link the buffer onto the front of the drive queue
! 			 */
! 			if ((bp->av_forw = dp->b_actf) == 0)
! 				dp->b_actl = bp;
! 			dp->b_actf = bp;
! 			/*
! 			 * Link the drive onto the controller queue
! 			 */
! 			if (dp->b_active == 0)
! 				{
! 				dp->b_forw = NULL;
! 				if (sc->sc_ctab.b_actf == NULL)
! 					sc->sc_ctab.b_actf = dp;
! 				else
! 					sc->sc_ctab.b_actl->b_forw = dp;
! 				sc->sc_ctab.b_actl = dp;
! 				dp->b_active = 1;
! 				}
! 			return;
! 			}
! 		if (st != M_ST_SUCC)
! 			{
! 			if (mp->mscp_flags & M_EF_SEREX)
! 				tms->tms_serex = 1;
! 			if (st != M_ST_TAPEM)
! 				{
! 				tprintf(tms->tms_ttyp,
! 				"tms%d,%d: hard err bn%ld status:0%o flags:0%o\n",
! 				    sc->sc_unit, mp->mscp_unit, bp->b_blkno,
! 				    mp->mscp_status, mp->mscp_flags);
! 				bp->b_flags |= B_ERROR;
! 				}
! 			else
! 				/* Hit a tape mark - Set serex flag to
! 				 * a special value so we can clear the
! 				 * serious exception on the next command.
! 				 */
! 				tms->tms_serex = 2;
! 			}
! 		/*
! 		 * The tmscp spec states that controllers do not have to
! 		 * report the number of records or files skipped.  So on
! 		 * reposition commands we go strictly by cmd status.
! 		 */
! 		if (mp->mscp_opcode != (M_OP_REPOS|M_OP_END))
! 			bp->b_resid = bp->b_bcount - mp->mscp_bytecnt;
! 		else
! 			bp->b_resid = 0;
! 		tms->tms_resid = bp->b_resid;
! 		iodone(bp);
! 		break;
! 
! 	case M_OP_GTUNT|M_OP_END:
! #ifdef TMSCP_DEBUG
! 		printd("tmscprsp: GTUNT end packet status = 0%o\n",st);
! 		printd("tmscprsp: %d,%d mediaid 0x%lx 0x%lx 0x%lx format=%d speed = %d\n",
! 		    sc->sc_unit,mp->mscp_unit, mp->mscp_mediaid
! 		    ,mp->mscp_unitid.val[0]
! 		    ,mp->mscp_unitid.val[1]
! 		    ,mp->mscp_format, mp->mscp_speed);
! #endif
! 		tms->tms_type = mp->mscp_mediaid;
! 		tms->tms_fmtmenu = mp->mscp_fmtmenu;
! 		tms->tms_unitflgs = mp->mscp_unitflgs;
! 		goto common;	/* need to dequeue buffer and do iodone() */
! 
  	default:
! 		printf("tms%d,%d unknown packet\n", sc->sc_unit,mp->mscp_unit);
! 		tmserror(sc->sc_unit, (struct mslg *)mp);
  	}	/* end switch mp->mscp_opcode */
  }
  
--- 1181,1229 ----
  				iodone(bp);
  				}
  			}
! 		if	(mp->mscp_cmdref)
  			wakeup((caddr_t)mp->mscp_cmdref);
! 		return;
  	/*
  	 * The AVAILABLE ATTENTION message occurs when the
! 	 * unit becomes available after loading.
! 	 * Marking the unit offline will force an
  	 * online command prior to using the unit.
  	 */
! 	case	M_OP_AVATN:
! 		tms->Tflags &= ~_ONLINE;
! 		return;
! 	case 0:
! 		log(LOG_INFO, "tms%d,%d: inv end=%x st=%x\n",
! 			sc->sc_unit, mp->mscp_unit, em_endcode, em_status);
! 		tms_iodone(mp, tms);
! 		return;
! 	case	M_OP_WRITE:
! 	case	M_OP_READ:
! 		tms_rw_em(mp, sc);
! 		return;
! 	case	M_OP_WRITM:
! 		tms_wtm_em(mp, sc);
! 		return;
! 	case	M_OP_REPOS:
! 		tms_repos_em(mp, sc);
! 		return;
! 	case	M_OP_STUNT:
! 		tms_stunt_em(mp, sc);
! 		return;
! 	case	M_OP_AVAIL:
! 		tms_avail_em(mp, sc);
! 		return;
! 	case	M_OP_GTUNT:
! 		tms_gtunt_em(mp, sc);
! 		return;
! 	case	M_OP_FLUSH:
! 		tms_flush_em(mp, sc);
! 		return;
  	default:
! 		log(LOG_INFO, "tms%d,%d bad rsp: %x\n", sc->sc_unit,
! 			mp->mscp_unit, em_endcode);
! 		return;
  	}	/* end switch mp->mscp_opcode */
  }
  
***************
*** 1464,1470 ****
  
  tmscpstrategy (bp)
  	register struct buf *bp;
! {
  	register struct buf *dp;
  	register struct tmscp_softc *sc;
  	struct	tms_info *tms;
--- 1233,1239 ----
  
  tmscpstrategy (bp)
  	register struct buf *bp;
! 	{
  	register struct buf *dp;
  	register struct tmscp_softc *sc;
  	struct	tms_info *tms;
***************
*** 1473,1484 ****
  
  	sc = &tmscp_softc[ctlr];
  	tms = sc->sc_drives[TMSUNIT(bp->b_dev)];
! 	if (!tms || tms->tms_online != 1)
  		{
  		bp->b_flags |= B_ERROR;
  		iodone(bp);
  		return;
  		}
  	mapalloc(bp);
  	s = spl5();
  	/*
--- 1242,1265 ----
  
  	sc = &tmscp_softc[ctlr];
  	tms = sc->sc_drives[TMSUNIT(bp->b_dev)];
! 	if	(!tms || !(tms->Tflags & _ONLINE))
  		{
  		bp->b_flags |= B_ERROR;
  		iodone(bp);
  		return;
  		}
+ /*
+  * If we're at the end of the tape and no Clear Serious Exception has been
+  * done then return an error rather than reading off the end of the tape.
+ */
+ 	if	((tms->tms_flags & MTF_CSE) == 0 && (tms->tms_flags & MTF_EOM))
+ 		{
+ 		bp->b_resid = bp->b_bcount;
+ 		bp->b_error = ENOSPC;
+ 		bp->b_flags |= B_ERROR;
+ 		iodone(bp);
+ 		return;
+ 		}
  	mapalloc(bp);
  	s = spl5();
  	/*
***************
*** 1507,1657 ****
  	/*
  	 * If the controller is not active, start it.
  	 */
! 	if (sc->sc_ctab.b_active == 0)
! 		{
! #ifdef TMSCP_DEBUG
! 		printd10("tmscpstrategy: Controller not active, starting it\n");
! #endif
  		(void) tmsstart(sc);
- 		}
  	splx(s);
  	return;
- }
- 
- #ifdef	TMSCP_DUMP
- #define DBSIZE 16
- 
- tmsdump(dev)
- 	dev_t dev;
- {
- 	register struct tmscpdevice *tmscpaddr;
- 	register struct	tmscp_softc *sc;
- 	register struct	mscp	*mp;
- 	daddr_t bn, dumpsize;
- 	long paddr, maddr;
- 	int unit = TMSUNIT(dev), count, ctlr = TMSCTLR(dev);
- 	struct	ubmap *ubp;
- 	segm seg5;
- 
- 	if (ctlr >= NTMSCP)
- 		return (ENXIO);
- 	sc = &tmscp_softc[ctlr];
- 	tmscpaddr = sc->sc_addr;
- 	if (tmscpaddr == NULL)
- 		return(ENXIO);
- 
- 	paddr = _iomap(tmscp[sc->sc_unit]);
- 	if (ubmap) {
- 		ubp = UBMAP;
- 		ubp->ub_lo = loint(paddr);
- 		ubp->ub_hi = hiint(paddr);
  	}
- 	paddr += RINGBASE;
- 	saveseg5(seg5);
- 	mapseg5(tmscp[sc->sc_unit], MAPBUFDESC);
- 	mp = sc->sc_com->tmscp_rsp;
- 	sc->sc_com->tmscp_ca.ca_cmdint = sc->sc_com->tmscp_ca.ca_rspint = 0;
- 	bzero(mp, 2 * sizeof (*mp));
  
- 	tmscpaddr->tmscpip = 0;
- 	while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
- 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- 	tmscpaddr->tmscpsa = TMSCP_ERR;
- 	while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0)
- 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- 	tmscpaddr->tmscpsa = loint(paddr);
- 	while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0)
- 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- 	tmscpaddr->tmscpsa = hiint(paddr);
- 	while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0)
- 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
- 	tmscpaddr->tmscpsa = TMSCP_GO;
- 	
- 	tmsginit(sc, sc->sc_com->tmscp_ca.ca_rspdsc, mp, 0, 2, 0);
- 
- 	if (tmscpcmd(M_OP_STCON, unit, sc) == 0) {
- 		return(EFAULT);
- 	}
- 	sc->sc_com->tmscp_cmd[0].mscp_unit = unit;
- 	if (tmscpcmd(M_OP_ONLIN, unit, sc) == 0) {
- 		return(EFAULT);
- 	}
- 
- 	dumpsize = 8 * 1024L;	 /* XXX */
- 	ubp = &UBMAP[1];
- 	for (paddr = 0; dumpsize > 0; dumpsize -= count) {
- 		count = MIN(dumpsize, DBSIZE);
- 		bn = paddr >> PGSHIFT;
- 		maddr = paddr;
- 		if (ubmap) {
- 			ubp->ub_lo = loint(paddr);
- 			ubp->ub_hi = hiint(paddr);
- 			maddr = (u_int)(1 << 13);
- 		}
- 	/* write it to the tape */
- 	mp = &sc->sc_com->tmscp_rsp[1];
- 	mp->mscp_lbn_l = loint(bn);
- 	mp->mscp_lbn_h = hiint(bn);
- 	mp->mscp_bytecnt = count * NBPG;
- 	mp->mscp_buffer_l = loint(maddr);
- 	mp->mscp_buffer_h = hiint(maddr);
- 	if (tmscpcmd(M_OP_WRITE, unit, sc) == 0)
- 		return(EIO);
- 	paddr += (DBSIZE << PGSHIFT);
- 	}
- 	restorseg5(seg5);
- 	return (0);
- }
- 
- /*
-  * Perform a standalone tmscp command.  This routine is only used by tmscpdump.
-  */
- 
- tmscpcmd(op, unit, sc)
- 	int op;
- 	int unit;
- 	register struct tmscp_softc *sc;
- {
- 	int i;
- 	register struct mscp *cmp, *rmp;
- 	Trl *rlp;
- 
- 	cmp = &sc->sc_com->tmscp_rsp[1];
- 	rmp = &sc->sc_com->tmscp_rsp[0];
- 	rlp = &sc->sc_com->tmscp_ca.ca_rspdsc[0];
- 
- 	cmp->mscp_opcode = op;
- 	cmp->mscp_unit = unit;
- 	cmp->mscp_header.tmscp_msglen = mscp_msglen;
- 	rmp->mscp_header.tmscp_msglen = mscp_msglen;
- 	rlp[0].hsh |= TMSCP_OWN|TMSCP_INT;
- 	rlp[1].hsh |= TMSCP_OWN|TMSCP_INT;
- 	if (sc->sc_addr->tmscpsa&TMSCP_ERR)
- 		printf(tmscpfatalerr, sc->sc_unit, unit, sc->sc_addr->tmscpsa);
- 	i = sc->sc_addr->tmscpip;
- 
- 	while ((rlp[1].hsh & TMSCP_INT) == 0)
- 		;
- 	while ((rlp[0].hsh & TMSCP_INT) == 0)
- 		;
- 
- 	sc->sc_com->tmscp_ca.ca_rspint = 0;
- 	sc->sc_com->tmscp_ca.ca_cmdint = 0;
- 	if (rmp->mscp_opcode != (op|M_OP_END) ||
- 	    (rmp->mscp_status&M_ST_MASK) != M_ST_SUCC)
- 		{
- 		printf("err: com %d opc 0x%x stat 0x%x\ndump ", op,
- 			rmp->mscp_opcode, rmp->mscp_status);
- 		return(0);
- 		}
- 	return(1);
- }
- #endif TMSCP_DUMP
- 
- /*
-  * Catch ioctl commands, and call the "command" routine to do them.
-  */
- 
  /* ARGSUSED */
  tmscpioctl(dev, cmd, data, flag)
  	dev_t dev;
--- 1288,1299 ----
  	/*
  	 * If the controller is not active, start it.
  	 */
! 	if	(sc->sc_ctab.b_active == 0)
  		(void) tmsstart(sc);
  	splx(s);
  	return;
  	}
  
  /* ARGSUSED */
  tmscpioctl(dev, cmd, data, flag)
  	dev_t dev;
***************
*** 1660,1720 ****
  	int flag;
  {
  	struct tmscp_softc *sc = &tmscp_softc[TMSCTLR(dev)];
! 	register struct buf *bp = &sc->sc_cmdbuf;
! 	register callcount;	/* number of times to call cmd routine */
! 	register struct tms_info *tms;
  	int fcount;		/* number of files (or records) to space */
  	register struct mtop *mtop;	/* mag tape cmd op to perform */
  	register struct mtget *mtget;	/* mag tape struct to get info in */
  
  	/* we depend of the values and order of the TMS ioctl codes here */
! 	static u_char tmsops[] =
  	 {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE,
! 	  TMS_CACHE,TMS_NOCACHE};
  
  	switch (cmd) {
! 	case MTIOCTOP:	/* tape operation */
  		mtop = (struct mtop *)data;
  		switch (mtop->mt_op) {
  
! 		case MTWEOF:
! 			callcount = mtop->mt_count;
! 			fcount = 1;
! 			break;
! 		case MTFSF: case MTBSF:
! 		case MTFSR: case MTBSR:
! 			callcount = 1;
  			fcount = mtop->mt_count;
  			break;
! 		case MTREW: case MTOFFL: case MTNOP:
! 		case MTCACHE: case MTNOCACHE:
! 			callcount = 1;
! 			fcount = 1;		/* wait for this rewind */
  			break;
  		default:
! 			return (ENXIO);
  		}	/* end switch mtop->mt_op */
  
! 		if (callcount <= 0 || fcount <= 0)
! 			return (EINVAL);
! 		while (--callcount >= 0)
  			{
! 			tmscpcommand(dev, tmsops[mtop->mt_op], fcount);
! 			if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
! 			    bp->b_resid)
! 				return (EIO);
! 			if (bp->b_flags & B_ERROR)	/* like hitting BOT */
! 				break;
  			}
! 		return (geterror(bp));
  
! 	case MTIOCGET:
  		/*
  		 * Return status info associated with the particular UNIT.
  		 */
- 		tms = sc->sc_drives[TMSUNIT(dev)];
- 		if (!tms)
- 			return(ENXIO);
  		mtget = (struct mtget *)data;
  		mtget->mt_type = MT_ISTMSCP;
  		mtget->mt_dsreg = tms->tms_flags << 8;
--- 1302,1370 ----
  	int flag;
  {
  	struct tmscp_softc *sc = &tmscp_softc[TMSCTLR(dev)];
! 	struct buf *bp = &sc->sc_cmdbuf;
! 	register struct tms_info *tms = sc->sc_drives[TMSUNIT(dev)];
  	int fcount;		/* number of files (or records) to space */
  	register struct mtop *mtop;	/* mag tape cmd op to perform */
  	register struct mtget *mtget;	/* mag tape struct to get info in */
  
  	/* we depend of the values and order of the TMS ioctl codes here */
! 	static char tmsops[] =
  	 {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE,
! 	  TMS_CACHE,TMS_NOCACHE,TMS_FLUSH};
  
+ 	if	(!tms)
+ 		return(ENXIO);
+ 	if	(cmd != MTIOCGET)
+ 		tms->tms_status = ~M_ST_SUCC;
+ 	if	(tms->tms_position == 0)
+ 		tms->tms_flags |= MTF_BOM;
+ 	else
+ 		tms->tms_flags &= ~MTF_BOM;
+ 
  	switch (cmd) {
! 	case	MTIOCTOP:
  		mtop = (struct mtop *)data;
  		switch (mtop->mt_op) {
  
! 		case	MTWEOF:
! 			return(tms_wrteof(dev, tms));
! 		case	MTFSF:
! 		case	MTBSF:
! 		case	MTFSR:
! 		case	MTBSR:
  			fcount = mtop->mt_count;
  			break;
! 		case	MTFLUSH:
! 		case	MTCACHE:
! 		case	MTNOCACHE:
! 			if	((tms->Tflags & _HASCACHE|_ONLINE) !=
! 				 _HASCACHE|_ONLINE)
! 				return(0);
! 		case	MTREW:
! 		case	MTOFFL:
! 		case	MTNOP:
! 			fcount = 1;
  			break;
  		default:
! 			return(ENXIO);
  		}	/* end switch mtop->mt_op */
  
! 		if	(fcount <= 0)
! 			return(EINVAL);
! 		tmscpcommand(dev, tmsops[mtop->mt_op], fcount);
! 		if	(tms->tms_status != M_ST_SUCC)
  			{
! 			if	(tms->Tflags & _CLSEREX)
! 				tmscpcommand(dev, TMS_CSE, 1);
! 			return(EIO);
  			}
! 		return(geterror(bp));
  
! 	case	MTIOCGET:
  		/*
  		 * Return status info associated with the particular UNIT.
  		 */
  		mtget = (struct mtget *)data;
  		mtget->mt_type = MT_ISTMSCP;
  		mtget->mt_dsreg = tms->tms_flags << 8;
***************
*** 1722,1798 ****
  		mtget->mt_erreg = tms->tms_status;
  		mtget->mt_resid = tms->tms_resid;
  		break;
- 
  	default:
! 		return (ENXIO);
  	}
  	return (0);
  }
  
  /*
!  * Process an error log message
   *
!  * Only minimal decoding is done, only "useful"
!  * information is printed.  Eventually should
!  * send message to an error logger.
!  */
  
! tmserror(ctlr, mp)
! 	register int ctlr;
! 	register struct mslg *mp;
! {
! 	register i;
  
! #ifdef TMSCP_DEBUG
! 	printd("tmserror:\n");
  #endif
! 	if(!(mp->mslg_flags & (M_LF_SUCC | M_LF_CONT)))
! 		log(TMS_PRI, "tms%d,%d: %s err ", ctlr, mp->mslg_unit,
! 		mp->mslg_flags & ( M_LF_SUCC | M_LF_CONT ) ? "soft" : "hard");
  
! 	switch (mp->mslg_format) {
  
! 	case M_FM_CNTERR:
! 		log(TMS_PRI, "ctlr err event 0%o\n", mp->mslg_event);
! 		break;
! 	case M_FM_BUSADDR:
! 		log(TMS_PRI, "host memory access err, event 0%o, addr 0%o\n",
! 			mp->mslg_event, mp->mslg_busaddr);
! 		break;
! 	case M_FM_TAPETRN:
! 		log(TMS_PRI, "tape transfer err unit %d grp 0x%x event 0%o\n",
! 			mp->mslg_unit, mp->mslg_group, mp->mslg_event);
! 		break;
! 	case M_FM_STIERR:
! 		log(TMS_PRI, "STI err unit %d event 0%o\n",
! 			mp->mslg_unit, mp->mslg_event);
! #ifdef notdef
! 		/* too painful to do with log() */
! 		for(i = 0; i < 62;i++)
! 			mprintf("\t0x%x",mp->mslg_stiunsucc[i] & 0xff);
! 		mprintf("\n");
  #endif
! 		break;
! 	case M_FM_STIDEL:
! 		log(TMS_PRI, "STI Drive ErrorLog unit %d event 0%o\n",
! 			mp->mslg_unit, mp->mslg_event);
! 		break;
! 	case M_FM_STIFEL:
! 		log(TMS_PRI, "STI Formatter ErrorLog unit %d event 0%o\n",
! 			mp->mslg_unit, mp->mslg_event);
! 		break;
! 	default:
! 		log(TMS_PRI, "unknown err %d,%d format 0%o event 0%o\n",
! 			ctlr,mp->mslg_unit, mp->mslg_format, mp->mslg_event);
  	}
  
! 	if (tmscperror)
! 		{
! 		register long *p = (long *)mp;
  
! 		for (i = 0; i < mp->mslg_header.tmscp_msglen; i += sizeof(*p))
! 			printf("%x ", *p++);
! 		printf("\n");
! 		}
! }
  #endif NTMSCP
--- 1372,1945 ----
  		mtget->mt_erreg = tms->tms_status;
  		mtget->mt_resid = tms->tms_resid;
  		break;
  	default:
! 		return(ENXIO);
  	}
  	return (0);
  }
  
+ tms_wrteof(dev, tms)
+ 	dev_t	dev;
+ 	register struct tms_info *tms;
+ 	{
+ 
+ 	tmscpcommand(dev, TMS_WRITM, 1);
+ 	if	(tms->tms_status != M_ST_SUCC)
+ 		return(EIO);
+ 	tms->tms_status = ~M_ST_SUCC;
+ 	tmscpcommand(dev, TMS_WRITM, 1);
+ 	if	(tms->tms_status != M_ST_SUCC)
+ 		return(EIO);
+ 	tms->Tflags &= ~_CACHE_WRITTEN;
+ 	tms->tms_status = ~M_ST_SUCC;
+ 	tmscpcommand(dev, TMS_BSR, 1);
+ 	if	(tms->tms_status != M_ST_SUCC)
+ 		return(EIO);
+ 	return(0);
+ 	}
+ 
  /*
!  * Initialize the mscp packet for a STUNT command.  If the drive is in a
!  * 'cache lost' but 'written' state then clear it and log the error.
! */
! 
! tms_stunt_st(mp, sc, flgs)
! 	register struct	mscp	*mp;
! 	register struct	tmscp_softc *sc;
! 	int	flgs;
! 	{
! 	register struct	tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 
! 	mp->mscp_opcode = M_OP_STUNT;
! 	mp->mscp_modifier = flgs | M_MD_EXCAC;
! 	tms_cache_cmn(sc, tms, mp);
! 
! /*
!  * Set the unit flags - this includes the cache enable/disable flags.
! */
! 
! 	mp->mscp_unitflgs = tms->tms_unitflgs;
! 
! /*
!  * Only initialize the density if the position is not at BOT.  On some
!  * drives (notably the TU81) selecting a density other than the 'current'
!  * (0) causes an illegal command error.
! */
! 	if	(tms->tms_position != 0)
! 		mp->mscp_format = 0;
! 	else
! 		mp->mscp_format = tms->tms_format;
! 	}
! 
! /*
!  * Initialize the mscp packet for a REPOS command.  The 'flgs' parameter
!  * specifies if the movement if forwards or backwards and if records or
!  * tape marks (objects) are to be skipped.
! */
! 
! tms_repos_st(mp, sc, flgs)
! 	register struct	mscp	*mp;
! 	register struct	tmscp_softc *sc;
! 	int	flgs;
! 	{
! 	struct	buf	*bp = (struct buf *)mp->mscp_cmdref;
! 	register struct	tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 
! 	mp->mscp_opcode = M_OP_REPOS;
! 	mp->mscp_modifier = flgs | M_MD_CLSEX;
! 	tms->Tflags &= ~_CLSEREX;
! 	tms_cache_cmn(sc, tms, mp);	/* shared code with tms_reposrec_st */
! 	if	(mp->mscp_modifier & M_MD_OBJCT)
! 		mp->mscp_reccnt = bp->b_bcount;
! 	else
! 		mp->mscp_tmkcnt = bp->b_bcount;
! 	}
! 
! /*
!  * Initialize the mscp packet for a REPOS 'record' command.  Tape records do
!  * not include tapemarks (which is why this is a separate routine from
!  * tms_repos_st above).
! */
! 
! tms_reposrec_st(mp, sc, flgs)
! 	register struct	mscp	*mp;
! 	register struct	tmscp_softc *sc;
! 	int	flgs;
! 	{
! 	struct	buf	*bp = (struct buf *)mp->mscp_cmdref;
! 	register struct	tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 
! 	mp->mscp_opcode = M_OP_REPOS;
! 	mp->mscp_modifier = flgs;
! 	tms_cache_cmn(sc, tms, mp);
! 	mp->mscp_reccnt = bp->b_bcount;
! 	}
! 
! /*
!  * Initialize the mscp packet for an AVAIL command.  The only time this is
!  * done is on a 'rewoffl' command.
! */
! 
! tms_avail_st(mp, sc, flgs)
! 	register struct	mscp	*mp;
! 	register struct	tmscp_softc *sc;
! 	int	flgs;
! 	{
! 	register struct	tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 
! 	mp->mscp_opcode = M_OP_AVAIL;
! 	mp->mscp_modifier = flgs | M_MD_CLSEX;
! 	tms->Tflags &= ~_CLSEREX;
! 	if	(tms->Tflags & _CACHE_LOST)
! 		{
! 		tms->Tflags &= ~(_CACHE_LOST | _CACHE_WRITTEN);
! 		mp->mscp_modifier |= M_MD_CDATL;
! 		}
! 	}
! 
! /*
!  * Initialize the mscp packet for a WTM (write tapemark) command.
! */
! 
! tms_wtm_st(mp, sc, flgs)
! 	register struct	mscp	*mp;
! 	register struct	tmscp_softc *sc;
! 	int	flgs;
! 	{
! 	register struct	tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 
! 	mp->mscp_opcode = M_OP_WRITM;
! 	mp->mscp_modifier = flgs | M_MD_CLSEX;
! 	tms->Tflags &= ~_CLSEREX;
! 	tms_cache_cmn(sc, tms, mp);
! 	}
! 
! tms_cache_cmn(sc, tms, mp)
! 	register struct	tmscp_softc *sc;
! 	register struct	tms_info *tms;
! 	register struct	mscp *mp;
! 	{
! 
! 	if	(tms->Tflags & _CACHE_LOST)
! 		{
! 		if	(!(tms->Tflags & _CACHE_WRITTEN) || 
! 			   (tms->tms_flags & MTF_CSE))
! 			{
! 			tms->Tflags &= ~(_CACHE_LOST | _CACHE_WRITTEN);
! 			mp->mscp_modifier |= M_MD_CDATL;
! 			}
! 		else
! 			log(LOG_INFO, "tms%d,%d cache lost\n",
! 				sc->sc_unit, mp->mscp_unit);
! 		}
! 	}
! 
! /*
!  * Process the end message from a REPOS command.  Called from tmscprsp().
! */
! 
! tms_repos_em(mp, sc)
! 	register struct mscp *mp;
! 	register struct tmscp_softc *sc;
! 	{
! 	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	u_short	em_status = mp->mscp_status & M_ST_MASK;
! 
! 	(void)tms_check_ret(mp, sc);
! 	if	(em_status == M_ST_SUCC)
! 		{
! 		if	(tms->tms_position != mp->mscp_position)
! 			tms->Tflags &= ~_WRITTEN;
! 		if	(tms->tms_position = mp->mscp_position)
! 			tms->tms_flags &= ~MTF_BOM;
! 		else
! 			{
! 			tms->tms_flags |= MTF_BOM;
! 			tms->Tflags &= ~_LOST;
! 			}
! 		tms->Tflags &= ~_CACHE_WRITTEN;
! 		}
! 	tms->tms_resid = 0;
! 	tms_iodone(mp, sc);
! 	}
! 
! /*
!  * Process the end message from a STUNT command.
! */
! 
! tms_stunt_em(mp, sc)
! 	register struct mscp *mp;
! 	register struct tmscp_softc *sc;
! 	{
! 	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	u_short	em_status = mp->mscp_status & M_ST_MASK;
! 
! 	(void)tms_check_ret(mp, sc);
! 	tms->Tflags &= ~_CACHE_WRITTEN;
! 	if	(em_status == M_ST_SUCC)
! 		{
! 		tms->tms_unitflgs = mp->mscp_unitflgs;
! 		tms->tms_format = mp->mscp_format;
! 		tms->tms_type = mp->mscp_mediaid;
! 		tms->Tflags |= _ONLINE;
! 		}
! 	tms->tms_resid = 0;
! 	tms_iodone(mp, sc);
! 	}
! 
! /*
!  * Process the end message from a WRITM (Write Tape Mark) command.
! */
! 
! tms_wtm_em(mp, sc)
! 	register struct mscp *mp;
! 	register struct tmscp_softc *sc;
! 	{
! 	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	u_short	em_status = mp->mscp_status & M_ST_MASK;
! 
! 	if	(em_status == M_ST_SUCC)
! 		{
! 		tms->Tflags &= ~_WRITTEN;
! 		tms->tms_position = mp->mscp_position;
! 		}
! 	(void)tms_check_ret(mp, sc);
! 	tms->tms_resid = 0;
! 	tms_iodone(mp, sc);
! 	}
! 
! tms_avail_em(mp, sc)
! 	register struct mscp *mp;
! 	register struct tmscp_softc *sc;
! 	{
! 	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 
! 	tms->Tflags &= ~_INUSE;
! 	(void)tms_check_ret(mp, sc);
! 	tms->Tflags &= ~_ONLINE;
! 	tms->tms_position = 0;
! 	tms->tms_flags |= MTF_BOM;
! 	if	(tms->tms_status == M_ST_SUCC)
! 		tms->Tflags &= ~_CACHE_WRITTEN;
! 	tms->tms_resid = 0;
! 	tms_iodone(mp, sc);
! 	}
! 
! tms_flush_em(mp, sc)
! 	register struct mscp *mp;
! 	register struct tmscp_softc *sc;
! 	{
! 	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	u_short	em_status = mp->mscp_status & M_ST_MASK;
! 
! 	if	(em_status == M_ST_SUCC)
! 		tms->Tflags &= ~_CACHE_WRITTEN;
! 	else
! 		log(LOG_INFO, "tms%d,%d flush fail\n",sc->sc_unit,mp->mscp_unit);
! 	tms->tms_position = mp->mscp_position;
! 	(void)tms_check_ret(mp, sc);
! 	tms->tms_resid = 0;
! 	tms_iodone(mp, sc);
! 	}
! 
! tms_gtunt_em(mp, sc)
! 	register struct mscp *mp;
! 	register struct tmscp_softc *sc;
! 	{
! 	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	u_short	em_status = mp->mscp_status & M_ST_MASK;
! 	u_short	em_flags = mp->mscp_unitflgs;
! 
! 	(void)tms_check_ret(mp, sc);
! 	if	(em_status == M_ST_SUCC)
! 		{
! 		tms->tms_format = mp->mscp_format;
! 		tms->tms_type = mp->mscp_mediaid;
! 		tms->tms_fmtmenu = mp->mscp_fmtmenu;
! 		tms->tms_unitflgs = mp->mscp_unitflgs;
! 		tms->Tflags |= _ONLINE;
! 		if	(em_flags & (M_UF_WRTPH | M_UF_WRTPS | M_UF_WRTPD))
! 			tms->tms_flags |= MTF_WRTLCK;
! 		else
! 			tms->tms_flags &= ~MTF_WRTLCK;
! 		if	(em_flags & M_UF_CACH)
! 			{
! 			tms->Tflags |= _HASCACHE;
! 			if	(tms->Tflags & _CACHE_ON)
! 				{
! 				tms->tms_unitflgs |= M_UF_WBKNV;
! 				tms->tms_unitflgs &= ~M_UF_SCCHH;
! 				}
! 			else
! 				{
! 				tms->tms_unitflgs &= ~M_UF_WBKNV;
! 				tms->tms_unitflgs |= M_UF_SCCHH;
! 				}
! 			}
! 		if	(tms->tms_position == 0)
! 			tms->tms_flags |= MTF_BOM;
! 		else
! 			tms->tms_flags &= ~MTF_BOM;
! 		}
! 	tms->tms_resid = 0;
! 	tms_iodone(mp, sc);
! 	}
! 
! tms_rw_em(mp, sc)
! 	register struct mscp *mp;
! 	register struct tmscp_softc *sc;
! 	{
! 	struct	buf	*bp = (struct buf *)mp->mscp_cmdref;
! 	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	u_short	em_status = mp->mscp_status & M_ST_MASK;
! 
! 	tms->tms_flags &= ~MTF_WRITTEN;
! 	(void)tms_check_ret(mp, sc);
! 	if	(em_status == M_ST_SUCC)
! 		{
! 		if	((tms->tms_endcode & ~M_OP_END) == M_OP_WRITE)
! 			{
! 			tms->Tflags |= _WRITTEN;
! 			tms->tms_flags |= MTF_WRITTEN;
! 			}
! 		else
! 			tms->Tflags &= ~_CACHE_WRITTEN;
! 		}
! 	tms->tms_resid = bp->b_bcount - mp->mscp_bytecnt;
! 	if	(tms->tms_position = mp->mscp_position)
! 		tms->tms_flags &= ~MTF_BOM;
! 	else
! 		tms->tms_flags |= MTF_BOM;
! 	tms_iodone(mp, sc);
! 	}
! 
! /*
!  * This routine removes the buffer from the I/O wait queue, decrements the
!  * drive queue size, stores the residual value in the buffer header and
!  * calls iodone.
! */
! 
! tms_iodone(mp, sc)
! 	struct	mscp	*mp;
! 	struct	tmscp_softc *sc;
! 	{
! 	struct	tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	register struct	buf	*bp = (struct buf *)mp->mscp_cmdref;
! 	register struct	buf	*dp = &tms->tms_dtab;
! 	u_short	st = tms->tms_status;
! 
! /*
!  * Remove the buffer from the I/O wait queue.
! */
! 	bp->av_back->av_forw = bp->av_forw;
! 	bp->av_forw->av_back = bp->av_back;
! 	dp->b_qsize--;
! /*
!  * The weird (and not fully understood) treatment of the OFFLIN and AVLBL
!  * status values was moved intact.  It is not clear why the error bit can't
!  * simply be set and iodone called as for other not successful status codes.
! */
! 	if	(st == M_ST_OFFLN || st == M_ST_AVLBL)
! 		{
! /*
!  * Link buffer on to the front of the drive queue.
! */
! 		if	((bp->av_forw = dp->b_actf) == 0)
! 			dp->b_actf = bp;
! 		dp->b_actf = bp;
! /*
!  * Link the drive onto the controller queue.
! */
! 		if	(dp->b_active == 0)
! 			{
! 			dp->b_forw = NULL;
! 			if	(sc->sc_ctab.b_actf == NULL)
! 				sc->sc_ctab.b_actf = dp;
! 			else
! 				sc->sc_ctab.b_actl->b_forw = dp;
! 			sc->sc_ctab.b_actl = dp;
! 			dp->b_active = 1;
! 			}
! 		return;
! 		}
! 	bp->b_resid = tms->tms_resid;
! 	iodone(bp);
! 	}
! 
! /*
!  * Check the return status of an mscp packet and adjust the drive's flags
!  * appropriately.  On error conditions set the error flag and code in the 
!  * buffer header.
   *
!  * Many of the 'case' statements below are finer grained than strictly
!  * necessary - this is done to provide easy access for logging of specific 
!  * conditions during debugging.
! */
  
! tms_check_ret(mp, sc)
! 	struct	mscp	*mp;
! 	struct	tmscp_softc *sc;
! 	{
! 	register struct	tms_info *tms = sc->sc_drives[mp->mscp_unit];
! 	register struct	buf	*bp = (struct buf *)mp->mscp_cmdref;
! 	u_short	em_status = mp->mscp_status & M_ST_MASK;
! 	u_short	em_subcode = mp->mscp_status >> M_ST_SBBIT;
! 	u_short	em_flags = mp->mscp_flags;
! 	u_short	em_endcode = mp->mscp_endcode & ~M_OP_END;
! 	char	berr, unkerr;
  
! #ifdef	TMSDEBUG
! 	if	(em_status != M_ST_SUCC && em_status != M_ST_TAPEM &&
! 			(tmscpprintf & 0x1))
! 		log(LOG_INFO, "tms%d,%d st=%x sb=%x fl=%x en=%x\n",
! 			sc->sc_unit, mp->mscp_unit,
! 			em_status, em_subcode, em_flags, em_endcode);
  #endif
! 	tms->tms_endcode = mp->mscp_endcode;
! 	if	(em_flags & M_EF_EOT)
! 		tms->tms_flags |= MTF_EOM;
! 	else
! 		tms->tms_flags &= ~MTF_EOM;
! 	if	(em_flags & M_EF_DLS)
! 		tms->Tflags |= _CACHE_LOST;
! 	if	(em_flags & M_EF_PLS)
! 		tms->Tflags |= _LOST;
! 	tms->tms_status = mp->mscp_status;
  
! 	berr = 0;
! 	unkerr = 0;
  
! 	switch	(em_status)
! 		{
! 		case	M_ST_SUCC:
! 			{
! 			switch	(em_subcode)
! 				{
! 				case	M_SC_DUPUN:	/* Duplicate unit */
! 					berr = ENXIO;
! 					break;
! 				case	M_SC_ALONL:	/* Already online */
! 				case	M_SC_STONL:	/* Still online */
! 				case	M_SC_UNIGN:	/* Unload ignored */
! 				case	M_SC_ROVOL:	/* Readonly unit */
! 					tms->Tflags |= _ONLINE;
! 					break;
! 				case	M_SC_EOT:	/* End of Tape */
! 					tms->tms_flags |= MTF_EOM;
! 					break;
! 				}
! 			}
! 			break;
! 		case	M_ST_OFFLN:
! 			tms->Tflags &= ~_ONLINE;
! 			if	((tms->Tflags & _CACHE_ON) && 
! 				 (tms->Tflags & _CACHE_WRITTEN))
! 				log(LOG_INFO, "tms%d,%d cache loss2\n",
! 					sc->sc_unit, mp->mscp_unit);
! 			berr = ENXIO;
! 			break;
! 		case	M_ST_WRTPR:			/* Write Protected */
! 			tms->tms_flags |= MTF_WRTLCK;
! 			berr = EACCES;			/* Really an error ? */
! 			break;
! 		case	M_ST_ICMD:			/* Byte count too big */
! 		case	M_ST_ABRTD:			/* Command aborted */
! 		case	M_ST_COMP:			/* Data Compare error */
! 		case	M_ST_DATA:			/* Data error */
! 		case	M_ST_HSTBF:			/* Host buffer error */
! 		case	M_ST_CNTLR:			/* Controller error */
! 		case	M_ST_FMTER:			/* Formatter error */
! 			berr = EIO;
! 			break;
! 		case	M_ST_AVLBL:			/* Unit available */
! 			tms->Tflags &= ~(_LOST | _CLSEREX | _SEREX | _ONLINE);
! 			break;
! 		case	M_ST_BOT:			/* Beginning of tape */
! 			tms->tms_flags |= MTF_BOM;
! 			tms->tms_position = 0;
! 			break;
! 		case	M_ST_TAPEM:			/* Tape Mark */
! 			tms->Tflags |= (_BUFMARK | _CLSEREX);
! 			break;
! 		case	M_ST_SEX:			/* Serious Exception */
! 			if	(em_flags & M_EF_EOT)
! 				{
! 				tms->tms_flags |= MTF_EOM;
! 				berr = ENOSPC;
! 				}
! 			else
! 				{
! 				tms->Tflags &= ~_CLSEREX;
! #ifdef	TMSDEBUG
! 				log(LOG_INFO, "tms%d,%d serex, subcode %x\n",
! 					sc->sc_unit, mp->mscp_unit);
  #endif
! 				berr = EIO;
! 				}
! 			break;
! 		case	M_ST_PLOST:			/* Position Lost */
! #ifdef	TMSDEBUG
! 			log(LOG_INFO, "tms%d,%d plost\n", sc->sc_unit,
! 				mp->mscp_unit);
! #endif
! 			tms->Tflags |= (_LOST | _SEREX);
! 			tms->Tflags &= ~_CLSEREX;
! 			berr = EIO;
! 			break;
! 		case	M_ST_LED:			/* Logical end of dev */
! 			tms->Tflags |= _CLSEREX;
! 			break;
! 		case	M_ST_MFMTE:			/* Media format err */
! 		case	M_ST_DRIVE:			/* Drive error */
! 		case	M_ST_RDTRN:			/* Record truncated */
! 			tms->Tflags |= _SEREX;
! 			tms->Tflags &= ~_CLSEREX;
! 		case	M_ST_LOADR:
! 		case	M_ST_DIAG:			/* Intern diag err */
! 		case	M_ST_IPARM:			/* Invalid parameter */
! 			berr = EIO;
! 			break;
! 		default:
! 			unkerr = 1;
! 			berr = EIO;
! 			break;
! 		}
! 	if	(unkerr)
! 		log(LOG_INFO, "tms%d,%d: bad st/sb =%x/%x\n",
! 			sc->sc_unit, mp->mscp_unit, em_status, em_subcode);
! 	if	(berr && bp)
! 		{
! 		bp->b_flags |= B_ERROR;
! 		bp->b_error = berr;
! 		}
! 	return;
  	}
  
! /*
!  * Process an error log datagram. 
!  *
!  * No decoding is done - it wasn't worth the D space.  If bit 1 is set
!  * in the print flags then a simple message is generated out of (hopefully) 
!  * useful fields.
!  *
!  * Eventually a error log daemon will be written and the datagram sent to
!  * it for capture and detailed analysis.  Until then the logging in 
!  * 'tms_check_ret' and a few other strategic spots will have to suffice.
!  */
  
! 	u_short	tms_datagrams[NTMSCP];
! 
! tmserror(ctlr, mp)
! 	int ctlr;
! 	register struct mslg *mp;
! 	{
! 
! 	tms_datagrams[ctlr]++;
! 	if	(tmscpprintf & 0x2)
! 		log(LOG_INFO,
! 		"tms%d,%d dgram fmt=%x evt=%x grp=%x flg=%x pos=%D\n",
! 			ctlr, mp->mslg_unit, mp->mslg_format,
! 			mp->mslg_event, mp->mslg_group, mp->mslg_flags, 
! 			mp->mslg_position);
! 	}
  #endif NTMSCP
*** /usr/src/sys/pdpuba/tmscpreg.h.old	Tue Aug 14 13:13:46 1990
--- /usr/src/sys/pdpuba/tmscpreg.h	Thu Dec 14 21:35:05 1995
***************
*** 1,6 ****
  /* @(#)tmscpreg.h	7.1 (Berkeley) 6/5/86 */
  
! /*	@(#)tmscpreg.h	1.1	11/2/84	84/09/25	*/
  
  /****************************************************************
   *								*
--- 1,6 ----
  /* @(#)tmscpreg.h	7.1 (Berkeley) 6/5/86 */
  
! /*	@(#)tmscpreg.h	1.2	(2.11BSD) 1995/12/14 */
  
  /****************************************************************
   *								*
***************
*** 58,63 ****
--- 58,75 ----
  /*
   * TMSCP Communications Area
   */
+ 
+ /* 
+  * These defines were moved here so they could be shared between the
+  * driver and the crash dump module.
+ */
+ #define	NRSPL2	3	/* log2 number of response packets */
+ #define	NCMDL2	3	/* log2 number of command packets */
+ #define	NRSP	(1<<NRSPL2)
+ #define	NCMD	(1<<NCMDL2)
+ #define	RINGBASE	(4 * sizeof (short))
+ /* Size to map in when mapping a controller's command packet area */
+ #define	MAPBUFDESC	(((btoc(sizeof (struct tmscp)) - 1) << 8) | RW)
   
  struct tmscpca {
  	short	ca_xxx1;	/* unused */
*** /VERSION.old	Tue Dec  5 20:42:46 1995
--- /VERSION	Wed Dec 27 11:22:23 1995
***************
*** 1,4 ****
! Current Patch Level: 282
  
  2.11 BSD
  ============
--- 1,4 ----
! Current Patch Level: 286
  
  2.11 BSD
  ============