Subject: kern/34832: Implement mode-select for ATAPI tape drives
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <paul@whooppee.com>
List: netbsd-bugs
Date: 10/16/2006 07:15:00
>Number:         34832
>Category:       kern
>Synopsis:       Implement mode-select for ATAPI tape drives
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Oct 16 07:15:00 +0000 2006
>Originator:     Paul Goyette
>Release:        NetBSD 4.99.3
>Organization:
----------------------------------------------------------------------
|   Paul Goyette   | PGP DSS Key fingerprint: |  E-mail addresses:   |
| Network Engineer | FA29 0E3B 35AF E8AE 6651 |  paul@whooppee.com   |
|                  | 0786 F758 55DE 53BA 7731 | pgoyette@juniper.net |
----------------------------------------------------------------------
>Environment:
	
	
System: NetBSD quicky.whooppee.com 4.99.3 NetBSD 4.99.3 (Quicky-A8N5X) #14: Sun Oct 15 19:25:19 PDT 2006 paul@quicky.whooppee.com:/usr/obj/sys/arch/amd64/compile.amd64/QUICKY amd64
Architecture: x86_64
Machine: amd64
>Description:
	Useful to implement mode-select for ATAPI tape drives that support multi blocksizes
>How-To-Repeat:
	N/A
>Fix:
The following diffs implement an ATAPI mode_select function that is 
adequate to set the drive's block size.  Tested with Seagate STT3401A
Travan-TR40 tape drive which supports both 512 and 1024 byte blocks.

Index: sys/dev/scsipi/st.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/st.c,v
retrieving revision 1.193
diff -u -p -r1.193 st.c
--- sys/dev/scsipi/st.c	12 Oct 2006 01:31:58 -0000	1.193
+++ sys/dev/scsipi/st.c	16 Oct 2006 04:50:14 -0000
@@ -316,6 +316,13 @@ static const struct st_quirk_inquiry_pat
 		{0, 0, 0},			       /* minor 8-11 */
 		{0, 0, 0}			       /* minor 12-15 */
 	}}},
+	{{T_SEQUENTIAL, T_REMOV,
+	 "Seagate STT3401A", "hp0atxa", ""},	{ST_Q_ATAPI_MODESEL, 0, {
+		{ST_Q_FORCE_BLKSIZE, 512, 0},		/* minor 0-3 */
+		{ST_Q_FORCE_BLKSIZE, 1024, 0},		/* minor 4-7 */
+		{ST_Q_FORCE_BLKSIZE, 512, 0},		/* minor 8-11 */
+		{ST_Q_FORCE_BLKSIZE, 512, 0}		/* minor 12-15 */
+	}}},
 };
 
 #define NOEJECT 0
Index: sys/dev/scsipi/st_atapi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/st_atapi.c,v
retrieving revision 1.19
diff -u -p -r1.19 st_atapi.c
--- sys/dev/scsipi/st_atapi.c	12 Oct 2006 01:31:58 -0000	1.19
+++ sys/dev/scsipi/st_atapi.c	16 Oct 2006 04:50:14 -0000
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: st_atapi.c,v
 
 #include <dev/scsipi/stvar.h>
 #include <dev/scsipi/atapi_tape.h>
+#include <dev/scsipi/scsi_spc.h>
 
 static int	st_atapibus_match(struct device *, struct cfdata *, void *);
 static void	st_atapibus_attach(struct device *, struct device *, void *);
@@ -177,8 +178,41 @@ st_atapibus_mode_sense(struct st_softc *
 	return error;
 }
 
+/*
+ * Send a filled out parameter structure to the drive to
+ * set it into the desire modes etc.
+ */
 static int
-st_atapibus_mode_select(struct st_softc *st __unused, int flags __unused)
+st_atapibus_mode_select(struct st_softc *st, int flags)
 {
-	return ENODEV; /* for now ... */
+	u_int atapi_select_len;
+	struct atapi_select {
+		struct scsi_mode_parameter_header_6  header;
+		struct scsi_general_block_descriptor blk_desc;
+		u_char sense_data[MAX_PAGE_0_SIZE];
+	} atapi_select;
+	struct scsipi_periph *periph = st->sc_periph;
+
+	if (!(st->quirkdata->quirks & ST_Q_ATAPI_MODESEL))
+		return ENODEV;
+
+	atapi_select_len = 12 + st->page_0_size;
+
+	/*
+	 * Set up for a mode select
+	 */
+	memset(&atapi_select, 0, atapi_select_len);
+	atapi_select.header.blk_desc_len = sizeof(struct scsi_general_block_descriptor);
+	atapi_select.blk_desc.density = st->density;
+	if (st->flags & ST_FIXEDBLOCKS)
+		_lto3b(st->blksize, atapi_select.blk_desc.blklen);
+	if (st->page_0_size)
+		memcpy(atapi_select.sense_data, st->sense_data, st->page_0_size);
+
+	/*
+	 * do the command
+	 */
+	return scsipi_mode_select(periph, 0, &atapi_select.header,
+	    atapi_select_len, flags | XS_CTL_DATA_ONSTACK,
+	    ST_RETRIES, ST_CTL_TIME);
 }
Index: sys/dev/scsipi/stvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/stvar.h,v
retrieving revision 1.17
diff -u -p -r1.17 stvar.h
--- sys/dev/scsipi/stvar.h	14 Apr 2006 13:09:06 -0000	1.17
+++ sys/dev/scsipi/stvar.h	16 Oct 2006 04:50:14 -0000
@@ -86,6 +86,7 @@ struct quirkdata {
 #define	ST_Q_NOPREVENT		0x0020	/* does not support PREVENT */
 #define	ST_Q_ERASE_NOIMM	0x0040	/* drive rejects ERASE/w Immed bit */
 #define	ST_Q_NOFILEMARKS	0x0080	/* can only write 0 filemarks */
+#define	ST_Q_ATAPI_MODESEL	0x0100	/* ATAPI drive does SCSI Mode Select */
 	u_int page_0_size;
 #define	MAX_PAGE_0_SIZE	64
 	struct modes modes[4];

>Unformatted: