patch-2.1.21 linux/drivers/scsi/ncr53c8xx.c

Next file: linux/drivers/scsi/ncr53c8xx.h
Previous file: linux/drivers/scsi/eata.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.20/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
@@ -40,7 +40,7 @@
 */
 
 /*
-**	26 December 1996, version 1.16b
+**	12 January 1997, version 1.16e
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -368,15 +368,17 @@
 /*
 **	Transfer direction
 **
-**	The middle scsi driver of Linux does not provide the transfer
-**	direction in the command structure.
-**	FreeBsd ncr driver requires this information.
-**
-**	I spent some hours to read the scsi2 documentation to see if
-**	it was possible to deduce the direction of transfer from the opcode
-**	of the command. It seems that it's OK.
-**	guess_xfer_direction() seems to work. If it's wrong we will
-**	get a phase mismatch on some opcode.
+**	Low-level scsi drivers under Linux do not receive the expected 
+**	data transfer direction from upper scsi drivers.
+**	The driver will only check actual data direction for common 
+**	scsi opcodes. Other ones may cause problem, since they may 
+**	depend on device type or be vendor specific.
+**	I would prefer to never trust the device for data direction, 
+**	but that is not possible.
+**
+**	The original driver requires the expected direction to be known.
+**	The Linux version of the driver has been enhanced in order to 
+**	be able to transfer data in the direction choosen by the target. 
 */
 
 #define XferNone	0
@@ -440,6 +442,7 @@
 	unsigned default_tags;
 	unsigned default_sync;
 	unsigned debug;
+	unsigned burst_max;
 } driver_setup = SCSI_NCR_DRIVER_SETUP;
 
 /*
@@ -656,7 +659,8 @@
 #define	SIR_REJECT_SENT		(10)
 #define	SIR_IGN_RESIDUE		(11)
 #define	SIR_MISSING_SAVE	(12)
-#define	SIR_MAX			(12)
+#define	SIR_DATA_IO_IS_OUT	(13)
+#define	SIR_MAX			(13)
 
 /*==========================================================
 **
@@ -1254,6 +1258,14 @@
 	*/
 
 	u_char			tag;
+
+	/*
+	**	Number of segments of the scatter list.
+	**	Used for recalculation of savep/goalp/lastp on 
+	**	SIR_DATA_IO_IS_OUT interrupt.
+	*/
+	
+	u_char			segments;
 };
 
 #define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
@@ -1297,6 +1309,7 @@
 	u_char	sv_dcntl;
 	u_char	sv_ctest3;
 	u_char	sv_ctest4;
+	u_char	sv_ctest5;
 
 	u_char	rv_dmode;
 	u_char	rv_dcntl;
@@ -1544,6 +1557,7 @@
 	ncrcmd	resel_tmp	[  5];
 	ncrcmd  resel_lun	[ 18];
 	ncrcmd	resel_tag	[ 24];
+	ncrcmd  data_io		[  2];	/* MUST be just before data_in */
 	ncrcmd  data_in		[MAX_SCATTER * 4 + 7];
 	ncrcmd  data_out	[MAX_SCATTER * 4 + 7];
 	ncrcmd	aborttag	[  4];
@@ -3088,6 +3102,17 @@
 	SCR_RETURN,
 		0,
 
