Subject: TMSCP fixes plus TQK70  support (#409)
Index:	pdpuba/tmscp.c,pdp/mscp_common.h 2.11BSD

Description:
	Due to a bug in the TMSCP driver a TQK70+TK70 would not work
	with 2.11BSD.

	Enabling the cache has no effect and possibly leaves the driver in
	a state where no further accesses to the drive will be allowed.

Repeat-By:
	Add a TK70 to the system.  Try writing to the tape.  One of two
	things will happen: 1) an immediate "end of tape" error will be 
	produced, 2) the program will hang and a reboot will be probably be 
	needed to regain control of the terminal (and free the tape drive).

	Attempting to read a TK70 tape will produce an error message
	from the driver saying that the read failed with a status of 4
	(the drive went "available" during the read command!).
	
	If the diagnostic output of the TMSCP driver is enabled with
	"sysctl -w machdep.tmscp.printf=9" it will be seen that an 'endcode'
	of 0x00 (actually 0x80 with the high bit indicating command complete)
	is being returned by the controller (with the status field
	set to 1 which indicates an invalid parameter in the previous 
	command).

	The TQK70 reports (via a flag in the 'get unit characteristics' 
	response) that it is 'cache capable' but enabling the cache
	with either "mt -f /dev/rmtxx cacheon" or the sysctl command
	"sysctl -w machdep.tmscp.cache=xxx" has no effect.

	All in all the TK70 was not working right at all.

Fix:

	The one basic problem was that the TQK70 is much more picky about
	the content of the 'density' (m_format) field in the TMSCP command
	packet.  Earlier controllers (TK50 for example) had 0 in the high
	byte of this field.  The TQK70 insists that a nonzero (0x2) value
	be present.   That field being in error in the 'set unit 
	characteristics' command was causing almost all of the problems.
	The density selection code was fixed to preserve the high byte.

	It is a bug on the TQK70's part that 0x80 is being returned  in
	response to a command of 0x0A!  The proper endcode is 0x8A!

	During the debugging and testing of the driver it was noticed that
	the drive would be left "busy" and not useable without a reboot.
	At one time the 'tmscpcommand()' function was only used to perform
	a non-blocking rewind when the drive was close.  Since that time
	the tmscpcommand() function was used much more widely and those
	newer uses require timeout logic to prevent the drive from being
	left permanently busy (hardware going catatonic).

	Another section of code never did feel quite right.  The special
	treatment of 'available and offline' status codes had been carried 
	over from previous versions of the driver.  This section of code
	was removed because it was failing to perform an iodone() call
	when a read or write command completed with an offline or available
	error return.

	Other minor changes included shortening some error message strings
	to save D space and  adding one or two extra debug statements to help
	with future debugging.

	NOTE:  When writing a TK70 cartridge it is necessary to use the
	"high density" device number.  Instead of "/dev/rmt0" use "/dev/rmt24"
	(created with "mknod /dev/rmt24 c 23 24").  This is because while
	a TQK70 presents two density choices (TK50 and TK70) only one of them
	can be used for writing (but the driver doesn't necessarily know
	which one - it didn't feel "right" to hard code that into the driver).

	Apply the following patch and rebuild the kernel.  Cut where
	indicated and save to a file (/tmp/409), then:

		patch < /tmp/409
		cd /sys/YOUR_KERNEL
		make
		mv /unix /ounix
		mv unix /unix
		chmod 744 /unix

	If you are using a networking kernel then:

		mv /netnix /onetnix
		mv netnix /netnix
		chmod 744 /netnix

	and finally:

		reboot

	It is also a very good idea to keep an updated GENERIC kernel
	present on the system for use in emergencies.  Often this is /genunix.

		cd /sys/GENERIC
		make
		mv unix /genunix
		chmod 744 /genunix

	As always this and previous updates to 2.11BSD are available via
	anonymous FTP to either FTP.IIPO.GTEGSC.COM or MOE.2BSD.COM in the
	directory /pub/2.11BSD.

--------------------------cut here---------------------
*** /usr/src/sys/pdpuba/tmscp.c.old	Fri Apr 24 19:50:11 1998
--- /usr/src/sys/pdpuba/tmscp.c	Fri Feb 26 21:15:19 1999
***************
*** 1,6 ****
  #define	TMSDEBUG	1
  
! /*	@(#)tmscp.c	1.11 (2.11BSD GTE) 1998/4/24 */
  
  #if	!defined(lint) && defined(DOSCCS)
  static	char	*sccsid = "@(#)tmscp.c	1.24	(ULTRIX)	1/21/86";
--- 1,6 ----
  #define	TMSDEBUG	1
  
! /*	@(#)tmscp.c	1.12 (2.11BSD) 1999/2/25 */
  
  #if	!defined(lint) && defined(DOSCCS)
  static	char	*sccsid = "@(#)tmscp.c	1.24	(ULTRIX)	1/21/86";
***************
*** 31,37 ****
--- 31,56 ----
   * tmscp.c - TMSCP (TK50/TU81) tape device driver
   * 
   * Modification History:
+  * 25-Feb-99 - sms
+  *	Fix density selection to preserve the high byte of m_format.  This
+  *	is required devices (such as the TK70) which have a nonzero value
+  *	in this field.
   *
+  * 22-Feb-99 - sms
+  *	Add timeout logic to tmscpcommand to catch hardware going catatonic.
+  *	When tmscpcommand() was first created the only use was to issue a
+  *	nonblocking rewind upon close.  Tmscpcommand is now called for many
+  *	other functions some of which can leave a process (and the drive) hung
+  *	unless a timeout is done.
+  *
+  *	Remove special treatment of OFFLINE and AVLBL status codes in 
+  *	tms_iodone().  The code is suspected of having been a bug even in
+  *	its old location but is definitely causing problems now - if a read
+  *	completes with a 'AVLBL' status the drive is hung because an iodone()
+  *	is never performed.
+  *
+  *	Minor cleanup done thruout (reduce D space consumption ,etc).
+  *
   * 24-Apr-98 - sms
   *	An incorrect pointer was being passed to tms_iodone() from tmscprsp()
   *	when dealing with the 'invalid endcode' case.  While that value should
***************
*** 318,323 ****
--- 337,343 ----
  int	tmscp_cp_wait = 0;	/* Something to wait on for command */
  				/* packets and or credits. */
  int	wakeup();
+ 	int	tmswatchdog();
  extern	int	hz;		/* Should find the right include */
  extern	long	_iomap();
  extern	u_int	tmscp_cache;	/* See pdp/kern_pdp.c */
***************
*** 528,534 ****
  		break;
  
  	default:
! 	    log(LOG_INFO, "tms%d: state %d\n", dev, sc->sc_state);
  	    return;
  	}	/* end switch */
  
--- 548,554 ----
  		break;
  
  	default:
! 	    log(LOG_INFO, "tms%d: ST %d\n", dev, sc->sc_state);
  	    return;
  	}	/* end switch */
  
***************
*** 604,609 ****
--- 624,630 ----
  	register struct tms_info *tms;
  	register struct mscp *mp;
  	struct tmscpdevice *tmscpaddr;
+ 	u_short	cmdref;
  	int s,i;
  	
  	if (ctlr >= NTMSCP)
***************
*** 628,634 ****
  		if (sc->sc_state == S_IDLE)
  			if	(!tkini(sc))
  				{
! 				log(LOG_INFO, "tms%d init fail\n", ctlr);
  				sc->sc_drives[unit] = NULL;
  				tms->Tflags = 0;
  				tms->tms_type = 0;
--- 649,655 ----
  		if (sc->sc_state == S_IDLE)
  			if	(!tkini(sc))
  				{
! 				log(LOG_INFO, "tms%d init\n", ctlr);
  				sc->sc_drives[unit] = NULL;
  				tms->Tflags = 0;
  				tms->tms_type = 0;
***************
*** 671,678 ****
  		mp->mscp_opcode = M_OP_ONLIN;
  		mp->mscp_unit = unit;		/* unit? */
  		tms_clrerr(tms, mp);
! 		mp->mscp_cmdref = (u_short)&tms->tms_type;
! 					    /* need to sleep on something */
  		((Trl *)mp->mscp_dscptr)->hsh |= (TMSCP_OWN | TMSCP_INT);
  		normalseg5();
  		i = tmscpaddr->tmscpip;
--- 692,700 ----
  		mp->mscp_opcode = M_OP_ONLIN;
  		mp->mscp_unit = unit;		/* unit? */
  		tms_clrerr(tms, mp);
! 	/* calculate this once instead of 4 times */
! 		cmdref = (u_short)&tms->tms_type;	
! 		mp->mscp_cmdref = cmdref; 	/* need to sleep on something */
  		((Trl *)mp->mscp_dscptr)->hsh |= (TMSCP_OWN | TMSCP_INT);
  		normalseg5();
  		i = tmscpaddr->tmscpip;
***************
*** 682,690 ****
  		 * 240 seconds (4 minutes) is necessary since a rewind
  		 * can take a few minutes.
  		 */
! 		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))
  		{
--- 704,712 ----
  		 * 240 seconds (4 minutes) is necessary since a rewind
  		 * can take a few minutes.
  		 */
! 		timeout(wakeup,(caddr_t) cmdref,240 * hz);
! 		sleep((caddr_t)cmdref,PSWP+1);
! 		untimeout(wakeup, cmdref);
  		}
  	if	(!(tms->Tflags & _ONLINE))
  		{
***************
*** 754,761 ****
   * 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;
  			}
  		}
--- 776,782 ----
   * 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 flsh\n", TMSCTLR(dev), unit);
  			tms->Tflags &= ~_CACHE_WRITTEN;
  			}
  		}
***************
*** 790,796 ****
  	bp = &tmscp_softc[TMSCTLR(dev)].sc_cmdbuf;
  
  	s = spl5();
! 	while (bp->b_flags&B_BUSY)
  		{
  		bp->b_flags |= B_WANTED;
  		sleep((caddr_t)bp, PRIBIO);
--- 811,817 ----
  	bp = &tmscp_softc[TMSCTLR(dev)].sc_cmdbuf;
  
  	s = spl5();
! 	while	(bp->b_flags&B_BUSY)
  		{
  		bp->b_flags |= B_WANTED;
  		sleep((caddr_t)bp, PRIBIO);
***************
*** 807,824 ****
  	bp->b_bcount = count;
  	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);
! 	bp->b_flags &= B_ERROR;
  }
  
  /*
   * Init mscp communications area
   */
  tmsginit(sc, com, msgs, offset, length, flags)
--- 828,860 ----
  	bp->b_bcount = count;
  	bp->b_resid = com;
  	bp->b_blkno = 0;
  /*
!  * Start the timer before entering the strategy routine.  If it declares
!  * an immediate error it will also perform an iodone which will cause us
!  * to fall thru and cancel the timer.
  */
+ 	timeout(tmswatchdog, bp, 240 * hz);
+ 	tmscpstrategy(bp);
  	iowait(bp);
! 	untimeout(tmswatchdog, bp);
! 	if	(bp->b_flags & B_WANTED)	/* Anyone waiting above? */
! 		wakeup(bp);
! 	bp->b_flags &= B_ERROR;		/* Clears B_BUSY */
  }
  
  /*
+  * If this routine is called then  (after 4 minutes) something is hung.
+  * Set the I/O done flag, set error to be ETIMEDOUT, and issue the wakeup.
+ */
+ tmswatchdog(bp)
+ 	struct	buf *bp;
+ 	{
+ 
+ 	bp->b_error = ETIMEDOUT;
+ 	biodone(bp);
+ 	}
+ 
+ /*
   * Init mscp communications area
   */
  tmsginit(sc, com, msgs, offset, length, flags)
***************
*** 968,974 ****
  	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 */
--- 1004,1010 ----
  	tms = sc->sc_drives[unit];
  	if	((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN)
  		{
! 		log(LOG_INFO, "tms%d,%d: sa %x st %d\n", sc->sc_unit,
  			unit, tmscpaddr->tmscpsa, sc->sc_state);
  		(void)tkini(sc);
  		/* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */
***************
*** 1062,1072 ****
  			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;
--- 1098,1109 ----
  			tms_repos_st(mp, sc, M_MD_OBJCT);
  			break;
  		case TMS_SETDENSITY:
! 			tms->tms_format &= ~M_TF_MASK;
! 			tms->tms_format |= Dmatrix[TMSDENS(bp->b_dev)][tms->tms_fmtmenu & FMTMASK];
  			tms_stunt_st(mp, sc, 0);
  			break;
  		default:
! 			log(LOG_INFO, "ioctl %x\n", bp->b_resid);
  			/* Need a no-op. Reposition no amount */
  			mp->mscp_opcode = M_OP_REPOS;
  			break;
***************
*** 1089,1094 ****
--- 1126,1138 ----
  		mp->mscp_modifier |= M_MD_CLSEX;
  		}
  
+ 	if	(tmscpprintf & 0x8)
+ 		{
+ 		log(LOG_INFO, "tms%d,%d -> op %x fl %x mod %x\n",
+ 			sc->sc_unit, mp->mscp_unit,
+ 			mp->mscp_opcode, mp->mscp_flags, mp->mscp_modifier);
+ 		}
+ 
  	((Trl *)mp->mscp_dscptr)->hsh |= (TMSCP_OWN|TMSCP_INT);
  	i = tmscpaddr->tmscpip;              /* initiate polling */
  	dp->b_qsize++;
***************
*** 1242,1248 ****
  	case	M_OP_AVATN:
  		tms->Tflags &= ~_ONLINE;
  		return;
! 	case 0:
  		if	(tmscpprintf & 0x8)
  			log(LOG_INFO, "tms%d,%d: inv end=%x st=%x\n",
  				sc->sc_unit,mp->mscp_unit,em_endcode,em_status);
--- 1286,1298 ----
  	case	M_OP_AVATN:
  		tms->Tflags &= ~_ONLINE;
  		return;
! /*
!  * An endcode with no opcode (0x80) is an invalid command.  This is supposed
!  * to indicate a protocol error (illegal opcode, parameter error, etc) but
!  * without the real opcode we don't know which command (reposition, write,
!  * read, ...) failed.  So, just declare I/O done and hope for the best.
! */
! 	case	0:
  		if	(tmscpprintf & 0x8)
  			log(LOG_INFO, "tms%d,%d: inv end=%x st=%x\n",
  				sc->sc_unit,mp->mscp_unit,em_endcode,em_status);
***************
*** 1272,1278 ****
  		return;
  	default:
  		if	(tmscpprintf & 0x8)
! 			log(LOG_INFO, "tms%d,%d bad rsp: %x\n", sc->sc_unit,
  				mp->mscp_unit, em_endcode);
  		return;
  	}	/* end switch mp->mscp_opcode */
--- 1322,1328 ----
  		return;
  	default:
  		if	(tmscpprintf & 0x8)
! 			log(LOG_INFO, "tms%d,%d rsp %x\n", sc->sc_unit,
  				mp->mscp_unit, em_endcode);
  		return;
  	}	/* end switch mp->mscp_opcode */
***************
*** 1590,1596 ****
  			mp->mscp_modifier |= M_MD_CDATL;
  			}
  		else
! 			log(LOG_INFO, "tms%d,%d cache lost\n",
  				sc->sc_unit, mp->mscp_unit);
  		}
  	}
--- 1640,1646 ----
  			mp->mscp_modifier |= M_MD_CDATL;
  			}
  		else
! 			log(LOG_INFO, "tms%d,%d clost\n",
  				sc->sc_unit, mp->mscp_unit);
  		}
  	}
***************
*** 1675,1683 ****
  	{
  	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)
--- 1725,1732 ----
  	{
  	register struct tms_info *tms = sc->sc_drives[mp->mscp_unit];
  
  	(void)tms_check_ret(mp, sc);
! 	tms->Tflags &= ~(_INUSE | _ONLINE);
  	tms->tms_position = 0;
  	tms->tms_flags |= MTF_BOM;
  	if	(tms->tms_status == M_ST_SUCC)
***************
*** 1696,1702 ****
  	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;
--- 1745,1751 ----
  	if	(em_status == M_ST_SUCC)
  		tms->Tflags &= ~_CACHE_WRITTEN;
  	else
! 		log(LOG_INFO, "tms%d,%d Flush\n",sc->sc_unit,mp->mscp_unit);
  	tms->tms_position = mp->mscp_position;
  	(void)tms_check_ret(mp, sc);
  	tms->tms_resid = 0;
***************
*** 1771,1782 ****
  	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;
--- 1820,1825 ----
***************
*** 1784,1825 ****
  	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);
  	}
--- 1827,1840 ----
  	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;
  
  /*
!  * Remove the buffer from the I/O wait queue.  Set the residual count and
!  * declare the I/O done.
  */
  	bp->av_back->av_forw = bp->av_forw;
  	bp->av_forw->av_back = bp->av_back;
  	dp->b_qsize--;
  	bp->b_resid = tms->tms_resid;
  	iodone(bp);
  	}
***************
*** 1890,1896 ****
  			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;
--- 1905,1911 ----
  			tms->Tflags &= ~_ONLINE;
  			if	((tms->Tflags & _CACHE_ON) && 
  				 (tms->Tflags & _CACHE_WRITTEN))
! 				log(LOG_INFO, "tms%d,%d closs2\n",
  					sc->sc_unit, mp->mscp_unit);
  			berr = ENXIO;
  			break;
***************
*** 1926,1932 ****
  			else
  				{
  				tms->Tflags &= ~_CLSEREX;
! 				log(LOG_INFO, "tms%d,%d serex, subcode %x\n",
  					sc->sc_unit, mp->mscp_unit, em_subcode);
  				berr = EIO;
  				}
--- 1941,1947 ----
  			else
  				{
  				tms->Tflags &= ~_CLSEREX;
! 				log(LOG_INFO, "tms%d,%d serex sb %x\n",
  					sc->sc_unit, mp->mscp_unit, em_subcode);
  				berr = EIO;
  				}
***************
*** 1957,1963 ****
  			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)
  		{
--- 1972,1978 ----
  			break;
  		}
  	if	(unkerr)
! 		log(LOG_INFO, "tms%d,%d: st/sb =%x/%x\n",
  			sc->sc_unit, mp->mscp_unit, em_status, em_subcode);
  	if	(berr && bp)
  		{
*** /usr/src/sys/pdp/mscp_common.h.old	Sun Feb  1 14:34:57 1998
--- /usr/src/sys/pdp/mscp_common.h	Thu Feb 25 19:42:19 1999
***************
*** 1,5 ****
  /*
!  *	1.2	(2.11BSD) 1998/2/31
   *
   * Definitions common to both MSCP and TMSCP were moved here from tmscp.h.
   * Eventually the MSCP driver and include file will be modified to use these
--- 1,5 ----
  /*
!  *	1.3	(2.11BSD) 1999/2/25
   *
   * Definitions common to both MSCP and TMSCP were moved here from tmscp.h.
   * Eventually the MSCP driver and include file will be modified to use these
***************
*** 336,344 ****
--- 336,361 ----
  /*
   * Tape Format Flag Values
   */
+ #define	M_TF_MASK	0x00ff	/* Density bits */
+ #define	M_TF_CODE	0x0100	/* Format code multiplier */
  #define	M_TF_800	0x01	/* NRZI 800 bpi */
  #define	M_TF_PE		0x02	/* Phase Encoded 1600 bpi */
  #define	M_TF_GCR	0x04	/* Group Code Recording 6250 bpi */
  #define	M_TF_BLK	0x08	/* Cartridge Block Mode */
+ 
+ #ifdef	notnow
+ /*
+  * Define a few of the common controller and drive types for reference but
+  * don't actually force the preprocessor to handle even more defines.
+ */
+ #define	M_CM_UDA50	2
+ #define	M_CM_TU81	5
+ #define	M_CM_UDA50A	6
+ #define	M_CM_TK50	9
+ #define	M_CM_TQK50	9
+ #define	M_CM_TK70	14
+ #define	M_CM_TQK70	14
+ #define	M_CM_RQDX3	19
+ #endif
  
  #endif	/* _MSCP_COMMON_H_ */
*** /VERSION.old	Thu Dec 31 20:27:01 1998
--- /VERSION	Fri Feb 26 20:09:03 1999
***************
*** 1,5 ****
! Current Patch Level: 408
! Date: December 31, 1998
  
  2.11 BSD
  ============
--- 1,5 ----
! Current Patch Level: 409
! Date: February 26, 1999
  
  2.11 BSD
  ============
