From fredriks@mcs.com  Fri May 24 08:43:23 1996
Received: from fredriks.pr.mcs.net (fredriks.pr.mcs.net [199.3.36.197])
          by freefall.freebsd.org (8.7.3/8.7.3) with ESMTP id IAA20619
          for <FreeBSD-gnats-submit@freebsd.org>; Fri, 24 May 1996 08:43:18 -0700 (PDT)
Received: (from fredriks@localhost) by fredriks.pr.mcs.net (8.7.5/8.6.6) id KAA18414; Fri, 24 May 1996 10:43:35 -0500 (CDT)
Message-Id: <199605241543.KAA18414@fredriks.pr.mcs.net>
Date: Fri, 24 May 1996 10:43:35 -0500 (CDT)
From: fredriks@mcs.com
Reply-To: fredriks@mcs.com
To: FreeBSD-gnats-submit@freebsd.org
Subject: scsi tape driver write-protect and eject handling is broken
X-Send-Pr-Version: 3.2

>Number:         1245
>Category:       kern
>Synopsis:       scsi tape driver write-protet and eject handling is broken
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri May 24 08:50:01 PDT 1996
>Closed-Date:    Sun Jun 23 21:51:53 PDT 1996
>Last-Modified:  Sun Jun 23 21:56:22 PDT 1996
>Originator:     & Fredriksen
>Release:        FreeBSD 2.2-CURRENT i386
>Organization:
Flaaklypa Hackers
>Environment:

	FreeBSD 2.2-CURRENT as of 5/23/96 (sup & compile)

>Description:
	Tape device driver does not eject, nor report write-protect properly.
	
	ecject: 
		The problem with eject is that there are devices out there,
		that will not eject if the device has been reserved. The
		current st.c reserves the device upon open and releases it
		upon close. However the release happens after the unload,
		so the eject will not occur. Also if you issue a 
			mt -f /dev/rstx offline
		command that will not eject either, since no release happens.

		The fix included below, fixes both of these problems.

	write-protect detection:
		The scsi tape driver registers its own error handling 
		routine that gets called when the device returns an
		error. This routine checks for the Filemark, End of Medium
		and Illegal Length Indicator bits to be set, and if they
		are and there are bytes left to be written to tape you
		get an EIO back. This routine needs to check for sense-key
		of 0x7 (Data Protect) first. The Exabyte 8500 sets the
		EOM bit (which is probably a bug on their part). Checking
		for sense-key of 0x7 should by-pass these kinds of bugs
		and accurately detect write-protected medium on all drives.

	density codes:
		Added density code for the Exabyte 8200, 8200C, 8500 and 8500C.
		These where patches that Eric J. Haug (ejh@eas.slu.edu)
		posted on current for the Exabyte 8505. 

>How-To-Repeat:
>Fix:


Index: scsiconf.h
===================================================================
RCS file: /home/ncvs/src/sys/scsi/scsiconf.h,v
retrieving revision 1.41
diff -r1.41 scsiconf.h
234c234
< /*  7*/	char    density;
---
> /*  7*/	u_int8_t  density;
549a550,553
> #define EXB_8200	0x14
> #define EXB_8500	0x15
> #define EXB_8200C	0x8c
> #define EXB_8500C	0x90
Index: st.c
===================================================================
RCS file: /home/ncvs/src/sys/scsi/st.c,v
retrieving revision 1.68
diff -r1.68 st.c
71c71,74
< #define SCSI_2_MAX_DENSITY_CODE	0x17	/* maximum density code specified
---
> #ifdef	EXB_8500C
> #	define SCSI_2_MAX_DENSITY_CODE	EXB_8500C	
> #else
> #	define SCSI_2_MAX_DENSITY_CODE	0x17	/* maximum density code specified
72a76
> #endif
498a503,509
> 
> 		/* has to happen before the unload, otherwise media will
> 		 * not be ejected when the EJECT flag is given.
> 		 */
> 
> 	scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
> 
513d523
< 	scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
1113a1124,1126
> 					/* Some devices will not eject unless*/
> 					/* the device gets released first */
> 				scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
1147a1161
> 					goto try_new_value;
1149d1162
< 				goto try_new_value;
1817c1830,1834
< 	if ((sense->error_code & SSD_ERRCODE) != 0x70) {
---
> 	key = sense->ext.extended.flags & SSD_KEY;
> 
> 	if ((sense->error_code & SSD_ERRCODE) != 0x70 || key == 0x7) {
> 					/* we want the generic code to hadle */
> 					/* write protect too */
1819a1837,1838
> 
> 
1893d1911
< 	key = sense->ext.extended.flags & SSD_KEY;
>Release-Note:
>Audit-Trail:

From: Lars Fredriksen <fredriks@mcs.com>
To: FreeBSD-gnats-submit@FreeBSD.org
Cc:  Subject: Re: kern/1245: scsi tape driver write-protect and eject handling is broken
Date: Sat, 25 May 1996 12:29:59 -0500 (CDT)

 Hi, 
 	Here are the context diffs. J"oerg was nice enough to point out
 that I hadn't submitted context diffs. If someone is willing to review
 these changes (Peter?), then I can submit them if that eases the load
 on people.
 
 Lars
 
 
 Index: scsiconf.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/scsi/scsiconf.h,v
 retrieving revision 1.41
 diff -c -r1.41 scsiconf.h
 *** scsiconf.h	1996/03/31 03:19:09	1.41
 --- scsiconf.h	1996/03/31 11:00:34
 ***************
 *** 231,237 ****
   struct st_mode {
   /*  4*/	u_int32_t blksiz;
   /*  6*/	u_int16_t quirks;		/* same definitions as in XXX */
 ! /*  7*/	char    density;
   /*  8*/	char    spare[1];
   };
   
 --- 231,237 ----
   struct st_mode {
   /*  4*/	u_int32_t blksiz;
   /*  6*/	u_int16_t quirks;		/* same definitions as in XXX */
 ! /*  7*/	u_int8_t  density;
   /*  8*/	char    spare[1];
   };
   
 ***************
 *** 547,552 ****
 --- 547,556 ----
   #define QIC_1320	0x12
   #define DDS		0x13
   #define DAT_1		0x13
 + #define EXB_8200	0x14
 + #define EXB_8500	0x15
 + #define EXB_8200C	0x8c
 + #define EXB_8500C	0x90
   #define	QIC_3080	0x29
   
   
 
 Index: st.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/scsi/st.c,v
 retrieving revision 1.68
 diff -c -r1.68 st.c
 *** st.c	1996/04/02 04:54:26	1.68
 --- st.c	1996/05/24 15:31:39
 ***************
 *** 68,75 ****
   
   #define IS_CTLMODE(DEV) (MODE(DEV) == CTLMODE)
   
 ! #define SCSI_2_MAX_DENSITY_CODE	0x17	/* maximum density code specified
   					 * in SCSI II spec. */
   
   static errval	st_space __P((u_int32_t unit, int32_t number, u_int32_t what, u_int32_t flags));
   static errval	st_rewind __P((u_int32_t unit, boolean immed, u_int32_t flags));
 --- 68,79 ----
   
   #define IS_CTLMODE(DEV) (MODE(DEV) == CTLMODE)
   
 ! #ifdef	EXB_8500C
 ! #	define SCSI_2_MAX_DENSITY_CODE	EXB_8500C	
 ! #else
 ! #	define SCSI_2_MAX_DENSITY_CODE	0x17	/* maximum density code specified
   					 * in SCSI II spec. */
 + #endif
   
   static errval	st_space __P((u_int32_t unit, int32_t number, u_int32_t what, u_int32_t flags));
   static errval	st_rewind __P((u_int32_t unit, boolean immed, u_int32_t flags));
 ***************
 *** 496,501 ****
 --- 500,512 ----
   
   	if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
   		st_write_filemarks(unit, 1, 0);
 + 
 + 		/* has to happen before the unload, otherwise media will
 + 		 * not be ejected when the EJECT flag is given.
 + 		 */
 + 
 + 	scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
 + 
   	switch (mode & 0x3) {
   	case 0:
   	case 3:		/* for now */
 ***************
 *** 510,516 ****
   		st_unmount(unit, EJECT);
   		break;
   	}
 - 	scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
   
   	sc_link->flags &= ~SDEV_OPEN;
   	st->flags &= ~ST_OPEN;
 --- 521,526 ----
 ***************
 *** 1111,1116 ****
 --- 1121,1129 ----
   						  flags);
   				break;
   			case MTOFFL:	/* rewind and put the drive offline */
 + 					/* Some devices will not eject unless*/
 + 					/* the device gets released first */
 + 				scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
   				st_unmount(unit, EJECT);
   				break;
   			case MTNOP:	/* no operation, sets status only */
 ***************
 *** 1145,1152 ****
   					errcode = EINVAL;
   				} else {
   					st->density = number;
   				}
 - 				goto try_new_value;
   
   			case MTCOMP:	/* enable default compression */
   				errcode = st_comp(unit,number);
 --- 1158,1165 ----
   					errcode = EINVAL;
   				} else {
   					st->density = number;
 + 					goto try_new_value;
   				}
   
   			case MTCOMP:	/* enable default compression */
   				errcode = st_comp(unit,number);
 ***************
 *** 1814,1822 ****
   			info = xs->datalen;
   		}
   	}
 ! 	if ((sense->error_code & SSD_ERRCODE) != 0x70) {
   		return SCSIRET_CONTINUE;/* let the generic code handle it */
   	}
   	if(sense->ext.extended.flags & (SSD_EOM|SSD_FILEMARK|SSD_ILI)) {
   		if (st->flags & ST_FIXEDBLOCKS) {
   			xs->resid = info * st->blksiz;
 --- 1827,1841 ----
   			info = xs->datalen;
   		}
   	}
 ! 	key = sense->ext.extended.flags & SSD_KEY;
 ! 
 ! 	if ((sense->error_code & SSD_ERRCODE) != 0x70 || key == 0x7) {
 ! 					/* we want the generic code to hadle */
 ! 					/* write protect too */
   		return SCSIRET_CONTINUE;/* let the generic code handle it */
   	}
 + 
 + 
   	if(sense->ext.extended.flags & (SSD_EOM|SSD_FILEMARK|SSD_ILI)) {
   		if (st->flags & ST_FIXEDBLOCKS) {
   			xs->resid = info * st->blksiz;
 ***************
 *** 1890,1896 ****
   		}
   		return 0;
   	}
 - 	key = sense->ext.extended.flags & SSD_KEY;
   
   	if (key == 0x8) {
   		xs->flags |= SCSI_EOF; /* some drives need this */
 --- 1909,1914 ----
State-Changed-From-To: open->closed 
State-Changed-By: gibbs 
State-Changed-When: Sun Jun 23 21:51:53 PDT 1996 
State-Changed-Why:  
Suggested fix applied with some changes to scsiconf.h v1.44 and 
st.c v1.70.  The main difference is that we no longer rely on a 
hard coded maximum density and instead allow the device to report 
invalid requests for us. 
>Unformatted:
 >Repeat-By:
 	With an Exabyte 8500 tape drive:
 
 	mt -f /dev/rst2 offline
 		should eject the tape, but doesn't
 
 	tar -tvf /dev/erst2
 		should eject the tape upon close, but doesn't
 	tar -cvf /dev/rstx and have a write protected cartridge in the
 	device. You will get EIO instead of EACCESS.