+}/*-------------------------< DATA_IO >--------------------*/,{
+/*
+**	Because Linux does not provide xfer data direction 
+**	to low-level scsi drivers, we must trust the target 
+**	for actual data direction when we cannot guess it.
+**	The programmed interrupt patches savep, lastp, goalp,
+**	etc.., and restarts the scsi script at data_out.
+*/
+	SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		SIR_DATA_IO_IS_OUT,
+
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
 **	Because the size depends on the
@@ -4149,8 +4174,14 @@
 	**----------------------------------------------------
 	*/
 
+	cp->segments = segments;
+
 	switch (xfer_direction) {
 	default:
+	case XferBoth:
+	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+	     cp->phys.header.goalp = cp->phys.header.savep +8 +20 +segments*16;
+	     break;
 	case XferIn:
 	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
 	     cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
@@ -4470,6 +4501,7 @@
 	OUTB(nc_dcntl,	np->sv_dcntl);
 	OUTB(nc_ctest3,	np->sv_ctest3);
 	OUTB(nc_ctest4,	np->sv_ctest4);
+	OUTB(nc_ctest5,	np->sv_ctest5);
 
 	if (np->uf_doubler) {
 		OUTB(nc_stest1, DBLEN);		/* Enable clock doubler	*/
@@ -4883,6 +4915,46 @@
 	};
 }
 
+/*===============================================================
+**
+**	NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
+**	transfers. 32,64,128 are only supported by 875 chips.
+**	We use log base 2 (burst length) as internal code, with 
+**	value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ *	Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ *	Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+	(ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ *	Set initial io register bits from burst code.
+ */
+static void ncr_init_burst(ncb_p np, u_char bc)
+{
+	np->rv_ctest4	&= ~0x80;
+	np->rv_dmode	&= ~(0x3 << 6);
+	np->rv_ctest5	&= ~0x4;
+
+	if (!bc) {
+		np->rv_ctest4	|= 0x80;
+	}
+	else {
+		--bc;
+		np->rv_dmode	|= ((bc & 0x3) << 6);
+		np->rv_ctest5	|= (bc & 0x4);
+	}
+}
+
 /*==========================================================
 **
 **
@@ -4897,6 +4969,7 @@
 	int	i;
 	u_long	usrsync;
 	u_char	usrwide;
+	u_char	burst_max;
 
 	/*
 	**	Reset chip.
@@ -4938,40 +5011,48 @@
 	np->rv_dcntl	= np->sv_dcntl;
 	np->rv_ctest3	= np->sv_ctest3;
 	np->rv_ctest4	= np->sv_ctest4;
+	np->rv_ctest5	= np->sv_ctest5;
+	burst_max	= burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
 #else
 	np->rv_dmode	= 0;
 	np->rv_dcntl	= 0;
 	np->rv_ctest3	= 0;
 	np->rv_ctest4	= 0;
+	burst_max	= driver_setup.burst_max;
+	if (burst_max == 255)
+		burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+	if (burst_max > 7)
+		burst_max = 7;
 
 /**	NCR53C810			**/
 	if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) {
-		np->rv_dmode	= 0x80;	/* burst length 8 */
+		burst_max	= burst_max < 4 ? burst_max : 4;
 	}
 	else
 /**	NCR53C815			**/
 	if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) {
-		np->rv_dmode	= 0x80;	/* burst length 8 */
+		burst_max	= burst_max < 4 ? burst_max : 4;
 	}
 	else
 /**	NCR53C825			**/
 	if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) {
-		np->rv_dmode	= 0x8a;	/* burst length 8, burst opcode fetch */
+		burst_max	= burst_max < 4 ? burst_max : 4;
+		np->rv_dmode	= 0x0a;	/* burst opcode fetch */
 	}
 	else
 /**	NCR53C810A or NCR53C860		**/
 	if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) ||
 	    ChipDevice == PCI_DEVICE_ID_NCR_53C860) {
 		if (!driver_setup.special_features)
-			np->rv_dmode	= 0xc0;	/* burst length 16 */
+			burst_max	= burst_max < 4 ? burst_max : 4;
 		else {
-			np->rv_dmode	= 0xc0 | BOF | ERMP | ERL;
+			burst_max	= burst_max < 4 ? burst_max : 4;
+			np->rv_dmode	= BOF | ERMP | ERL;
 						/* burst op-code fetch, read multiple */
-						/* read line, burst 16 */
+						/* read line */
 			np->rv_dcntl	= PFEN | CLSE;
 						/* prefetch, cache line size */
 			np->rv_ctest3	= WRIE;	/* write and invalidate */
-			np->rv_ctest4	= 0x0;	/* burst not disabled */
 		}
 	}
 	else
@@ -4979,30 +5060,43 @@
 	if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) ||
 	    ChipDevice == PCI_DEVICE_ID_NCR_53C875) {
 		if (!driver_setup.special_features)
-			np->rv_dmode	= 0xc0;	/* burst length 16 */
+			burst_max	= burst_max < 4 ? burst_max : 4;
 		else {
-			np->rv_dmode	= 0xc0 | BOF | ERMP | ERL;
+			burst_max	= burst_max < 7 ? burst_max : 7;
+			np->rv_dmode	= BOF | ERMP | ERL;
 						/* burst op-code fetch, read multiple */
 						/* read line, burst 128 (ctest5&4) */
 			np->rv_dcntl	= PFEN | CLSE;
 						/* prefetch, cache line size */
 			np->rv_ctest3	= WRIE;	/* write and invalidate */
-			np->rv_ctest4	= 0x0;	/* burst not disabled */
-			np->rv_ctest5	= 0x24;	/* burst 128	(0x04) */
-						/* dma fifo 536	(0x20) */
+			np->rv_ctest5	= 0x20;	/* dma fifo 536 (0x20) */
 		}
 	}
 /**	OTHERS				**/
 	else {
-		np->rv_dmode	= 0xc0;	/* burst length 16 */
+		burst_max	= burst_max < 4 ? burst_max : 4;
 	}
 #endif /* SCSI_NCR_TRUST_BIOS_SETTING */
 
+	/*
+	 *	Prepare initial io register bits for burst length
+	 */
+	ncr_init_burst(np, burst_max);
+
+	if (bootverbose > 1) {
+		printf ("%s: initial value of dmode/ctest4/ctest5 = 0x%02x/0x%02x/0x%02x\n",
+			ncr_name(np), np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+	}
+	if (bootverbose) {
+		printf ("%s: final value of dmode/ctest4/ctest5 = 0x%02x/0x%02x/0x%02x\n",
+			ncr_name(np), np->rv_dmode, np->rv_ctest4, np->rv_ctest5);
+	}
+
 #if 0
-	printf("%s: bios: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x\n",
-		ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4);
-	printf("%s: used: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x\n",
-		ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4);
+	printf("%s: bios: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x, ctest5=0x%02x\n",
+		ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+	printf("%s: used: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x, ctest5=0x%02x\n",
+		ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
 #endif
 
 	OUTB (nc_istat,  0x00   );      /*  Remove Reset, abort ...	     */
@@ -6268,6 +6362,23 @@
 	}
 
 	switch (num) {
+	case SIR_DATA_IO_IS_OUT:
+/*
+**	We did not guess the direction of transfer. We assumed DATA IN,
+**	but the the target drove DATA OUT.
+**	We have to patch the script context with DATA OUT context and 
+**	restart processing at data out script address.
+*/
+		cp->phys.header.savep	= NCB_SCRIPT_PHYS (np, data_out);
+		cp->phys.header.goalp	= cp->phys.header.savep +20 +cp->segments*16;
+		cp->phys.header.lastp	= cp->phys.header.savep;
+		np->header.savep	= cp->phys.header.savep;
+		np->header.goalp	= cp->phys.header.goalp;
+		np->header.lastp	= cp->phys.header.lastp;
+		OUTL (nc_temp,	np->header.savep);
+		OUTL (nc_dsp,	np->header.savep);
+		return;
+		/* break; */
 
 /*--------------------------------------------------------------------
 **
@@ -6492,14 +6603,14 @@
 		/*
 		**	Check against controller limits.
 		**	--------------------------------
-		**	per <= 13  special case, allow fast 20 MHz transfer.
-		**	per <  25  fast 20
+		**	per <  25  fast20
 		**	per <  50  fast
 		**	per < 100  slow
 		**	Use a value p2 twice the controller limit in order to 
 		**	not do wrong integer calculation for 80 MHz clock.
 		**	(12.5x2 = 25ns).
-		**	Compute scntl3&0xf0 sync clock divisor for 50 ns period.
+		**	Compute scntl3&0xf0 sync clock divisor for 50 ns period 
+		**	from the async pre-scaler.
 		**	Ajust it according to actual controller sync period.
 		**	- 0x40 divides it by 4  -> 50/4 = 12.5ns
 		**	- 0x20 divides it by 2  -> 50/2 = 25 ns
@@ -6513,25 +6624,19 @@
 			p2	= 100;
 			scntl3	= (np->rv_scntl3 & 0x07) << 4;
 
-			if (per <= 13) {
-				fak	= 0;
+			if (per < 25) {
+				p2	= 25;
 				scntl3	= (scntl3 - 0x40) | 0x80;
 			}
-			else {
-				if (per < 25) {
-					p2	= 25;
-					scntl3	= (scntl3 - 0x40) | 0x80;
-				}
-				else if (per < 50) {
-					p2	= 50;
-					scntl3	= scntl3 - 0x20;
-				}
+			else if (per < 50) {
+				p2	= 50;
+				scntl3	= scntl3 - 0x20;
+			}
 
-				fak = (8 * per - 1) / p2 - 3;
-				if (fak > 7) {
-					chg = 1;
-					ofs = 0;
-				}
+			fak = (8 * per - 1) / p2 - 3;
+			if (fak > 7) {
+				chg = 1;
+				ofs = 0;
 			}
 		}
 		if (ofs == 0) {
@@ -7654,22 +7759,27 @@
 **		0x04	enable read multiple
 **		0x08	enable read line
 **		0xc0	burst length 16/8/2
-**	DCNTL   0xa0
+**	DCNTL   0xa8
+**		0x08	totem pole irq
 **		0x20	enable pre-fetch
 **		0x80	enable cache line size
 **	CTEST3  0x01
 **		0x01	set write and invalidate
 **	CTEST4  0x80
 **		0x80	burst disabled
+**	CTEST5  0x24
+**		0x20	dma fifo 536		(875 only)
+**		0x04	burst len 32/64/128	(875 only)
 */
 
 static void ncr_save_bios_setting(ncb_p np)
 {
 	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
 	np->sv_dmode	= INB(nc_dmode)  & 0xce;
-	np->sv_dcntl	= INB(nc_dcntl)  & 0xa0;
+	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
 	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
 	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
+	np->sv_ctest5	= INB(nc_ctest5) & 0x24;
 }
 
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
@@ -7750,6 +7860,8 @@
 			driver_setup.verbose	= val;
 		else if	(!strncmp(cur, "debug:", 6))
 			driver_setup.debug	= val;
+		else if	(!strncmp(cur, "burst:", 6))
+			driver_setup.burst_max	= val;
 
 		if ((cur = strchr(cur, ',')) != NULL)
 			++cur;
@@ -7804,12 +7916,13 @@
 
 #define YesNo(y)	y ? 'y' : 'n'
     if (bootverbose >= 2) {
-         printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d\n",
+         printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d\n",
 			 YesNo(driver_setup.disconnection),
 			 YesNo(driver_setup.special_features),
 			 YesNo(driver_setup.ultra_scsi),
 			 driver_setup.default_tags,
-			 driver_setup.default_sync/1000);
+			 driver_setup.default_sync/1000,
+			 driver_setup.burst_max);
          printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x\n",
 			 YesNo(driver_setup.master_parity),
 			 YesNo(driver_setup.scsi_parity),
@@ -8173,13 +8286,7 @@
 #undef next_wcmd
 
 /*
-**	In order to patch the SCSI script for SAVE/RESTORE DATA POINTER,
-**	we need the direction of transfer.
-**	Linux middle-level scsi driver does not provide this information.
-**	So we have to guess it.
-**	My documentation about SCSI-II standard is old. Probably some opcode
-**	are missing.
-**	If I do'nt know the command code, I assume input transfer direction.
+**	Returns data transfer direction for common op-codes.
 */
 
 static int guess_xfer_direction(int opcode)
@@ -8187,111 +8294,31 @@
 	int d;
 
 	switch(opcode) {
-	case 0x00:  /*	TEST UNIT READY			00 */
-	case 0x08:  /*	READ(6)				08 */
 	case 0x12:  /*	INQUIRY				12 */
 	case 0x4D:  /*	LOG SENSE			4D */
 	case 0x5A:  /*	MODE SENSE(10)			5A */
 	case 0x1A:  /*	MODE SENSE(6)			1A */
-	case 0x28:  /*	READ(10)			28 */
-	case 0xA8:  /*	READ(12)			A8 */
 	case 0x3C:  /*	READ BUFFER			3C */
 	case 0x1C:  /*	RECEIVE DIAGNOSTIC RESULTS	1C */
-	case 0xB7:  /*	READ DEFECT DATA(12)		B7 */
-	case 0xB8:  /*	READ ELEMENT STATUS		B8 */
-	            /*	GET WINDOW			25 */
-	case 0x25:  /*	READ CAPACITY			25 */
-	case 0x29:  /*	READ GENERATION			29 */
-	case 0x3E:  /*	READ LONG			3E */
-	            /*	GET DATA BUFFER STATUS		34 */
-	            /*	PRE-FETCH			34 */
-	case 0x34:  /*	READ POSITION			34 */
 	case 0x03:  /*	REQUEST SENSE			03 */
-	case 0x05:  /*	READ BLOCK LIMITS		05 */
-	case 0x0F:  /*	READ REVERSE			0F */
-	case 0x14:  /*	RECOVER BUFFERED DATA		14 */
-	case 0x2D:  /*	READ UPDATED BLOCK		2D */
-	case 0x37:  /*	READ DEFECT DATA(10)		37 */
-	case 0x42:  /*	READ SUB-CHANNEL		42 */
-	case 0x43:  /*	READ TOC			43 */
-	case 0x44:  /*	READ HEADER			44 */
-	case 0xC7:  /*  ???                  ???        C7 */
 		d = XferIn;
 		break;
 	case 0x39:  /*	COMPARE				39 */
 	case 0x3A:  /*	COPY AND VERIFY			3A */
-	            /*	PRINT				0A */
-	            /*	SEND MESSAGE(6)			0A */
-	case 0x0A:  /*	WRITE(6)			0A */
 	case 0x18:  /*	COPY				18 */
 	case 0x4C:  /*	LOG SELECT			4C */
 	case 0x55:  /*	MODE SELECT(10)			55 */
 	case 0x3B:  /*	WRITE BUFFER			3B */
 	case 0x1D:  /*	SEND DIAGNOSTIC			1D */
 	case 0x40:  /*	CHANGE DEFINITION		40 */
-	            /*	SEND MESSAGE(12)		AA */
-	case 0xAA:  /*	WRITE(12)			AA */
-	case 0xB6:  /*	SEND VOLUME TAG			B6 */
-	case 0x3F:  /*	WRITE LONG			3F */
-	case 0x04:  /*	FORMAT UNIT			04 */
-		    /*	INITIALIZE ELEMENT STATUS	07 */
-	case 0x07:  /*	REASSIGN BLOCKS			07 */
 	case 0x15:  /*	MODE SELECT(6)			15 */
-	case 0x24:  /*	SET WINDOW			24 */
-	case 0x2A:  /*	WRITE(10)			2A */
-	case 0x2E:  /*	WRITE AND VERIFY(10)		2E */
-	case 0xAE:  /*	WRITE AND VERIFY(12)		AE */
-	case 0xB0:  /*	SEARCH DATA HIGH(12)		B0 */
-	case 0xB1:  /*	SEARCH DATA EQUAL(12)		B1 */
-	case 0xB2:  /*	SEARCH DATA LOW(12)		B2 */
-	            /*	OBJECT POSITION			31 */
-	case 0x30:  /*	SEARCH DATA HIGH(10)		30 */
-	case 0x31:  /*	SEARCH DATA EQUAL(10)		31 */
-	case 0x32:  /*	SEARCH DATA LOW(10)		32 */
-	case 0x38:  /*	MEDIUM SCAN			38 */
-	case 0x3D:  /*	UPDATE BLOCK			3D */
-	case 0x41:  /*	WRITE SAME			41 */
-	            /*	LOAD UNLOAD			1B */
-	            /*	SCAN				1B */
-	case 0x1B:  /*	START STOP UNIT			1B */
 		d = XferOut;
 		break;
-	case 0x01:  /*	REZERO UNIT			01 */
-	            /*	SEEK(6)				0B */
-	case 0x0B:  /*	SLEW AND PRINT			0B */
-	            /*	SYNCHRONIZE BUFFER		10 */
-	case 0x10:  /*	WRITE FILEMARKS			10 */
-	case 0x11:  /*	SPACE				11 */
-	case 0x13:  /*	VERIFY				13 */
-	case 0x16:  /*	RESERVE UNIT			16 */
-	case 0x17:  /*	RELEASE UNIT			17 */
-	case 0x19:  /*	ERASE				19 */
-	            /*	LOCATE				2B */
-	            /*	POSITION TO ELEMENT		2B */
-	case 0x2B:  /*	SEEK(10)			2B */
-	case 0x1E:  /*	PREVENT ALLOW MEDIUM REMOVAL	1E */
-	case 0x2C:  /*	ERASE(10)			2C */
-	case 0xAC:  /*	ERASE(12)			AC */
-	case 0x2F:  /*	VERIFY(10)			2F */
-	case 0xAF:  /*	VERIFY(12)			AF */
-	case 0x33:  /*	SET LIMITS(10)			33 */
-	case 0xB3:  /*	SET LIMITS(12)			B3 */
-	case 0x35:  /*	SYNCHRONIZE CACHE		35 */
-	case 0x36:  /*	LOCK UNLOCK CACHE		36 */
-	case 0x45:  /*	PLAY AUDIO(10)			45 */
-	case 0x47:  /*	PLAY AUDIO MSF			47 */
-	case 0x48:  /*	PLAY AUDIO TRACK/INDEX		48 */
-	case 0x49:  /*	PLAY TRACK RELATIVE(10)		49 */
-	case 0xA9:  /*	PLAY TRACK RELATIVE(12)		A9 */
-	case 0x4B:  /*	PAUSE/RESUME			4B */
-	            /*	MOVE MEDIUM			A5 */
-	case 0xA5:  /*	PLAY AUDIO(12)			A5 */
-	case 0xA6:  /*	EXCHANGE MEDIUM			A6 */
-	case 0xB5:  /*	REQUEST VOLUME ELEMENT ADDRESS	B5 */
+	case 0x00:  /*	TEST UNIT READY			00 */
 		d = XferNone;
 		break;
 	default:
-		d = XferIn;
+		d = XferBoth;
 		break;
 	}
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov