LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
@ 2008-03-08 17:32 matthieu castet
  2008-03-08 18:31 ` Matthew Dharm
  0 siblings, 1 reply; 14+ messages in thread
From: matthieu castet @ 2008-03-08 17:32 UTC (permalink / raw)
  To: linux-usb; +Cc: Linux Kernel list

Hi,

I have got a cypress usb-ide bridge and I would like to tune or monitor
my disk with tools like hdparm, hddtemp or smartctl.

My controller support a way to send raw ATA command to the disk with
something call atacb (see
http://download.cypress.com.edgesuite.net/design_resources/datasheets/contents/cy7c68300c_8.pdf).

Atacb support can be added for each application, but there is some 
disadvantages :
- all application need to be patched
- A race is possible if there other accesses, because the emulation can
be split in 2 atacb scsi transactions. One for sending the command, one
for reading the register (if ck_cond is set).

I have implemented the emulation in usb-storage with a special 
proto_handler,
and an unsual entry.

Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>

Index: linux-2.6.24.2/drivers/usb/storage/protocol.c
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/protocol.c	2008-02-29 
22:14:09.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/protocol.c	2008-03-08 
18:18:22.000000000 +0100
@@ -47,6 +47,8 @@
  #include <linux/highmem.h>
  #include <scsi/scsi.h>
  #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>

  #include "usb.h"
  #include "protocol.h"
@@ -144,6 +146,179 @@
  	usb_stor_invoke_transport(srb, us);
  }

+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+static void emulate_pass_thru_with_atacb(struct scsi_cmnd *srb,
+				       struct us_data *us)
+{
+	unsigned char save_cmnd[MAX_COMMAND_SIZE];
+	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+	memset(srb->cmnd, 0, sizeof(srb->cmnd));
+
+	/* check if we support the command */
+	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+		goto invalid_fld;
+	/* check protocol */
+	switch((save_cmnd[1] >> 1) & 0xf) {
+		case 3:
+		case 4:
+		case 5:
+			break;
+		default:
+			goto invalid_fld;
+	}
+
+	/* first build the ATACB command */
+	srb->cmd_len = 16;
+
+ 	/* this value can change, but most(all ?) manufacturers keep the cypress
+	 * default : 0x24
+	 */
+	srb->cmnd[0] = 0x24;
+	srb->cmnd[1] = 0x24;
+	srb->cmnd[2] = 0;
+
+	srb->cmnd[3] = 0xff - 1;
+	srb->cmnd[4] = 1;
+
+	if (save_cmnd[0] == ATA_16) {
+		srb->cmnd[6] = save_cmnd[4]; /* features */
+		srb->cmnd[7] = save_cmnd[6]; /* sector count */
+		srb->cmnd[8] = save_cmnd[8]; /* lba low */
+		srb->cmnd[9] = save_cmnd[10]; /* lba med */
+		srb->cmnd[10] = save_cmnd[12]; /* lba high */
+		srb->cmnd[11] = save_cmnd[13]; /* device */
+		srb->cmnd[12] = save_cmnd[14]; /* command */
+
+		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+			/* this could be supported by atacb2 */
+			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+					|| save_cmnd[11])
+				goto invalid_fld;
+		}
+	}
+	else { /* ATA12 */
+		srb->cmnd[6] = save_cmnd[3]; /* features */
+		srb->cmnd[7] = save_cmnd[4]; /* sector count */
+		srb->cmnd[8] = save_cmnd[5]; /* lba low */
+		srb->cmnd[9] = save_cmnd[6]; /* lba med */
+		srb->cmnd[10] = save_cmnd[7]; /* lba high */
+		srb->cmnd[11] = save_cmnd[8]; /* device */
+		srb->cmnd[12] = save_cmnd[9]; /* command */
+
+	}
+	/* Filter SET_FEATURES - XFER MODE command */
+	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+			&& (srb->cmnd[6] == SETFEATURES_XFER))
+		goto invalid_fld;
+
+	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+		srb->cmnd[2] |= (1<<7);
+
+
+	usb_stor_invoke_transport(srb, us);
+
+	/* if the device doesn't support ATACB
+	 * abort and register usb_stor_transparent_scsi_command
+	 * callback
+	 */
+	if (srb->result == SAM_STAT_CHECK_CONDITION &&
+			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+				sizeof(usb_stor_sense_invalidCDB)) == 0) {
+		us->proto_handler = usb_stor_transparent_scsi_command;
+		goto end;
+	}
+
+	/* if ck_cond flags is set, and there wasn't critical error,
+	 * build the special sense
+	 */
+	if ((srb->result != (DID_ERROR << 16) &&
+				srb->result != (DID_ABORT << 16)) &&
+			save_cmnd[2] & 0x20) {
+		struct scsi_eh_save ses;
+		unsigned char sk, asc, ascq;
+		unsigned char regs[8];
+		unsigned char *sb = srb->sense_buffer;
+		unsigned char *desc = sb + 8;
+		int tmp_result;
+
+		sk = RECOVERED_ERROR;
+		asc = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+		ascq = 0x1D;
+
+		/* read registers */
+		srb->cmnd[2] = 1;
+		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
+		srb->request_buffer = regs;
+		srb->request_bufflen = sizeof(regs);
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+
+		usb_stor_invoke_transport(srb, us);
+		tmp_result = srb->result;
+		scsi_eh_restore_cmnd(srb, &ses);
+		/* we fail to get registers, report invalid command */
+		if (tmp_result != SAM_STAT_GOOD)
+			goto invalid_fld;
+
+		/* build the sense */
+		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+		/* XXX we should generate sk, asc, ascq from status and error
+		 * regs
+		 * (see 11.1 Error translation ­ ATA device error to SCSI error map)
+		 * and ata_to_sense_error from libata.
+		 */
+		sb[1] = sk;
+		sb[2] = asc;
+		sb[3] = ascq;
+
+		/* Sense data is current and format is descriptor. */
+		sb[0] = 0x72;
+		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+		/* set length of additional sense data */
+		sb[7] = 14;
+		desc[1] = 12;
+
+		/* Copy registers into sense buffer. */
+		desc[2] = 0x00;
+		desc[3] = regs[1];
+		desc[5] = regs[2];
+		desc[7] = regs[3];
+		desc[9] = regs[4];
+		desc[11] = regs[5];
+		desc[12] = regs[6];
+		desc[13] = regs[7];
+
+		srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+	}
+	goto end;
+invalid_fld:
+	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+	memcpy(srb->sense_buffer,
+			usb_stor_sense_invalidCDB,
+			sizeof(usb_stor_sense_invalidCDB));
+end:
+	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+	if (srb->cmnd[0] == ATA_12)
+		srb->cmd_len = 12;
+}
+
+void usb_stor_transparent_scsi_command_atacb(struct scsi_cmnd *srb,
+				       struct us_data *us)
+{
+	if (srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)
+		usb_stor_invoke_transport(srb, us);
+	else
+		emulate_pass_thru_with_atacb(srb, us);
+}
+
  /***********************************************************************
   * Scatter-gather transfer buffer access routines
   ***********************************************************************/
Index: linux-2.6.24.2/drivers/usb/storage/initializers.c
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/initializers.c	2008-02-29 
22:14:09.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/initializers.c	2008-03-08 
18:30:00.000000000 +0100
@@ -43,6 +43,7 @@
  #include "initializers.h"
  #include "debug.h"
  #include "transport.h"
+#include "protocol.h"

  /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
   * mode */
@@ -104,3 +105,11 @@
  	US_DEBUGP("usb_control_msg performing result is %d\n", result);
  	return (result ? 0 : -1);
  }
+
+/* This function register the atacb proto callback */
+int usb_atacb_init(struct us_data *us)
+{
+	us->proto_handler = usb_stor_transparent_scsi_command_atacb;
+	US_DEBUGP("atacb proto_handler is set\n");
+	return 0;
+}
Index: linux-2.6.24.2/drivers/usb/storage/initializers.h
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/initializers.h	2008-02-29 
22:14:09.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/initializers.h	2008-03-08 
18:28:33.000000000 +0100
@@ -50,3 +50,6 @@

  /* This places the HUAWEI E220 devices in multi-port mode */
  int usb_stor_huawei_e220_init(struct us_data *us);
+
+/* This function register the atacb proto callback */
+int usb_atacb_init(struct us_data *us);
Index: linux-2.6.24.2/drivers/usb/storage/protocol.h
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/protocol.h	2008-02-29 
22:14:09.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/protocol.h	2008-02-29 
22:16:03.000000000 +0100
@@ -47,6 +47,8 @@
  extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*);
  extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
  		struct us_data*);
+extern void usb_stor_transparent_scsi_command_atacb(struct scsi_cmnd*,
+		struct us_data*);

  /* struct scsi_cmnd transfer buffer access utilities */
  enum xfer_buf_dir	{TO_XFER_BUF, FROM_XFER_BUF};
Index: linux-2.6.24.2/drivers/usb/storage/unusual_devs.h
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/unusual_devs.h	2008-02-29 
22:14:09.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/unusual_devs.h	2008-02-29 
22:16:03.000000000 +0100
@@ -1588,6 +1588,12 @@
  		US_SC_DEVICE, US_PR_DEVICE, NULL,
  		US_FL_CAPACITY_HEURISTICS),

+UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress AT2LP",
+		US_SC_SCSI, US_PR_BULK, usb_atacb_init,
+		US_FL_NEED_OVERRIDE),
+
  /* Control/Bulk transport for all SubClass values */
  USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
  USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-08 17:32 [PATCH] mass storage : emulation of sat scsi_pass_thru with ATACB matthieu castet
@ 2008-03-08 18:31 ` Matthew Dharm
  2008-03-08 20:08   ` matthieu castet
  2008-03-09 10:13   ` [PATCH] mass storage : emulation of sat scsi_pass_thru with ATACB Alan Cox
  0 siblings, 2 replies; 14+ messages in thread
From: Matthew Dharm @ 2008-03-08 18:31 UTC (permalink / raw)
  To: matthieu castet; +Cc: linux-usb, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 11432 bytes --]

Why are you using an initializer instead of a new protocol code?

Most of this should probably be moved into it's own file, just like all of
the other protocol handlers.

Actually, why do you even have a separate 'dispatcher' function?  Why not
just one protocol handler function which checks the command at the top and
calls invoke_transport there?

Also, unless ATACB is a new standard (and I don't think it is, as the
Cypress datasheet uses the term 'vendor specific'), then your functions
need renaming.  Instead of 'emulate_pass_thru_with_atacb', how about
something like 'cypress_atacb' --  since it's already a protocol handler,
everyone already knows it's for passing commands.

Matt

On Sat, Mar 08, 2008 at 06:32:05PM +0100, matthieu castet wrote:
> Hi,
> 
> I have got a cypress usb-ide bridge and I would like to tune or monitor
> my disk with tools like hdparm, hddtemp or smartctl.
> 
> My controller support a way to send raw ATA command to the disk with
> something call atacb (see
> http://download.cypress.com.edgesuite.net/design_resources/datasheets/contents/cy7c68300c_8.pdf).
> 
> Atacb support can be added for each application, but there is some 
> disadvantages :
> - all application need to be patched
> - A race is possible if there other accesses, because the emulation can
> be split in 2 atacb scsi transactions. One for sending the command, one
> for reading the register (if ck_cond is set).
> 
> I have implemented the emulation in usb-storage with a special 
> proto_handler,
> and an unsual entry.
> 
> Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>
> 
> Index: linux-2.6.24.2/drivers/usb/storage/protocol.c
> ===================================================================
> --- linux-2.6.24.2.orig/drivers/usb/storage/protocol.c	2008-02-29 
> 22:14:09.000000000 +0100
> +++ linux-2.6.24.2/drivers/usb/storage/protocol.c	2008-03-08 
> 18:18:22.000000000 +0100
> @@ -47,6 +47,8 @@
>  #include <linux/highmem.h>
>  #include <scsi/scsi.h>
>  #include <scsi/scsi_cmnd.h>
> +#include <scsi/scsi_eh.h>
> +#include <linux/ata.h>
> 
>  #include "usb.h"
>  #include "protocol.h"
> @@ -144,6 +146,179 @@
>  	usb_stor_invoke_transport(srb, us);
>  }
> 
> +/*
> + * ATACB is a protocol used on cypress usb<->ata bridge to
> + * send raw ATA command over mass storage
> + * There is a ATACB2 protocol that support LBA48 on newer chip.
> + * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
> + * datasheet from cypress.com.
> + */
> +static void emulate_pass_thru_with_atacb(struct scsi_cmnd *srb,
> +				       struct us_data *us)
> +{
> +	unsigned char save_cmnd[MAX_COMMAND_SIZE];
> +	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
> +	memset(srb->cmnd, 0, sizeof(srb->cmnd));
> +
> +	/* check if we support the command */
> +	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
> +		goto invalid_fld;
> +	/* check protocol */
> +	switch((save_cmnd[1] >> 1) & 0xf) {
> +		case 3:
> +		case 4:
> +		case 5:
> +			break;
> +		default:
> +			goto invalid_fld;
> +	}
> +
> +	/* first build the ATACB command */
> +	srb->cmd_len = 16;
> +
> + 	/* this value can change, but most(all ?) manufacturers keep the 
> cypress
> +	 * default : 0x24
> +	 */
> +	srb->cmnd[0] = 0x24;
> +	srb->cmnd[1] = 0x24;
> +	srb->cmnd[2] = 0;
> +
> +	srb->cmnd[3] = 0xff - 1;
> +	srb->cmnd[4] = 1;
> +
> +	if (save_cmnd[0] == ATA_16) {
> +		srb->cmnd[6] = save_cmnd[4]; /* features */
> +		srb->cmnd[7] = save_cmnd[6]; /* sector count */
> +		srb->cmnd[8] = save_cmnd[8]; /* lba low */
> +		srb->cmnd[9] = save_cmnd[10]; /* lba med */
> +		srb->cmnd[10] = save_cmnd[12]; /* lba high */
> +		srb->cmnd[11] = save_cmnd[13]; /* device */
> +		srb->cmnd[12] = save_cmnd[14]; /* command */
> +
> +		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
> +			/* this could be supported by atacb2 */
> +			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || 
> save_cmnd[9]
> +					|| save_cmnd[11])
> +				goto invalid_fld;
> +		}
> +	}
> +	else { /* ATA12 */
> +		srb->cmnd[6] = save_cmnd[3]; /* features */
> +		srb->cmnd[7] = save_cmnd[4]; /* sector count */
> +		srb->cmnd[8] = save_cmnd[5]; /* lba low */
> +		srb->cmnd[9] = save_cmnd[6]; /* lba med */
> +		srb->cmnd[10] = save_cmnd[7]; /* lba high */
> +		srb->cmnd[11] = save_cmnd[8]; /* device */
> +		srb->cmnd[12] = save_cmnd[9]; /* command */
> +
> +	}
> +	/* Filter SET_FEATURES - XFER MODE command */
> +	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
> +			&& (srb->cmnd[6] == SETFEATURES_XFER))
> +		goto invalid_fld;
> +
> +	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == 
> ATA_CMD_ID_ATAPI)
> +		srb->cmnd[2] |= (1<<7);
> +
> +
> +	usb_stor_invoke_transport(srb, us);
> +
> +	/* if the device doesn't support ATACB
> +	 * abort and register usb_stor_transparent_scsi_command
> +	 * callback
> +	 */
> +	if (srb->result == SAM_STAT_CHECK_CONDITION &&
> +			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
> +				sizeof(usb_stor_sense_invalidCDB)) == 0) {
> +		us->proto_handler = usb_stor_transparent_scsi_command;
> +		goto end;
> +	}
> +
> +	/* if ck_cond flags is set, and there wasn't critical error,
> +	 * build the special sense
> +	 */
> +	if ((srb->result != (DID_ERROR << 16) &&
> +				srb->result != (DID_ABORT << 16)) &&
> +			save_cmnd[2] & 0x20) {
> +		struct scsi_eh_save ses;
> +		unsigned char sk, asc, ascq;
> +		unsigned char regs[8];
> +		unsigned char *sb = srb->sense_buffer;
> +		unsigned char *desc = sb + 8;
> +		int tmp_result;
> +
> +		sk = RECOVERED_ERROR;
> +		asc = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
> +		ascq = 0x1D;
> +
> +		/* read registers */
> +		srb->cmnd[2] = 1;
> +		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
> +		srb->request_buffer = regs;
> +		srb->request_bufflen = sizeof(regs);
> +		srb->sc_data_direction = DMA_FROM_DEVICE;
> +
> +		usb_stor_invoke_transport(srb, us);
> +		tmp_result = srb->result;
> +		scsi_eh_restore_cmnd(srb, &ses);
> +		/* we fail to get registers, report invalid command */
> +		if (tmp_result != SAM_STAT_GOOD)
> +			goto invalid_fld;
> +
> +		/* build the sense */
> +		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
> +
> +		/* XXX we should generate sk, asc, ascq from status and error
> +		 * regs
> +		 * (see 11.1 Error translation ­ ATA device error to SCSI 
> error map)
> +		 * and ata_to_sense_error from libata.
> +		 */
> +		sb[1] = sk;
> +		sb[2] = asc;
> +		sb[3] = ascq;
> +
> +		/* Sense data is current and format is descriptor. */
> +		sb[0] = 0x72;
> +		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
> +
> +		/* set length of additional sense data */
> +		sb[7] = 14;
> +		desc[1] = 12;
> +
> +		/* Copy registers into sense buffer. */
> +		desc[2] = 0x00;
> +		desc[3] = regs[1];
> +		desc[5] = regs[2];
> +		desc[7] = regs[3];
> +		desc[9] = regs[4];
> +		desc[11] = regs[5];
> +		desc[12] = regs[6];
> +		desc[13] = regs[7];
> +
> +		srb->result = (DRIVER_SENSE << 24) | 
> SAM_STAT_CHECK_CONDITION;
> +	}
> +	goto end;
> +invalid_fld:
> +	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
> +
> +	memcpy(srb->sense_buffer,
> +			usb_stor_sense_invalidCDB,
> +			sizeof(usb_stor_sense_invalidCDB));
> +end:
> +	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
> +	if (srb->cmnd[0] == ATA_12)
> +		srb->cmd_len = 12;
> +}
> +
> +void usb_stor_transparent_scsi_command_atacb(struct scsi_cmnd *srb,
> +				       struct us_data *us)
> +{
> +	if (srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)
> +		usb_stor_invoke_transport(srb, us);
> +	else
> +		emulate_pass_thru_with_atacb(srb, us);
> +}
> +
>  /***********************************************************************
>   * Scatter-gather transfer buffer access routines
>   ***********************************************************************/
> Index: linux-2.6.24.2/drivers/usb/storage/initializers.c
> ===================================================================
> --- linux-2.6.24.2.orig/drivers/usb/storage/initializers.c	2008-02-29 
> 22:14:09.000000000 +0100
> +++ linux-2.6.24.2/drivers/usb/storage/initializers.c	2008-03-08 
> 18:30:00.000000000 +0100
> @@ -43,6 +43,7 @@
>  #include "initializers.h"
>  #include "debug.h"
>  #include "transport.h"
> +#include "protocol.h"
> 
>  /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
>   * mode */
> @@ -104,3 +105,11 @@
>  	US_DEBUGP("usb_control_msg performing result is %d\n", result);
>  	return (result ? 0 : -1);
>  }
> +
> +/* This function register the atacb proto callback */
> +int usb_atacb_init(struct us_data *us)
> +{
> +	us->proto_handler = usb_stor_transparent_scsi_command_atacb;
> +	US_DEBUGP("atacb proto_handler is set\n");
> +	return 0;
> +}
> Index: linux-2.6.24.2/drivers/usb/storage/initializers.h
> ===================================================================
> --- linux-2.6.24.2.orig/drivers/usb/storage/initializers.h	2008-02-29 
> 22:14:09.000000000 +0100
> +++ linux-2.6.24.2/drivers/usb/storage/initializers.h	2008-03-08 
> 18:28:33.000000000 +0100
> @@ -50,3 +50,6 @@
> 
>  /* This places the HUAWEI E220 devices in multi-port mode */
>  int usb_stor_huawei_e220_init(struct us_data *us);
> +
> +/* This function register the atacb proto callback */
> +int usb_atacb_init(struct us_data *us);
> Index: linux-2.6.24.2/drivers/usb/storage/protocol.h
> ===================================================================
> --- linux-2.6.24.2.orig/drivers/usb/storage/protocol.h	2008-02-29 
> 22:14:09.000000000 +0100
> +++ linux-2.6.24.2/drivers/usb/storage/protocol.h	2008-02-29 
> 22:16:03.000000000 +0100
> @@ -47,6 +47,8 @@
>  extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*);
>  extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
>  		struct us_data*);
> +extern void usb_stor_transparent_scsi_command_atacb(struct scsi_cmnd*,
> +		struct us_data*);
> 
>  /* struct scsi_cmnd transfer buffer access utilities */
>  enum xfer_buf_dir	{TO_XFER_BUF, FROM_XFER_BUF};
> Index: linux-2.6.24.2/drivers/usb/storage/unusual_devs.h
> ===================================================================
> --- linux-2.6.24.2.orig/drivers/usb/storage/unusual_devs.h	2008-02-29 
> 22:14:09.000000000 +0100
> +++ linux-2.6.24.2/drivers/usb/storage/unusual_devs.h	2008-02-29 
> 22:16:03.000000000 +0100
> @@ -1588,6 +1588,12 @@
>  		US_SC_DEVICE, US_PR_DEVICE, NULL,
>  		US_FL_CAPACITY_HEURISTICS),
> 
> +UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
> +		"Cypress",
> +		"Cypress AT2LP",
> +		US_SC_SCSI, US_PR_BULK, usb_atacb_init,
> +		US_FL_NEED_OVERRIDE),
> +
>  /* Control/Bulk transport for all SubClass values */
>  USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
>  USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Matthew Dharm                              Home: mdharm-usb@one-eyed-alien.net 
Maintainer, Linux USB Mass Storage Driver

A:  The most ironic oxymoron wins ...
DP: "Microsoft Works"
A:  Uh, okay, you win.
					-- A.J. & Dust Puppy
User Friendly, 1/18/1998

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-08 18:31 ` Matthew Dharm
@ 2008-03-08 20:08   ` matthieu castet
  2008-03-08 21:21     ` Matthew Dharm
  2008-03-09 10:13   ` [PATCH] mass storage : emulation of sat scsi_pass_thru with ATACB Alan Cox
  1 sibling, 1 reply; 14+ messages in thread
From: matthieu castet @ 2008-03-08 20:08 UTC (permalink / raw)
  To: mdharm-kernel, linux-usb, Linux Kernel list

Hi Matthew,

thanks for your comments

Matthew Dharm wrote:
> Why are you using an initializer instead of a new protocol code?
Because using a new protocol code means I need to patch all the place 
where there is a comparison between us->subclass and US_SC_SCSI.
After all I am US_SC_SCSI with a special case for ATA12 & ATA16 commands.
I don't translate all scsi to atacb (that's what does US_SC_ISD200).

> 
> Most of this should probably be moved into it's own file, just like all of
> the other protocol handlers.
Ok, I will move it in another file.
> 
> Actually, why do you even have a separate 'dispatcher' function?  Why not
> just one protocol handler function which checks the command at the top and
> calls invoke_transport there?
What do you means by having a separate 'dispatcher' function?
You means why I have 2 functions emulate_pass_thru_with_atacb and 
usb_stor_transparent_scsi_command_atacb ?
I did 2 functions for having a code more clean.

You suggest something like
void usb_stor_transparent_scsi_command_atacb(struct scsi_cmnd *srb,
                        struct us_data *us)
{
     if (srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12) {
         usb_stor_invoke_transport(srb, us);
         return;
     }
     copy emulate_pass_thru_with_atacb code here
}

> 
> Also, unless ATACB is a new standard (and I don't think it is, as the
> Cypress datasheet uses the term 'vendor specific'), then your functions
> need renaming.  Instead of 'emulate_pass_thru_with_atacb', how about
> something like 'cypress_atacb' --  since it's already a protocol handler,
> everyone already knows it's for passing commands.
But 'emulate_pass_thru_with_atacb' only handle ATA pass_thru scsi 
commands. It doesn't translate all scsi commands to atacb like 
'cypress_atacb' could suggest.
That's why I put 'usb_stor_transparent_scsi_command_atacb' saying it is 
transparent_scsi_command + atacb support.

Matthieu

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-08 20:08   ` matthieu castet
@ 2008-03-08 21:21     ` Matthew Dharm
  2008-03-09  8:21       ` matthieu castet
  0 siblings, 1 reply; 14+ messages in thread
From: Matthew Dharm @ 2008-03-08 21:21 UTC (permalink / raw)
  To: matthieu castet; +Cc: linux-usb, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 3002 bytes --]

On Sat, Mar 08, 2008 at 09:08:26PM +0100, matthieu castet wrote:
> Hi Matthew,
> 
> thanks for your comments
> 
> Matthew Dharm wrote:
> >Why are you using an initializer instead of a new protocol code?
> Because using a new protocol code means I need to patch all the place 
> where there is a comparison between us->subclass and US_SC_SCSI.
> After all I am US_SC_SCSI with a special case for ATA12 & ATA16 commands.
> I don't translate all scsi to atacb (that's what does US_SC_ISD200).

Yet, you call invoke_transport directly, just like any other protocol
handler.

The proper way to do this is as a separate protocol handler.  If you want
to make it clear that you are only intercepting a couple of command types,
then don't call invoke_transport() directly, call the transparent scsi
protocol handler (which, of course, does the same thing but provides
clearer layering).

Oh, and you should add some "unlikely" tags to these if() conditionals.

> >Actually, why do you even have a separate 'dispatcher' function?  Why not
> >just one protocol handler function which checks the command at the top and
> >calls invoke_transport there?
> What do you means by having a separate 'dispatcher' function?
> You means why I have 2 functions emulate_pass_thru_with_atacb and 
> usb_stor_transparent_scsi_command_atacb ?
> I did 2 functions for having a code more clean.
> 
> You suggest something like
> void usb_stor_transparent_scsi_command_atacb(struct scsi_cmnd *srb,
>                        struct us_data *us)
> {
>     if (srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12) {
>         usb_stor_invoke_transport(srb, us);
>         return;
>     }
>     copy emulate_pass_thru_with_atacb code here
> }

Yes, modulo my comment above about calling the transparent scsi protocol
handler instead of invoke_transport directly.

> >Also, unless ATACB is a new standard (and I don't think it is, as the
> >Cypress datasheet uses the term 'vendor specific'), then your functions
> >need renaming.  Instead of 'emulate_pass_thru_with_atacb', how about
> >something like 'cypress_atacb' --  since it's already a protocol handler,
> >everyone already knows it's for passing commands.
> But 'emulate_pass_thru_with_atacb' only handle ATA pass_thru scsi 
> commands. It doesn't translate all scsi commands to atacb like 
> 'cypress_atacb' could suggest.
> That's why I put 'usb_stor_transparent_scsi_command_atacb' saying it is 
> transparent_scsi_command + atacb support.

Yes, but your name suggests that ATACB is a new industry standard which is
implemented by more than a few chips from one specific vendor.  That's not
acceptable.

Try 'cypress_atacb_passthrough' instead?

Matt

-- 
Matthew Dharm                              Home: mdharm-usb@one-eyed-alien.net 
Maintainer, Linux USB Mass Storage Driver

P:  Nine more messages in admin.policy.
M: I know, I'm typing as fast as I can!
					-- Pitr and Mike
User Friendly, 11/27/97

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-08 21:21     ` Matthew Dharm
@ 2008-03-09  8:21       ` matthieu castet
  2008-03-09 18:45         ` Matthew Dharm
  0 siblings, 1 reply; 14+ messages in thread
From: matthieu castet @ 2008-03-09  8:21 UTC (permalink / raw)
  To: Matthew Dharm, linux-usb, Linux Kernel list

Matthew Dharm wrote:
> On Sat, Mar 08, 2008 at 09:08:26PM +0100, matthieu castet wrote:
>> Hi Matthew,
>>
>> thanks for your comments
>>
>> Matthew Dharm wrote:
>>> Why are you using an initializer instead of a new protocol code?
>> Because using a new protocol code means I need to patch all the place 
>> where there is a comparison between us->subclass and US_SC_SCSI.
>> After all I am US_SC_SCSI with a special case for ATA12 & ATA16 commands.
>> I don't translate all scsi to atacb (that's what does US_SC_ISD200).
> 
> Yet, you call invoke_transport directly, just like any other protocol
> handler.
> 
> The proper way to do this is as a separate protocol handler.  If you want
> to make it clear that you are only intercepting a couple of command types,
> then don't call invoke_transport() directly, call the transparent scsi
> protocol handler (which, of course, does the same thing but provides
> clearer layering).
> 
> Oh, and you should add some "unlikely" tags to these if() conditionals.
Hum, may be to avoid confusion with a new protocol handler, I can add my 
hook in usb_stor_control_thread with a new flag.

Something like :
[...]
  /* Handle those devices which need us to fake
          * their inquiry data */
         else if ((us->srb->cmnd[0] == INQUIRY) &&
                 (us->flags & US_FL_FIX_INQUIRY)) {
[...]
	else if (( (us->srb->cmnd[0] == ATA_12) || (us->srb->cmnd[0] == ATA_16)) &&
                 (us->flags & US_FL_CYPRESS_ATACB)) {
         US_DEBUGP("emulating ATA pass thru\n");
		call to emulate_pass_thru_with_atacb code
         }

         /* we've got a command, let's do it! */
         else {
             US_DEBUG(usb_stor_show_command(us->srb));
             us->proto_handler(us->srb, us);
         }

Does it sound better ?

Matthieu

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-08 18:31 ` Matthew Dharm
  2008-03-08 20:08   ` matthieu castet
@ 2008-03-09 10:13   ` Alan Cox
  1 sibling, 0 replies; 14+ messages in thread
From: Alan Cox @ 2008-03-09 10:13 UTC (permalink / raw)
  To: Matthew Dharm; +Cc: matthieu castet, linux-usb, Linux Kernel list

On Sat, 8 Mar 2008 10:31:25 -0800
Matthew Dharm <mdharm-kernel@one-eyed-alien.net> wrote:

> Why are you using an initializer instead of a new protocol code?
> 
> Most of this should probably be moved into it's own file, just like all of
> the other protocol handlers.

Would it perhaps be simpler to just attach the device to the ATA driver
and use the ATACB interface for everything ?

Alan

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-09  8:21       ` matthieu castet
@ 2008-03-09 18:45         ` Matthew Dharm
  2008-03-09 21:42           ` matthieu castet
  0 siblings, 1 reply; 14+ messages in thread
From: Matthew Dharm @ 2008-03-09 18:45 UTC (permalink / raw)
  To: matthieu castet; +Cc: linux-usb, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 1740 bytes --]

On Sun, Mar 09, 2008 at 09:21:40AM +0100, matthieu castet wrote:
> Hum, may be to avoid confusion with a new protocol handler, I can add my 
> hook in usb_stor_control_thread with a new flag.
> 
> Something like :
> [...]
>  /* Handle those devices which need us to fake
>          * their inquiry data */
>         else if ((us->srb->cmnd[0] == INQUIRY) &&
>                 (us->flags & US_FL_FIX_INQUIRY)) {
> [...]
> 	else if (( (us->srb->cmnd[0] == ATA_12) || (us->srb->cmnd[0] == 
> 	ATA_16)) &&
>                 (us->flags & US_FL_CYPRESS_ATACB)) {
>         US_DEBUGP("emulating ATA pass thru\n");
> 		call to emulate_pass_thru_with_atacb code
>         }
> 
>         /* we've got a command, let's do it! */
>         else {
>             US_DEBUG(usb_stor_show_command(us->srb));
>             us->proto_handler(us->srb, us);
>         }
> 
> Does it sound better ?

Somewhat better.  I still like a separate protocol handler better.

I guess I see this as being more like the ISD200 case.  In that code, it
attempts to identify the device as ATA or ATAPI.  If it's ATAPI, it
switches back to the transparent scsi protocol handler.  Here, we're just
talking about doing it on a command-by-command basis, instead of a one-time
selection.  But there is no confusion that the ISD200 code handles all
commands; but it does implement a new 'protocol' (a way to transport
commands to/from the device), which is exactly what you're doing.

Matt

-- 
Matthew Dharm                              Home: mdharm-usb@one-eyed-alien.net 
Maintainer, Linux USB Mass Storage Driver

I'm seen in many forms.  Now open your mouth.  It's caffeine time.
					-- Cola Man to Greg
User Friendly, 10/28/1998

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-09 18:45         ` Matthew Dharm
@ 2008-03-09 21:42           ` matthieu castet
  2008-03-10  1:20             ` Matthew Dharm
  0 siblings, 1 reply; 14+ messages in thread
From: matthieu castet @ 2008-03-09 21:42 UTC (permalink / raw)
  To: Matthew Dharm, linux-usb, Linux Kernel list

Hi

here an update version of the patch


I have got a cypress usb-ide bridge and I would like to tune or monitor
my disk with tools like hdparm, hddtemp or smartctl.

My controller support a way to send raw ATA command to the disk with
something call atacb (see
http://download.cypress.com.edgesuite.net/design_resources/datasheets/contents/cy7c68300c_8.pdf).

Atacb support can be added for each application, but there is some 
disadvantages :
- all application need to be patched
- A race is possible if there other accesses, because the emulation can
be split in 2 atacb scsi transactions. One for sending the command, one
for reading the register (if ck_cond is set).

I have implemented the emulation in usb-storage with a special 
proto_handler, and an unsual entry.

Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>

Index: linux-2.6.24.2/drivers/usb/storage/unusual_devs.h
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/unusual_devs.h	2008-02-29 
22:14:09.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/unusual_devs.h	2008-03-09 
22:10:59.000000000 +0100
@@ -1588,6 +1588,14 @@
  		US_SC_DEVICE, US_PR_DEVICE, NULL,
  		US_FL_CAPACITY_HEURISTICS),

+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress AT2LP",
+		US_SC_CYP_ATACB, US_PR_BULK, NULL,
+		0),
+#endif
+
  /* Control/Bulk transport for all SubClass values */
  USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
  USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
Index: linux-2.6.24.2/drivers/usb/storage/cypress_atacb.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24.2/drivers/usb/storage/cypress_atacb.c	2008-03-09 
22:04:18.000000000 +0100
@@ -0,0 +1,199 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "scsiglue.h"
+
+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned char save_cmnd[MAX_COMMAND_SIZE];
+
+	if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
+		usb_stor_transparent_scsi_command(srb, us);
+		return;
+	}
+
+	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+	memset(srb->cmnd, 0, sizeof(srb->cmnd));
+
+	/* check if we support the command */
+	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+		goto invalid_fld;
+	/* check protocol */
+	switch((save_cmnd[1] >> 1) & 0xf) {
+		case 3:
+		case 4:
+		case 5:
+			break;
+		default:
+			goto invalid_fld;
+	}
+
+	/* first build the ATACB command */
+	srb->cmd_len = 16;
+
+ 	/* this value can change, but most(all ?) manufacturers keep the cypress
+	 * default : 0x24
+	 */
+	srb->cmnd[0] = 0x24;
+	srb->cmnd[1] = 0x24;
+	srb->cmnd[2] = 0;
+
+	srb->cmnd[3] = 0xff - 1;
+	srb->cmnd[4] = 1;
+
+	if (save_cmnd[0] == ATA_16) {
+		srb->cmnd[6] = save_cmnd[4]; /* features */
+		srb->cmnd[7] = save_cmnd[6]; /* sector count */
+		srb->cmnd[8] = save_cmnd[8]; /* lba low */
+		srb->cmnd[9] = save_cmnd[10]; /* lba med */
+		srb->cmnd[10] = save_cmnd[12]; /* lba high */
+		srb->cmnd[11] = save_cmnd[13]; /* device */
+		srb->cmnd[12] = save_cmnd[14]; /* command */
+
+		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+			/* this could be supported by atacb2 */
+			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+					|| save_cmnd[11])
+				goto invalid_fld;
+		}
+	}
+	else { /* ATA12 */
+		srb->cmnd[6] = save_cmnd[3]; /* features */
+		srb->cmnd[7] = save_cmnd[4]; /* sector count */
+		srb->cmnd[8] = save_cmnd[5]; /* lba low */
+		srb->cmnd[9] = save_cmnd[6]; /* lba med */
+		srb->cmnd[10] = save_cmnd[7]; /* lba high */
+		srb->cmnd[11] = save_cmnd[8]; /* device */
+		srb->cmnd[12] = save_cmnd[9]; /* command */
+
+	}
+	/* Filter SET_FEATURES - XFER MODE command */
+	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+			&& (srb->cmnd[6] == SETFEATURES_XFER))
+		goto invalid_fld;
+
+	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+		srb->cmnd[2] |= (1<<7);
+
+
+	usb_stor_transparent_scsi_command(srb, us);
+
+	/* if the device doesn't support ATACB
+	 * abort and register usb_stor_transparent_scsi_command
+	 * callback
+	 */
+	if (srb->result == SAM_STAT_CHECK_CONDITION &&
+			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+				sizeof(usb_stor_sense_invalidCDB)) == 0) {
+		us->subclass = US_SC_SCSI;
+		us->proto_handler = usb_stor_transparent_scsi_command;
+		goto end;
+	}
+
+	/* if ck_cond flags is set, and there wasn't critical error,
+	 * build the special sense
+	 */
+	if ((srb->result != (DID_ERROR << 16) &&
+				srb->result != (DID_ABORT << 16)) &&
+			save_cmnd[2] & 0x20) {
+		struct scsi_eh_save ses;
+		unsigned char sk, asc, ascq;
+		unsigned char regs[8];
+		unsigned char *sb = srb->sense_buffer;
+		unsigned char *desc = sb + 8;
+		int tmp_result;
+
+		sk = RECOVERED_ERROR;
+		asc = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+		ascq = 0x1D;
+
+		/* read registers */
+		srb->cmnd[2] = 1;
+		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
+		srb->request_buffer = regs;
+		srb->request_bufflen = sizeof(regs);
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+
+		usb_stor_transparent_scsi_command(srb, us);
+		tmp_result = srb->result;
+		scsi_eh_restore_cmnd(srb, &ses);
+		/* we fail to get registers, report invalid command */
+		if (tmp_result != SAM_STAT_GOOD)
+			goto invalid_fld;
+
+		/* build the sense */
+		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+		/* XXX we should generate sk, asc, ascq from status and error
+		 * regs
+		 * (see 11.1 Error translation ­ ATA device error to SCSI error map)
+		 * and ata_to_sense_error from libata.
+		 */
+		sb[1] = sk;
+		sb[2] = asc;
+		sb[3] = ascq;
+
+		/* Sense data is current and format is descriptor. */
+		sb[0] = 0x72;
+		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+		/* set length of additional sense data */
+		sb[7] = 14;
+		desc[1] = 12;
+
+		/* Copy registers into sense buffer. */
+		desc[2] = 0x00;
+		desc[3] = regs[1];
+		desc[5] = regs[2];
+		desc[7] = regs[3];
+		desc[9] = regs[4];
+		desc[11] = regs[5];
+		desc[12] = regs[6];
+		desc[13] = regs[7];
+
+		srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+	}
+	goto end;
+invalid_fld:
+	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+	memcpy(srb->sense_buffer,
+			usb_stor_sense_invalidCDB,
+			sizeof(usb_stor_sense_invalidCDB));
+end:
+	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+	if (srb->cmnd[0] == ATA_12)
+		srb->cmd_len = 12;
+}
Index: linux-2.6.24.2/drivers/usb/storage/cypress_atacb.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.24.2/drivers/usb/storage/cypress_atacb.h	2008-03-09 
22:03:51.000000000 +0100
@@ -0,0 +1,25 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CYPRESS_ATACB_H_
+#define _CYPRESS_ATACB_H_
+extern void cypress_atacb_passthrough(struct scsi_cmnd*, struct us_data*);
+#endif
Index: linux-2.6.24.2/drivers/usb/storage/Kconfig
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/Kconfig	2008-03-09 
21:42:32.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/Kconfig	2008-03-09 
21:52:16.000000000 +0100
@@ -145,6 +145,17 @@
  	  on the resulting scsi device node returns the Karma to normal
  	  operation.

+config USB_STORAGE_CYPRESS_ATACB
+	bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
+	depends on USB_STORAGE
+	---help---
+	  Say Y here if you want to use SAT (ata pass through) on devices based
+	  on the Cypress USB/ATA bridge supporting ATACB. This will allow you
+	  to use tools to tune and monitor your drive (like hdparm or smartctl).
+
+	  If you say no here your device will still work with the standard usb
+	  mass storage class.
+
  config USB_LIBUSUAL
  	bool "The shared table of common (or usual) storage devices"
  	depends on USB
Index: linux-2.6.24.2/drivers/usb/storage/Makefile
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/Makefile	2008-03-09 
21:39:45.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/Makefile	2008-03-09 
21:55:26.000000000 +0100
@@ -21,6 +21,7 @@
  usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= alauda.o
  usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
  usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)	+= karma.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o

  usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
  			initializers.o $(usb-storage-obj-y)
Index: linux-2.6.24.2/drivers/usb/storage/scsiglue.c
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/scsiglue.c	2008-03-09 
21:33:25.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/scsiglue.c	2008-03-09 
21:33:49.000000000 +0100
@@ -132,7 +132,7 @@
  		/* Disk-type devices use MODE SENSE(6) if the protocol
  		 * (SubClass) is Transparent SCSI, otherwise they use
  		 * MODE SENSE(10). */
-		if (us->subclass != US_SC_SCSI)
+		if (us->subclass != US_SC_SCSI && us->subclass != US_SC_CYP_ATACB)
  			sdev->use_10_for_ms = 1;

  		/* Many disks only accept MODE SENSE transfer lengths of
Index: linux-2.6.24.2/drivers/usb/storage/transport.c
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/transport.c	2008-03-09 
21:33:56.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/transport.c	2008-03-09 
21:34:14.000000000 +0100
@@ -587,7 +587,8 @@
  		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);

  		/* FIXME: we must do the protocol translation here */
-		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI ||
+				us->subclass == US_SC_CYP_ATACB)
  			srb->cmd_len = 6;
  		else
  			srb->cmd_len = 12;
Index: linux-2.6.24.2/drivers/usb/storage/usb.c
===================================================================
--- linux-2.6.24.2.orig/drivers/usb/storage/usb.c	2008-03-09 
21:12:36.000000000 +0100
+++ linux-2.6.24.2/drivers/usb/storage/usb.c	2008-03-09 
21:53:55.000000000 +0100
@@ -101,6 +101,9 @@
  #ifdef CONFIG_USB_STORAGE_KARMA
  #include "karma.h"
  #endif
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+#include "cypress_atacb.h"
+#endif

  /* Some informational data */
  MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -708,6 +711,13 @@
  		break;
  #endif

+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+	case US_SC_CYP_ATACB:
+		us->protocol_name = "Transparent SCSI with Cypress ATACB";
+		us->proto_handler = cypress_atacb_passthrough;
+		break;
+#endif
+
  	default:
  		return -EIO;
  	}
Index: linux-2.6.24.2/include/linux/usb_usual.h
===================================================================
--- linux-2.6.24.2.orig/include/linux/usb_usual.h	2008-03-09 
21:15:01.000000000 +0100
+++ linux-2.6.24.2/include/linux/usb_usual.h	2008-03-09 
21:24:12.000000000 +0100
@@ -81,8 +81,9 @@
  #define US_SC_8070	0x05		/* Removable media */
  #define US_SC_SCSI	0x06		/* Transparent */
  #define US_SC_ISD200    0x07		/* ISD200 ATA */
+#define US_SC_CYP_ATACB 0x08		/* Cypress ATACB */
  #define US_SC_MIN	US_SC_RBC
-#define US_SC_MAX	US_SC_ISD200
+#define US_SC_MAX	US_SC_CYP_ATACB

  #define US_SC_DEVICE	0xff		/* Use device's value */


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-09 21:42           ` matthieu castet
@ 2008-03-10  1:20             ` Matthew Dharm
  2008-03-13 21:22               ` matthieu castet
  0 siblings, 1 reply; 14+ messages in thread
From: Matthew Dharm @ 2008-03-10  1:20 UTC (permalink / raw)
  To: matthieu castet; +Cc: linux-usb, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 2417 bytes --]

On Sun, Mar 09, 2008 at 10:42:50PM +0100, matthieu castet wrote:
> Hi
> 
> here an update version of the patch

We're getting very close here.

> + 	/* this value can change, but most(all ?) manufacturers keep the 
> cypress
> +	 * default : 0x24
> +	 */

Line wrap problem.  This happens a few times in your patch, but this was
the first one I noticed.

> +	srb->cmnd[0] = 0x24;
> +	srb->cmnd[1] = 0x24;
> +	srb->cmnd[2] = 0;
> +
> +	srb->cmnd[3] = 0xff - 1;
> +	srb->cmnd[4] = 1;

What are these magic constants?  Symbolic names or comments would be
apropriate here.

> +	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == 
> ATA_CMD_ID_ATAPI)
> +		srb->cmnd[2] |= (1<<7);

What does this block do?  In general, you could use some more comments
about the code flow...

> +	/* if the device doesn't support ATACB
> +	 * abort and register usb_stor_transparent_scsi_command
> +	 * callback
> +	 */
> +	if (srb->result == SAM_STAT_CHECK_CONDITION &&
> +			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
> +				sizeof(usb_stor_sense_invalidCDB)) == 0) {
> +		us->subclass = US_SC_SCSI;
> +		us->proto_handler = usb_stor_transparent_scsi_command;
> +		goto end;
> +	}

This is an interesting section of code.  Do you have reason to believe that
some of the units you've claimed via unusual_devs.h do not support this
protocol, or are you just being forward-looking?

Either way, some debug printout would be good here...

> --- linux-2.6.24.2.orig/include/linux/usb_usual.h	2008-03-09 
> 21:15:01.000000000 +0100
> +++ linux-2.6.24.2/include/linux/usb_usual.h	2008-03-09 
> 21:24:12.000000000 +0100
> @@ -81,8 +81,9 @@
>  #define US_SC_8070	0x05		/* Removable media */
>  #define US_SC_SCSI	0x06		/* Transparent */
>  #define US_SC_ISD200    0x07		/* ISD200 ATA */
> +#define US_SC_CYP_ATACB 0x08		/* Cypress ATACB */
>  #define US_SC_MIN	US_SC_RBC
> -#define US_SC_MAX	US_SC_ISD200
> +#define US_SC_MAX	US_SC_CYP_ATACB
> 
>  #define US_SC_DEVICE	0xff		/* Use device's value */

I thought we changed this so that the non-spec protocols started from 0xfe
and worked their way down?

Matt

-- 
Matthew Dharm                              Home: mdharm-usb@one-eyed-alien.net 
Maintainer, Linux USB Mass Storage Driver

C:  They kicked your ass, didn't they?
S:  They were cheating!
					-- The Chief and Stef
User Friendly, 11/19/1997

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-10  1:20             ` Matthew Dharm
@ 2008-03-13 21:22               ` matthieu castet
  2008-03-14  0:51                 ` Matthew Dharm
  0 siblings, 1 reply; 14+ messages in thread
From: matthieu castet @ 2008-03-13 21:22 UTC (permalink / raw)
  To: Matthew Dharm, linux-usb, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 2979 bytes --]

Matthew Dharm wrote:
> On Sun, Mar 09, 2008 at 10:42:50PM +0100, matthieu castet wrote:
>> Hi
>>
>> here an update version of the patch
> 
> We're getting very close here.
> 
>> + 	/* this value can change, but most(all ?) manufacturers keep the 
>> cypress
>> +	 * default : 0x24
>> +	 */
> 
> Line wrap problem.  This happens a few times in your patch, but this was
> the first one I noticed.
Ha, may be my mailer is broken with inline patch. I will attach the next 
one.

> 
>> +	srb->cmnd[0] = 0x24;
>> +	srb->cmnd[1] = 0x24;
>> +	srb->cmnd[2] = 0;
>> +
>> +	srb->cmnd[3] = 0xff - 1;
>> +	srb->cmnd[4] = 1;
> 
> What are these magic constants?  Symbolic names or comments would be
> apropriate here.
Ok I will change that
> 
>> +	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == 
>> ATA_CMD_ID_ATAPI)
>> +		srb->cmnd[2] |= (1<<7);
> 
> What does this block do?  In general, you could use some more comments
> about the code flow...
It's a bit that should be set for these commands. I will add a comment
about that.
> 
>> +	/* if the device doesn't support ATACB
>> +	 * abort and register usb_stor_transparent_scsi_command
>> +	 * callback
>> +	 */
>> +	if (srb->result == SAM_STAT_CHECK_CONDITION &&
>> +			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
>> +				sizeof(usb_stor_sense_invalidCDB)) == 0) {
>> +		us->subclass = US_SC_SCSI;
>> +		us->proto_handler = usb_stor_transparent_scsi_command;
>> +		goto end;
>> +	}
> 
> This is an interesting section of code.  Do you have reason to believe that
> some of the units you've claimed via unusual_devs.h do not support this
> protocol, or are you just being forward-looking?
when I did this code, I was wondering where to plug the hook and was 
thinking about auto-discovering of atacb device.
I think I can remove it now and replace it with a message.
But I should find a way to discover other devices supporting atacb. May 
be I will do a userspace tool for that.

> 
> Either way, some debug printout would be good here...
> 
>> --- linux-2.6.24.2.orig/include/linux/usb_usual.h	2008-03-09 
>> 21:15:01.000000000 +0100
>> +++ linux-2.6.24.2/include/linux/usb_usual.h	2008-03-09 
>> 21:24:12.000000000 +0100
>> @@ -81,8 +81,9 @@
>>  #define US_SC_8070	0x05		/* Removable media */
>>  #define US_SC_SCSI	0x06		/* Transparent */
>>  #define US_SC_ISD200    0x07		/* ISD200 ATA */
>> +#define US_SC_CYP_ATACB 0x08		/* Cypress ATACB */
>>  #define US_SC_MIN	US_SC_RBC
>> -#define US_SC_MAX	US_SC_ISD200
>> +#define US_SC_MAX	US_SC_CYP_ATACB
>>
>>  #define US_SC_DEVICE	0xff		/* Use device's value */
> 
> I thought we changed this so that the non-spec protocols started from 0xfe
> and worked their way down?
Oh, I suppose I need to port this to lastest git.

- I updated the patch to git version (I have to change some stuff for 
scsi) and I follow the above comments.


Matthieu

PS : I don't have a running kernel git version. So I only build the mass 
storage driver with this patch, I didn't run it.
----

[-- Attachment #2: mass_storage_atacb_emulate_sat --]
[-- Type: text/plain, Size: 13834 bytes --]


I have got a cypress usb-ide bridge and I would like to tune or monitor
my disk with tools like hdparm, hddtemp or smartctl.

My controller support a way to send raw ATA command to the disk with
something call atacb (see
http://download.cypress.com.edgesuite.net/design_resources/datasheets/contents/cy7c68300c_8.pdf).

Atacb support can be added for each application, but there is some disadvantages :
- all application need to be patched
- A race is possible if there other accesses, because the emulation can
be split in 2 atacb scsi transactions. One for sending the command, one
for reading the register (if ck_cond is set). 

I have implemented the emulation in usb-storage with a special proto_handler,
and an unsual entry.

Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>

Index: linux-2.6/drivers/usb/storage/unusual_devs.h
===================================================================
--- linux-2.6.orig/drivers/usb/storage/unusual_devs.h	2008-02-28 11:21:20.000000000 +0100
+++ linux-2.6/drivers/usb/storage/unusual_devs.h	2008-03-13 21:19:21.000000000 +0100
@@ -1620,6 +1620,14 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_CAPACITY_HEURISTICS),
 
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress AT2LP",
+		US_SC_CYP_ATACB, US_PR_BULK, NULL,
+		0),
+#endif
+
 /* Control/Bulk transport for all SubClass values */
 USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
 USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
Index: linux-2.6/drivers/usb/storage/cypress_atacb.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/drivers/usb/storage/cypress_atacb.c	2008-03-13 21:29:26.000000000 +0100
@@ -0,0 +1,203 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned char save_cmnd[MAX_COMMAND_SIZE];
+
+	if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
+		usb_stor_transparent_scsi_command(srb, us);
+		return;
+	}
+
+	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+	memset(srb->cmnd, 0, sizeof(srb->cmnd));
+
+	/* check if we support the command */
+	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+		goto invalid_fld;
+	/* check protocol */
+	switch((save_cmnd[1] >> 1) & 0xf) {
+		case 3: /*no DATA */
+		case 4: /* PIO in */
+		case 5: /* PIO out */
+			break;
+		default:
+			goto invalid_fld;
+	}
+
+	/* first build the ATACB command */
+	srb->cmd_len = 16;
+
+	srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command
+	                        this value can change, but most(all ?) manufacturers
+							keep the cypress default : 0x24 */
+	srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
+
+	srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med
+								lba high, device, command are valid */
+	srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
+
+	if (save_cmnd[0] == ATA_16) {
+		srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
+		srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
+		srb->cmnd[10] = save_cmnd[12]; /* lba high */
+		srb->cmnd[11] = save_cmnd[13]; /* device */
+		srb->cmnd[12] = save_cmnd[14]; /* command */
+
+		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+			/* this could be supported by atacb2 */
+			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+					|| save_cmnd[11])
+				goto invalid_fld;
+		}
+	}
+	else { /* ATA12 */
+		srb->cmnd[ 6] = save_cmnd[3]; /* features */
+		srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
+		srb->cmnd[10] = save_cmnd[7]; /* lba high */
+		srb->cmnd[11] = save_cmnd[8]; /* device */
+		srb->cmnd[12] = save_cmnd[9]; /* command */
+
+	}
+	/* Filter SET_FEATURES - XFER MODE command */
+	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+			&& (srb->cmnd[6] == SETFEATURES_XFER))
+		goto invalid_fld;
+
+	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+		srb->cmnd[2] |= (1<<7); /* set  IdentifyPacketDevice for these cmds */
+
+
+	usb_stor_transparent_scsi_command(srb, us);
+
+	/* if the device doesn't support ATACB
+	 */
+	if (srb->result == SAM_STAT_CHECK_CONDITION &&
+			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+				sizeof(usb_stor_sense_invalidCDB)) == 0) {
+		US_DEBUGP("cypress atacb not supported ???\n");
+		goto end;
+	}
+
+	/* if ck_cond flags is set, and there wasn't critical error,
+	 * build the special sense
+	 */
+	if ((srb->result != (DID_ERROR << 16) &&
+				srb->result != (DID_ABORT << 16)) &&
+			save_cmnd[2] & 0x20) {
+		struct scsi_eh_save ses;
+		unsigned char sk, asc, ascq;
+		unsigned char regs[8];
+		unsigned char *sb = srb->sense_buffer;
+		unsigned char *desc = sb + 8;
+		int tmp_result;
+
+		sk = RECOVERED_ERROR;
+		asc = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+		ascq = 0x1D;
+
+		/* build the command for
+		 * reading the ATA registers */
+		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
+		srb->sdb.length = sizeof(regs);
+		sg_init_one(&ses.sense_sgl, regs, srb->sdb.length);
+		srb->sdb.table.sgl = &ses.sense_sgl;
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+		srb->sdb.table.nents = 1;
+		/* we use the same command as before, but we set
+		 * the read taskfile bit, for not executing atacb command,
+		 * but reading register selected in srb->cmnd[4]
+		 */
+		srb->cmnd[2] = 1;
+
+		usb_stor_transparent_scsi_command(srb, us);
+		tmp_result = srb->result;
+		scsi_eh_restore_cmnd(srb, &ses);
+		/* we fail to get registers, report invalid command */
+		if (tmp_result != SAM_STAT_GOOD)
+			goto invalid_fld;
+
+		/* build the sense */
+		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+		/* XXX we should generate sk, asc, ascq from status and error
+		 * regs
+		 * (see 11.1 Error translation ­ ATA device error to SCSI error map)
+		 * and ata_to_sense_error from libata.
+		 */
+		sb[1] = sk;
+		sb[2] = asc;
+		sb[3] = ascq;
+
+		/* Sense data is current and format is descriptor. */
+		sb[0] = 0x72;
+		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+		/* set length of additional sense data */
+		sb[7] = 14;
+		desc[1] = 12;
+
+		/* Copy registers into sense buffer. */
+		desc[ 2] = 0x00;
+		desc[ 3] = regs[1];  /* features */
+		desc[ 5] = regs[2];  /* sector count */
+		desc[ 7] = regs[3];  /* lba low */
+		desc[ 9] = regs[4];  /* lba med */
+		desc[11] = regs[5];  /* lba high */
+		desc[12] = regs[6];  /* device */
+		desc[13] = regs[7];  /* command */
+
+		srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+	}
+	goto end;
+invalid_fld:
+	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+	memcpy(srb->sense_buffer,
+			usb_stor_sense_invalidCDB,
+			sizeof(usb_stor_sense_invalidCDB));
+end:
+	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+	if (srb->cmnd[0] == ATA_12)
+		srb->cmd_len = 12;
+}
Index: linux-2.6/drivers/usb/storage/cypress_atacb.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/drivers/usb/storage/cypress_atacb.h	2008-03-13 21:19:21.000000000 +0100
@@ -0,0 +1,25 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CYPRESS_ATACB_H_
+#define _CYPRESS_ATACB_H_
+extern void cypress_atacb_passthrough(struct scsi_cmnd*, struct us_data*);
+#endif
Index: linux-2.6/drivers/usb/storage/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/storage/Kconfig	2007-11-29 11:03:48.000000000 +0100
+++ linux-2.6/drivers/usb/storage/Kconfig	2008-03-13 21:19:21.000000000 +0100
@@ -145,6 +145,17 @@
 	  on the resulting scsi device node returns the Karma to normal
 	  operation.
 
+config USB_STORAGE_CYPRESS_ATACB
+	bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
+	depends on USB_STORAGE
+	---help---
+	  Say Y here if you want to use SAT (ata pass through) on devices based
+	  on the Cypress USB/ATA bridge supporting ATACB. This will allow you
+	  to use tools to tune and monitor your drive (like hdparm or smartctl).
+
+	  If you say no here your device will still work with the standard usb
+	  mass storage class.
+
 config USB_LIBUSUAL
 	bool "The shared table of common (or usual) storage devices"
 	depends on USB
Index: linux-2.6/drivers/usb/storage/Makefile
===================================================================
--- linux-2.6.orig/drivers/usb/storage/Makefile	2007-06-08 14:22:39.000000000 +0200
+++ linux-2.6/drivers/usb/storage/Makefile	2008-03-13 21:19:21.000000000 +0100
@@ -21,6 +21,7 @@
 usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= alauda.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)	+= karma.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
Index: linux-2.6/drivers/usb/storage/scsiglue.c
===================================================================
--- linux-2.6.orig/drivers/usb/storage/scsiglue.c	2008-02-05 09:42:21.000000000 +0100
+++ linux-2.6/drivers/usb/storage/scsiglue.c	2008-03-13 21:19:21.000000000 +0100
@@ -132,7 +132,7 @@
 		/* Disk-type devices use MODE SENSE(6) if the protocol
 		 * (SubClass) is Transparent SCSI, otherwise they use
 		 * MODE SENSE(10). */
-		if (us->subclass != US_SC_SCSI)
+		if (us->subclass != US_SC_SCSI && us->subclass != US_SC_CYP_ATACB)
 			sdev->use_10_for_ms = 1;
 
 		/* Many disks only accept MODE SENSE transfer lengths of
Index: linux-2.6/drivers/usb/storage/transport.c
===================================================================
--- linux-2.6.orig/drivers/usb/storage/transport.c	2008-02-28 11:21:20.000000000 +0100
+++ linux-2.6/drivers/usb/storage/transport.c	2008-03-13 21:19:21.000000000 +0100
@@ -603,7 +603,8 @@
 		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
 
 		/* FIXME: we must do the protocol translation here */
-		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI ||
+				us->subclass == US_SC_CYP_ATACB)
 			srb->cmd_len = 6;
 		else
 			srb->cmd_len = 12;
Index: linux-2.6/drivers/usb/storage/usb.c
===================================================================
--- linux-2.6.orig/drivers/usb/storage/usb.c	2007-11-29 11:03:48.000000000 +0100
+++ linux-2.6/drivers/usb/storage/usb.c	2008-03-13 21:19:21.000000000 +0100
@@ -101,6 +101,9 @@
 #ifdef CONFIG_USB_STORAGE_KARMA
 #include "karma.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+#include "cypress_atacb.h"
+#endif
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -708,6 +711,13 @@
 		break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+	case US_SC_CYP_ATACB:
+		us->protocol_name = "Transparent SCSI with Cypress ATACB";
+		us->proto_handler = cypress_atacb_passthrough;
+		break;
+#endif
+
 	default:
 		return -EIO;
 	}
Index: linux-2.6/include/linux/usb_usual.h
===================================================================
--- linux-2.6.orig/include/linux/usb_usual.h	2008-02-05 09:42:23.000000000 +0100
+++ linux-2.6/include/linux/usb_usual.h	2008-03-13 21:20:33.000000000 +0100
@@ -83,6 +83,7 @@
 #define US_SC_LOCKABLE	0x07		/* Password-protected */
 
 #define US_SC_ISD200    0xf0		/* ISD200 ATA */
+#define US_SC_CYP_ATACB 0xf1		/* Cypress ATACB */
 #define US_SC_DEVICE	0xff		/* Use device's value */
 
 /* Protocols */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-13 21:22               ` matthieu castet
@ 2008-03-14  0:51                 ` Matthew Dharm
       [not found]                   ` <20080318221207.GY2820@one-eyed-alien.net>
  0 siblings, 1 reply; 14+ messages in thread
From: Matthew Dharm @ 2008-03-14  0:51 UTC (permalink / raw)
  To: matthieu castet; +Cc: linux-usb, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 1022 bytes --]

On Thu, Mar 13, 2008 at 10:22:09PM +0100, matthieu castet wrote:
> Matthew Dharm wrote:
> >On Sun, Mar 09, 2008 at 10:42:50PM +0100, matthieu castet wrote:
> >>Hi
> >>
> >>here an update version of the patch
> >
> >We're getting very close here.

> +		unsigned char sk, asc, ascq;

> +		sk = RECOVERED_ERROR;
> +		asc = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
> +		ascq = 0x1D;

> +		/* XXX we should generate sk, asc, ascq from status and error
> +		 * regs
> +		 * (see 11.1 Error translation ? ATA device error to SCSI error map)
> +		 * and ata_to_sense_error from libata.
> +		 */
> +		sb[1] = sk;
> +		sb[2] = asc;
> +		sb[3] = ascq;

I may have missed this in an earlier patch, but why to you declare and use
these 3 variables like this?  Seems odd and confusing to me....

Matt

-- 
Matthew Dharm                              Home: mdharm-usb@one-eyed-alien.net 
Maintainer, Linux USB Mass Storage Driver

It was a new hope.
					-- Dust Puppy
User Friendly, 12/25/1998

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
       [not found]                   ` <20080318221207.GY2820@one-eyed-alien.net>
@ 2008-03-19 18:40                     ` matthieu castet
  2008-03-19 20:02                       ` Matthew Dharm
  2008-03-20 21:39                       ` patch usb-mass-storage-emulation-of-sat-scsi_pass_thru-with-atacb.patch added to gregkh-2.6 tree gregkh
  0 siblings, 2 replies; 14+ messages in thread
From: matthieu castet @ 2008-03-19 18:40 UTC (permalink / raw)
  To: Matthew Dharm; +Cc: linux-usb, Linux Kernel list

[-- Attachment #1: Type: text/plain, Size: 1343 bytes --]

Matthew Dharm wrote:
> Matt --
> 
> I just noticed that it's been about a week since I sent this...
> 
> Any progress?
Sorry I was a bit busy.

Matt
> 
> On Thu, Mar 13, 2008 at 05:51:39PM -0700, Matthew Dharm wrote:
>> On Thu, Mar 13, 2008 at 10:22:09PM +0100, matthieu castet wrote:
>>> Matthew Dharm wrote:
>>>> On Sun, Mar 09, 2008 at 10:42:50PM +0100, matthieu castet wrote:
>>>>> Hi
>>>>>
>>>>> here an update version of the patch
>>>> We're getting very close here.
>>> +		unsigned char sk, asc, ascq;
>>> +		sk = RECOVERED_ERROR;
>>> +		asc = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
>>> +		ascq = 0x1D;
>>> +		/* XXX we should generate sk, asc, ascq from status and error
>>> +		 * regs
>>> +		 * (see 11.1 Error translation ? ATA device error to SCSI error map)
>>> +		 * and ata_to_sense_error from libata.
>>> +		 */
>>> +		sb[1] = sk;
>>> +		sb[2] = asc;
>>> +		sb[3] = ascq;
>> I may have missed this in an earlier patch, but why to you declare and use
>> these 3 variables like this?  Seems odd and confusing to me....
I did that because in previous patch I was saving value from the first 
sense buffer if the first atacb command failed.
But after some test, I saw the returned values were always 0 and I 
always set the same value.
I think I can remove them now.

Patch with sk, asc, ascq removed attached.

Matthieu



[-- Attachment #2: mass_storage_atacb_emulate_sat --]
[-- Type: text/plain, Size: 13800 bytes --]


I have got a cypress usb-ide bridge and I would like to tune or monitor
my disk with tools like hdparm, hddtemp or smartctl.

My controller support a way to send raw ATA command to the disk with
something call atacb (see
http://download.cypress.com.edgesuite.net/design_resources/datasheets/contents/cy7c68300c_8.pdf).

Atacb support can be added for each application, but there is some disadvantages :
- all application need to be patched
- A race is possible if there other accesses, because the emulation can
be split in 2 atacb scsi transactions. One for sending the command, one
for reading the register (if ck_cond is set). 

I have implemented the emulation in usb-storage with a special proto_handler,
and an unsual entry.

Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>

Index: linux-2.6/drivers/usb/storage/unusual_devs.h
===================================================================
--- linux-2.6.orig/drivers/usb/storage/unusual_devs.h	2008-02-28 11:21:20.000000000 +0100
+++ linux-2.6/drivers/usb/storage/unusual_devs.h	2008-03-13 21:19:21.000000000 +0100
@@ -1620,6 +1620,14 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_CAPACITY_HEURISTICS),
 
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress AT2LP",
+		US_SC_CYP_ATACB, US_PR_BULK, NULL,
+		0),
+#endif
+
 /* Control/Bulk transport for all SubClass values */
 USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
 USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
Index: linux-2.6/drivers/usb/storage/cypress_atacb.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/drivers/usb/storage/cypress_atacb.c	2008-03-19 19:34:11.000000000 +0100
@@ -0,0 +1,200 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned char save_cmnd[MAX_COMMAND_SIZE];
+
+	if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
+		usb_stor_transparent_scsi_command(srb, us);
+		return;
+	}
+
+	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+	memset(srb->cmnd, 0, sizeof(srb->cmnd));
+
+	/* check if we support the command */
+	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+		goto invalid_fld;
+	/* check protocol */
+	switch((save_cmnd[1] >> 1) & 0xf) {
+		case 3: /*no DATA */
+		case 4: /* PIO in */
+		case 5: /* PIO out */
+			break;
+		default:
+			goto invalid_fld;
+	}
+
+	/* first build the ATACB command */
+	srb->cmd_len = 16;
+
+	srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command
+	                        this value can change, but most(all ?) manufacturers
+							keep the cypress default : 0x24 */
+	srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
+
+	srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med
+								lba high, device, command are valid */
+	srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
+
+	if (save_cmnd[0] == ATA_16) {
+		srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
+		srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
+		srb->cmnd[10] = save_cmnd[12]; /* lba high */
+		srb->cmnd[11] = save_cmnd[13]; /* device */
+		srb->cmnd[12] = save_cmnd[14]; /* command */
+
+		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+			/* this could be supported by atacb2 */
+			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+					|| save_cmnd[11])
+				goto invalid_fld;
+		}
+	}
+	else { /* ATA12 */
+		srb->cmnd[ 6] = save_cmnd[3]; /* features */
+		srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
+		srb->cmnd[10] = save_cmnd[7]; /* lba high */
+		srb->cmnd[11] = save_cmnd[8]; /* device */
+		srb->cmnd[12] = save_cmnd[9]; /* command */
+
+	}
+	/* Filter SET_FEATURES - XFER MODE command */
+	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+			&& (srb->cmnd[6] == SETFEATURES_XFER))
+		goto invalid_fld;
+
+	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+		srb->cmnd[2] |= (1<<7); /* set  IdentifyPacketDevice for these cmds */
+
+
+	usb_stor_transparent_scsi_command(srb, us);
+
+	/* if the device doesn't support ATACB
+	 */
+	if (srb->result == SAM_STAT_CHECK_CONDITION &&
+			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+				sizeof(usb_stor_sense_invalidCDB)) == 0) {
+		US_DEBUGP("cypress atacb not supported ???\n");
+		goto end;
+	}
+
+	/* if ck_cond flags is set, and there wasn't critical error,
+	 * build the special sense
+	 */
+	if ((srb->result != (DID_ERROR << 16) &&
+				srb->result != (DID_ABORT << 16)) &&
+			save_cmnd[2] & 0x20) {
+		struct scsi_eh_save ses;
+		unsigned char regs[8];
+		unsigned char *sb = srb->sense_buffer;
+		unsigned char *desc = sb + 8;
+		int tmp_result;
+
+		/* build the command for
+		 * reading the ATA registers */
+		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
+		srb->sdb.length = sizeof(regs);
+		sg_init_one(&ses.sense_sgl, regs, srb->sdb.length);
+		srb->sdb.table.sgl = &ses.sense_sgl;
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+		srb->sdb.table.nents = 1;
+		/* we use the same command as before, but we set
+		 * the read taskfile bit, for not executing atacb command,
+		 * but reading register selected in srb->cmnd[4]
+		 */
+		srb->cmnd[2] = 1;
+
+		usb_stor_transparent_scsi_command(srb, us);
+		tmp_result = srb->result;
+		scsi_eh_restore_cmnd(srb, &ses);
+		/* we fail to get registers, report invalid command */
+		if (tmp_result != SAM_STAT_GOOD)
+			goto invalid_fld;
+
+		/* build the sense */
+		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+		/* set sk, asc for a good command */
+		sb[1] = RECOVERED_ERROR;
+		sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+		sb[3] = 0x1D;
+
+		/* XXX we should generate sk, asc, ascq from status and error
+		 * regs
+		 * (see 11.1 Error translation ­ ATA device error to SCSI error map)
+		 * and ata_to_sense_error from libata.
+		 */
+
+		/* Sense data is current and format is descriptor. */
+		sb[0] = 0x72;
+		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+		/* set length of additional sense data */
+		sb[7] = 14;
+		desc[1] = 12;
+
+		/* Copy registers into sense buffer. */
+		desc[ 2] = 0x00;
+		desc[ 3] = regs[1];  /* features */
+		desc[ 5] = regs[2];  /* sector count */
+		desc[ 7] = regs[3];  /* lba low */
+		desc[ 9] = regs[4];  /* lba med */
+		desc[11] = regs[5];  /* lba high */
+		desc[12] = regs[6];  /* device */
+		desc[13] = regs[7];  /* command */
+
+		srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+	}
+	goto end;
+invalid_fld:
+	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+	memcpy(srb->sense_buffer,
+			usb_stor_sense_invalidCDB,
+			sizeof(usb_stor_sense_invalidCDB));
+end:
+	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+	if (srb->cmnd[0] == ATA_12)
+		srb->cmd_len = 12;
+}
Index: linux-2.6/drivers/usb/storage/cypress_atacb.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/drivers/usb/storage/cypress_atacb.h	2008-03-13 21:19:21.000000000 +0100
@@ -0,0 +1,25 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CYPRESS_ATACB_H_
+#define _CYPRESS_ATACB_H_
+extern void cypress_atacb_passthrough(struct scsi_cmnd*, struct us_data*);
+#endif
Index: linux-2.6/drivers/usb/storage/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/storage/Kconfig	2007-11-29 11:03:48.000000000 +0100
+++ linux-2.6/drivers/usb/storage/Kconfig	2008-03-13 21:19:21.000000000 +0100
@@ -145,6 +145,17 @@
 	  on the resulting scsi device node returns the Karma to normal
 	  operation.
 
+config USB_STORAGE_CYPRESS_ATACB
+	bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
+	depends on USB_STORAGE
+	---help---
+	  Say Y here if you want to use SAT (ata pass through) on devices based
+	  on the Cypress USB/ATA bridge supporting ATACB. This will allow you
+	  to use tools to tune and monitor your drive (like hdparm or smartctl).
+
+	  If you say no here your device will still work with the standard usb
+	  mass storage class.
+
 config USB_LIBUSUAL
 	bool "The shared table of common (or usual) storage devices"
 	depends on USB
Index: linux-2.6/drivers/usb/storage/Makefile
===================================================================
--- linux-2.6.orig/drivers/usb/storage/Makefile	2007-06-08 14:22:39.000000000 +0200
+++ linux-2.6/drivers/usb/storage/Makefile	2008-03-13 21:19:21.000000000 +0100
@@ -21,6 +21,7 @@
 usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= alauda.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)	+= karma.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
Index: linux-2.6/drivers/usb/storage/scsiglue.c
===================================================================
--- linux-2.6.orig/drivers/usb/storage/scsiglue.c	2008-02-05 09:42:21.000000000 +0100
+++ linux-2.6/drivers/usb/storage/scsiglue.c	2008-03-13 21:19:21.000000000 +0100
@@ -132,7 +132,7 @@
 		/* Disk-type devices use MODE SENSE(6) if the protocol
 		 * (SubClass) is Transparent SCSI, otherwise they use
 		 * MODE SENSE(10). */
-		if (us->subclass != US_SC_SCSI)
+		if (us->subclass != US_SC_SCSI && us->subclass != US_SC_CYP_ATACB)
 			sdev->use_10_for_ms = 1;
 
 		/* Many disks only accept MODE SENSE transfer lengths of
Index: linux-2.6/drivers/usb/storage/transport.c
===================================================================
--- linux-2.6.orig/drivers/usb/storage/transport.c	2008-02-28 11:21:20.000000000 +0100
+++ linux-2.6/drivers/usb/storage/transport.c	2008-03-13 21:19:21.000000000 +0100
@@ -603,7 +603,8 @@
 		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
 
 		/* FIXME: we must do the protocol translation here */
-		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI ||
+				us->subclass == US_SC_CYP_ATACB)
 			srb->cmd_len = 6;
 		else
 			srb->cmd_len = 12;
Index: linux-2.6/drivers/usb/storage/usb.c
===================================================================
--- linux-2.6.orig/drivers/usb/storage/usb.c	2007-11-29 11:03:48.000000000 +0100
+++ linux-2.6/drivers/usb/storage/usb.c	2008-03-13 21:19:21.000000000 +0100
@@ -101,6 +101,9 @@
 #ifdef CONFIG_USB_STORAGE_KARMA
 #include "karma.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+#include "cypress_atacb.h"
+#endif
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -708,6 +711,13 @@
 		break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+	case US_SC_CYP_ATACB:
+		us->protocol_name = "Transparent SCSI with Cypress ATACB";
+		us->proto_handler = cypress_atacb_passthrough;
+		break;
+#endif
+
 	default:
 		return -EIO;
 	}
Index: linux-2.6/include/linux/usb_usual.h
===================================================================
--- linux-2.6.orig/include/linux/usb_usual.h	2008-02-05 09:42:23.000000000 +0100
+++ linux-2.6/include/linux/usb_usual.h	2008-03-13 21:20:33.000000000 +0100
@@ -83,6 +83,7 @@
 #define US_SC_LOCKABLE	0x07		/* Password-protected */
 
 #define US_SC_ISD200    0xf0		/* ISD200 ATA */
+#define US_SC_CYP_ATACB 0xf1		/* Cypress ATACB */
 #define US_SC_DEVICE	0xff		/* Use device's value */
 
 /* Protocols */

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH]  mass storage : emulation of sat scsi_pass_thru with ATACB
  2008-03-19 18:40                     ` matthieu castet
@ 2008-03-19 20:02                       ` Matthew Dharm
  2008-03-20 21:39                       ` patch usb-mass-storage-emulation-of-sat-scsi_pass_thru-with-atacb.patch added to gregkh-2.6 tree gregkh
  1 sibling, 0 replies; 14+ messages in thread
From: Matthew Dharm @ 2008-03-19 20:02 UTC (permalink / raw)
  To: matthieu castet; +Cc: linux-usb, Linux Kernel list, USB Storage List

[-- Attachment #1: Type: text/plain, Size: 15349 bytes --]

Looks good to me.  Greg, please apply.

Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>

Matt

On Wed, Mar 19, 2008 at 07:40:52PM +0100, matthieu castet wrote:
> 
> I have got a cypress usb-ide bridge and I would like to tune or monitor
> my disk with tools like hdparm, hddtemp or smartctl.
> 
> My controller support a way to send raw ATA command to the disk with
> something call atacb (see
> http://download.cypress.com.edgesuite.net/design_resources/datasheets/contents/cy7c68300c_8.pdf).
> 
> Atacb support can be added for each application, but there is some disadvantages :
> - all application need to be patched
> - A race is possible if there other accesses, because the emulation can
> be split in 2 atacb scsi transactions. One for sending the command, one
> for reading the register (if ck_cond is set). 
> 
> I have implemented the emulation in usb-storage with a special proto_handler,
> and an unsual entry.
> 
> Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>
> 
> Index: linux-2.6/drivers/usb/storage/unusual_devs.h
> ===================================================================
> --- linux-2.6.orig/drivers/usb/storage/unusual_devs.h	2008-02-28 11:21:20.000000000 +0100
> +++ linux-2.6/drivers/usb/storage/unusual_devs.h	2008-03-13 21:19:21.000000000 +0100
> @@ -1620,6 +1620,14 @@
>  		US_SC_DEVICE, US_PR_DEVICE, NULL,
>  		US_FL_CAPACITY_HEURISTICS),
>  
> +#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
> +UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
> +		"Cypress",
> +		"Cypress AT2LP",
> +		US_SC_CYP_ATACB, US_PR_BULK, NULL,
> +		0),
> +#endif
> +
>  /* Control/Bulk transport for all SubClass values */
>  USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
>  USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
> Index: linux-2.6/drivers/usb/storage/cypress_atacb.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6/drivers/usb/storage/cypress_atacb.c	2008-03-19 19:34:11.000000000 +0100
> @@ -0,0 +1,200 @@
> +/*
> + * Support for emulating SAT (ata pass through) on devices based
> + *       on the Cypress USB/ATA bridge supporting ATACB.
> + *
> + * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2, or (at your option) any
> + * later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <scsi/scsi.h>
> +#include <scsi/scsi_cmnd.h>
> +#include <scsi/scsi_eh.h>
> +#include <linux/ata.h>
> +
> +#include "usb.h"
> +#include "protocol.h"
> +#include "scsiglue.h"
> +#include "debug.h"
> +
> +/*
> + * ATACB is a protocol used on cypress usb<->ata bridge to
> + * send raw ATA command over mass storage
> + * There is a ATACB2 protocol that support LBA48 on newer chip.
> + * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
> + * datasheet from cypress.com.
> + */
> +void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
> +{
> +	unsigned char save_cmnd[MAX_COMMAND_SIZE];
> +
> +	if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
> +		usb_stor_transparent_scsi_command(srb, us);
> +		return;
> +	}
> +
> +	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
> +	memset(srb->cmnd, 0, sizeof(srb->cmnd));
> +
> +	/* check if we support the command */
> +	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
> +		goto invalid_fld;
> +	/* check protocol */
> +	switch((save_cmnd[1] >> 1) & 0xf) {
> +		case 3: /*no DATA */
> +		case 4: /* PIO in */
> +		case 5: /* PIO out */
> +			break;
> +		default:
> +			goto invalid_fld;
> +	}
> +
> +	/* first build the ATACB command */
> +	srb->cmd_len = 16;
> +
> +	srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command
> +	                        this value can change, but most(all ?) manufacturers
> +							keep the cypress default : 0x24 */
> +	srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
> +
> +	srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med
> +								lba high, device, command are valid */
> +	srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
> +
> +	if (save_cmnd[0] == ATA_16) {
> +		srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
> +		srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
> +		srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
> +		srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
> +		srb->cmnd[10] = save_cmnd[12]; /* lba high */
> +		srb->cmnd[11] = save_cmnd[13]; /* device */
> +		srb->cmnd[12] = save_cmnd[14]; /* command */
> +
> +		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
> +			/* this could be supported by atacb2 */
> +			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
> +					|| save_cmnd[11])
> +				goto invalid_fld;
> +		}
> +	}
> +	else { /* ATA12 */
> +		srb->cmnd[ 6] = save_cmnd[3]; /* features */
> +		srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
> +		srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
> +		srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
> +		srb->cmnd[10] = save_cmnd[7]; /* lba high */
> +		srb->cmnd[11] = save_cmnd[8]; /* device */
> +		srb->cmnd[12] = save_cmnd[9]; /* command */
> +
> +	}
> +	/* Filter SET_FEATURES - XFER MODE command */
> +	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
> +			&& (srb->cmnd[6] == SETFEATURES_XFER))
> +		goto invalid_fld;
> +
> +	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
> +		srb->cmnd[2] |= (1<<7); /* set  IdentifyPacketDevice for these cmds */
> +
> +
> +	usb_stor_transparent_scsi_command(srb, us);
> +
> +	/* if the device doesn't support ATACB
> +	 */
> +	if (srb->result == SAM_STAT_CHECK_CONDITION &&
> +			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
> +				sizeof(usb_stor_sense_invalidCDB)) == 0) {
> +		US_DEBUGP("cypress atacb not supported ???\n");
> +		goto end;
> +	}
> +
> +	/* if ck_cond flags is set, and there wasn't critical error,
> +	 * build the special sense
> +	 */
> +	if ((srb->result != (DID_ERROR << 16) &&
> +				srb->result != (DID_ABORT << 16)) &&
> +			save_cmnd[2] & 0x20) {
> +		struct scsi_eh_save ses;
> +		unsigned char regs[8];
> +		unsigned char *sb = srb->sense_buffer;
> +		unsigned char *desc = sb + 8;
> +		int tmp_result;
> +
> +		/* build the command for
> +		 * reading the ATA registers */
> +		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
> +		srb->sdb.length = sizeof(regs);
> +		sg_init_one(&ses.sense_sgl, regs, srb->sdb.length);
> +		srb->sdb.table.sgl = &ses.sense_sgl;
> +		srb->sc_data_direction = DMA_FROM_DEVICE;
> +		srb->sdb.table.nents = 1;
> +		/* we use the same command as before, but we set
> +		 * the read taskfile bit, for not executing atacb command,
> +		 * but reading register selected in srb->cmnd[4]
> +		 */
> +		srb->cmnd[2] = 1;
> +
> +		usb_stor_transparent_scsi_command(srb, us);
> +		tmp_result = srb->result;
> +		scsi_eh_restore_cmnd(srb, &ses);
> +		/* we fail to get registers, report invalid command */
> +		if (tmp_result != SAM_STAT_GOOD)
> +			goto invalid_fld;
> +
> +		/* build the sense */
> +		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
> +
> +		/* set sk, asc for a good command */
> +		sb[1] = RECOVERED_ERROR;
> +		sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
> +		sb[3] = 0x1D;
> +
> +		/* XXX we should generate sk, asc, ascq from status and error
> +		 * regs
> +		 * (see 11.1 Error translation ? ATA device error to SCSI error map)
> +		 * and ata_to_sense_error from libata.
> +		 */
> +
> +		/* Sense data is current and format is descriptor. */
> +		sb[0] = 0x72;
> +		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
> +
> +		/* set length of additional sense data */
> +		sb[7] = 14;
> +		desc[1] = 12;
> +
> +		/* Copy registers into sense buffer. */
> +		desc[ 2] = 0x00;
> +		desc[ 3] = regs[1];  /* features */
> +		desc[ 5] = regs[2];  /* sector count */
> +		desc[ 7] = regs[3];  /* lba low */
> +		desc[ 9] = regs[4];  /* lba med */
> +		desc[11] = regs[5];  /* lba high */
> +		desc[12] = regs[6];  /* device */
> +		desc[13] = regs[7];  /* command */
> +
> +		srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
> +	}
> +	goto end;
> +invalid_fld:
> +	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
> +
> +	memcpy(srb->sense_buffer,
> +			usb_stor_sense_invalidCDB,
> +			sizeof(usb_stor_sense_invalidCDB));
> +end:
> +	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
> +	if (srb->cmnd[0] == ATA_12)
> +		srb->cmd_len = 12;
> +}
> Index: linux-2.6/drivers/usb/storage/cypress_atacb.h
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6/drivers/usb/storage/cypress_atacb.h	2008-03-13 21:19:21.000000000 +0100
> @@ -0,0 +1,25 @@
> +/*
> + * Support for emulating SAT (ata pass through) on devices based
> + *       on the Cypress USB/ATA bridge supporting ATACB.
> + *
> + * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2, or (at your option) any
> + * later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _CYPRESS_ATACB_H_
> +#define _CYPRESS_ATACB_H_
> +extern void cypress_atacb_passthrough(struct scsi_cmnd*, struct us_data*);
> +#endif
> Index: linux-2.6/drivers/usb/storage/Kconfig
> ===================================================================
> --- linux-2.6.orig/drivers/usb/storage/Kconfig	2007-11-29 11:03:48.000000000 +0100
> +++ linux-2.6/drivers/usb/storage/Kconfig	2008-03-13 21:19:21.000000000 +0100
> @@ -145,6 +145,17 @@
>  	  on the resulting scsi device node returns the Karma to normal
>  	  operation.
>  
> +config USB_STORAGE_CYPRESS_ATACB
> +	bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
> +	depends on USB_STORAGE
> +	---help---
> +	  Say Y here if you want to use SAT (ata pass through) on devices based
> +	  on the Cypress USB/ATA bridge supporting ATACB. This will allow you
> +	  to use tools to tune and monitor your drive (like hdparm or smartctl).
> +
> +	  If you say no here your device will still work with the standard usb
> +	  mass storage class.
> +
>  config USB_LIBUSUAL
>  	bool "The shared table of common (or usual) storage devices"
>  	depends on USB
> Index: linux-2.6/drivers/usb/storage/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/usb/storage/Makefile	2007-06-08 14:22:39.000000000 +0200
> +++ linux-2.6/drivers/usb/storage/Makefile	2008-03-13 21:19:21.000000000 +0100
> @@ -21,6 +21,7 @@
>  usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= alauda.o
>  usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
>  usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)	+= karma.o
> +usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
>  
>  usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
>  			initializers.o $(usb-storage-obj-y)
> Index: linux-2.6/drivers/usb/storage/scsiglue.c
> ===================================================================
> --- linux-2.6.orig/drivers/usb/storage/scsiglue.c	2008-02-05 09:42:21.000000000 +0100
> +++ linux-2.6/drivers/usb/storage/scsiglue.c	2008-03-13 21:19:21.000000000 +0100
> @@ -132,7 +132,7 @@
>  		/* Disk-type devices use MODE SENSE(6) if the protocol
>  		 * (SubClass) is Transparent SCSI, otherwise they use
>  		 * MODE SENSE(10). */
> -		if (us->subclass != US_SC_SCSI)
> +		if (us->subclass != US_SC_SCSI && us->subclass != US_SC_CYP_ATACB)
>  			sdev->use_10_for_ms = 1;
>  
>  		/* Many disks only accept MODE SENSE transfer lengths of
> Index: linux-2.6/drivers/usb/storage/transport.c
> ===================================================================
> --- linux-2.6.orig/drivers/usb/storage/transport.c	2008-02-28 11:21:20.000000000 +0100
> +++ linux-2.6/drivers/usb/storage/transport.c	2008-03-13 21:19:21.000000000 +0100
> @@ -603,7 +603,8 @@
>  		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
>  
>  		/* FIXME: we must do the protocol translation here */
> -		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
> +		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI ||
> +				us->subclass == US_SC_CYP_ATACB)
>  			srb->cmd_len = 6;
>  		else
>  			srb->cmd_len = 12;
> Index: linux-2.6/drivers/usb/storage/usb.c
> ===================================================================
> --- linux-2.6.orig/drivers/usb/storage/usb.c	2007-11-29 11:03:48.000000000 +0100
> +++ linux-2.6/drivers/usb/storage/usb.c	2008-03-13 21:19:21.000000000 +0100
> @@ -101,6 +101,9 @@
>  #ifdef CONFIG_USB_STORAGE_KARMA
>  #include "karma.h"
>  #endif
> +#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
> +#include "cypress_atacb.h"
> +#endif
>  
>  /* Some informational data */
>  MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
> @@ -708,6 +711,13 @@
>  		break;
>  #endif
>  
> +#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
> +	case US_SC_CYP_ATACB:
> +		us->protocol_name = "Transparent SCSI with Cypress ATACB";
> +		us->proto_handler = cypress_atacb_passthrough;
> +		break;
> +#endif
> +
>  	default:
>  		return -EIO;
>  	}
> Index: linux-2.6/include/linux/usb_usual.h
> ===================================================================
> --- linux-2.6.orig/include/linux/usb_usual.h	2008-02-05 09:42:23.000000000 +0100
> +++ linux-2.6/include/linux/usb_usual.h	2008-03-13 21:20:33.000000000 +0100
> @@ -83,6 +83,7 @@
>  #define US_SC_LOCKABLE	0x07		/* Password-protected */
>  
>  #define US_SC_ISD200    0xf0		/* ISD200 ATA */
> +#define US_SC_CYP_ATACB 0xf1		/* Cypress ATACB */
>  #define US_SC_DEVICE	0xff		/* Use device's value */
>  
>  /* Protocols */


-- 
Matthew Dharm                              Home: mdharm-usb@one-eyed-alien.net 
Maintainer, Linux USB Mass Storage Driver

I could always suspend a few hundred accounts and watch what happens.
					-- Tanya
User Friendly, 7/31/1998

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* patch usb-mass-storage-emulation-of-sat-scsi_pass_thru-with-atacb.patch added to gregkh-2.6 tree
  2008-03-19 18:40                     ` matthieu castet
  2008-03-19 20:02                       ` Matthew Dharm
@ 2008-03-20 21:39                       ` gregkh
  1 sibling, 0 replies; 14+ messages in thread
From: gregkh @ 2008-03-20 21:39 UTC (permalink / raw)
  To: castet.matthieu, gregkh, linux-kernel, mdharm-kernel, mdharm-usb

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 13731 bytes --]


This is a note to let you know that I've just added the patch titled

     Subject: USB: mass storage: emulation of sat scsi_pass_thru with ATACB

to my gregkh-2.6 tree.  Its filename is

     usb-mass-storage-emulation-of-sat-scsi_pass_thru-with-atacb.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


>From linux-usb-owner@vger.kernel.org Wed Mar 19 13:37:47 2008
From: matthieu castet <castet.matthieu@free.fr>
Date: Wed, 19 Mar 2008 19:40:52 +0100
Subject: USB: mass storage: emulation of sat scsi_pass_thru with ATACB
To: Matthew Dharm <mdharm-kernel@one-eyed-alien.net>
Cc: linux-usb@vger.kernel.org, Linux Kernel list <linux-kernel@vger.kernel.org>
Message-ID: <47E15E34.4080204@free.fr>


I have got a cypress usb-ide bridge and I would like to tune or monitor
my disk with tools like hdparm, hddtemp or smartctl.

My controller support a way to send raw ATA command to the disk with
something call atacb (see
http://download.cypress.com.edgesuite.net/design_resources/datasheets/contents/cy7c68300c_8.pdf).

Atacb support can be added for each application, but there is some disadvantages :
- all application need to be patched
- A race is possible if there other accesses, because the emulation can
be split in 2 atacb scsi transactions. One for sending the command, one
for reading the register (if ck_cond is set). 

I have implemented the emulation in usb-storage with a special proto_handler,
and an unsual entry.

Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>
Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
 drivers/usb/storage/Kconfig         |   11 +
 drivers/usb/storage/Makefile        |    1 
 drivers/usb/storage/cypress_atacb.c |  200 ++++++++++++++++++++++++++++++++++++
 drivers/usb/storage/cypress_atacb.h |   25 ++++
 drivers/usb/storage/scsiglue.c      |    2 
 drivers/usb/storage/transport.c     |    3 
 drivers/usb/storage/unusual_devs.h  |    8 +
 drivers/usb/storage/usb.c           |   10 +
 include/linux/usb_usual.h           |    1 
 9 files changed, 259 insertions(+), 2 deletions(-)

--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -145,6 +145,17 @@ config USB_STORAGE_KARMA
 	  on the resulting scsi device node returns the Karma to normal
 	  operation.
 
+config USB_STORAGE_CYPRESS_ATACB
+	bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
+	depends on USB_STORAGE
+	---help---
+	  Say Y here if you want to use SAT (ata pass through) on devices based
+	  on the Cypress USB/ATA bridge supporting ATACB. This will allow you
+	  to use tools to tune and monitor your drive (like hdparm or smartctl).
+
+	  If you say no here your device will still work with the standard usb
+	  mass storage class.
+
 config USB_LIBUSUAL
 	bool "The shared table of common (or usual) storage devices"
 	depends on USB
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -21,6 +21,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_JUM
 usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA)	+= alauda.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)	+= karma.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
--- /dev/null
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -0,0 +1,200 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned char save_cmnd[MAX_COMMAND_SIZE];
+
+	if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
+		usb_stor_transparent_scsi_command(srb, us);
+		return;
+	}
+
+	memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+	memset(srb->cmnd, 0, sizeof(srb->cmnd));
+
+	/* check if we support the command */
+	if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+		goto invalid_fld;
+	/* check protocol */
+	switch((save_cmnd[1] >> 1) & 0xf) {
+		case 3: /*no DATA */
+		case 4: /* PIO in */
+		case 5: /* PIO out */
+			break;
+		default:
+			goto invalid_fld;
+	}
+
+	/* first build the ATACB command */
+	srb->cmd_len = 16;
+
+	srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command
+	                        this value can change, but most(all ?) manufacturers
+							keep the cypress default : 0x24 */
+	srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
+
+	srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med
+								lba high, device, command are valid */
+	srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
+
+	if (save_cmnd[0] == ATA_16) {
+		srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
+		srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
+		srb->cmnd[10] = save_cmnd[12]; /* lba high */
+		srb->cmnd[11] = save_cmnd[13]; /* device */
+		srb->cmnd[12] = save_cmnd[14]; /* command */
+
+		if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+			/* this could be supported by atacb2 */
+			if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+					|| save_cmnd[11])
+				goto invalid_fld;
+		}
+	}
+	else { /* ATA12 */
+		srb->cmnd[ 6] = save_cmnd[3]; /* features */
+		srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
+		srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
+		srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
+		srb->cmnd[10] = save_cmnd[7]; /* lba high */
+		srb->cmnd[11] = save_cmnd[8]; /* device */
+		srb->cmnd[12] = save_cmnd[9]; /* command */
+
+	}
+	/* Filter SET_FEATURES - XFER MODE command */
+	if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+			&& (srb->cmnd[6] == SETFEATURES_XFER))
+		goto invalid_fld;
+
+	if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+		srb->cmnd[2] |= (1<<7); /* set  IdentifyPacketDevice for these cmds */
+
+
+	usb_stor_transparent_scsi_command(srb, us);
+
+	/* if the device doesn't support ATACB
+	 */
+	if (srb->result == SAM_STAT_CHECK_CONDITION &&
+			memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+				sizeof(usb_stor_sense_invalidCDB)) == 0) {
+		US_DEBUGP("cypress atacb not supported ???\n");
+		goto end;
+	}
+
+	/* if ck_cond flags is set, and there wasn't critical error,
+	 * build the special sense
+	 */
+	if ((srb->result != (DID_ERROR << 16) &&
+				srb->result != (DID_ABORT << 16)) &&
+			save_cmnd[2] & 0x20) {
+		struct scsi_eh_save ses;
+		unsigned char regs[8];
+		unsigned char *sb = srb->sense_buffer;
+		unsigned char *desc = sb + 8;
+		int tmp_result;
+
+		/* build the command for
+		 * reading the ATA registers */
+		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0);
+		srb->sdb.length = sizeof(regs);
+		sg_init_one(&ses.sense_sgl, regs, srb->sdb.length);
+		srb->sdb.table.sgl = &ses.sense_sgl;
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+		srb->sdb.table.nents = 1;
+		/* we use the same command as before, but we set
+		 * the read taskfile bit, for not executing atacb command,
+		 * but reading register selected in srb->cmnd[4]
+		 */
+		srb->cmnd[2] = 1;
+
+		usb_stor_transparent_scsi_command(srb, us);
+		tmp_result = srb->result;
+		scsi_eh_restore_cmnd(srb, &ses);
+		/* we fail to get registers, report invalid command */
+		if (tmp_result != SAM_STAT_GOOD)
+			goto invalid_fld;
+
+		/* build the sense */
+		memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+		/* set sk, asc for a good command */
+		sb[1] = RECOVERED_ERROR;
+		sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+		sb[3] = 0x1D;
+
+		/* XXX we should generate sk, asc, ascq from status and error
+		 * regs
+		 * (see 11.1 Error translation ­ ATA device error to SCSI error map)
+		 * and ata_to_sense_error from libata.
+		 */
+
+		/* Sense data is current and format is descriptor. */
+		sb[0] = 0x72;
+		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+		/* set length of additional sense data */
+		sb[7] = 14;
+		desc[1] = 12;
+
+		/* Copy registers into sense buffer. */
+		desc[ 2] = 0x00;
+		desc[ 3] = regs[1];  /* features */
+		desc[ 5] = regs[2];  /* sector count */
+		desc[ 7] = regs[3];  /* lba low */
+		desc[ 9] = regs[4];  /* lba med */
+		desc[11] = regs[5];  /* lba high */
+		desc[12] = regs[6];  /* device */
+		desc[13] = regs[7];  /* command */
+
+		srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+	}
+	goto end;
+invalid_fld:
+	srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+	memcpy(srb->sense_buffer,
+			usb_stor_sense_invalidCDB,
+			sizeof(usb_stor_sense_invalidCDB));
+end:
+	memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+	if (srb->cmnd[0] == ATA_12)
+		srb->cmd_len = 12;
+}
--- /dev/null
+++ b/drivers/usb/storage/cypress_atacb.h
@@ -0,0 +1,25 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ *       on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CYPRESS_ATACB_H_
+#define _CYPRESS_ATACB_H_
+extern void cypress_atacb_passthrough(struct scsi_cmnd*, struct us_data*);
+#endif
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -132,7 +132,7 @@ static int slave_configure(struct scsi_d
 		/* Disk-type devices use MODE SENSE(6) if the protocol
 		 * (SubClass) is Transparent SCSI, otherwise they use
 		 * MODE SENSE(10). */
-		if (us->subclass != US_SC_SCSI)
+		if (us->subclass != US_SC_SCSI && us->subclass != US_SC_CYP_ATACB)
 			sdev->use_10_for_ms = 1;
 
 		/* Many disks only accept MODE SENSE transfer lengths of
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -603,7 +603,8 @@ void usb_stor_invoke_transport(struct sc
 		scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
 
 		/* FIXME: we must do the protocol translation here */
-		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI ||
+				us->subclass == US_SC_CYP_ATACB)
 			srb->cmd_len = 6;
 		else
 			srb->cmd_len = 12;
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1631,6 +1631,14 @@ UNUSUAL_DEV(  0xed06, 0x4500, 0x0001, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_CAPACITY_HEURISTICS),
 
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress AT2LP",
+		US_SC_CYP_ATACB, US_PR_BULK, NULL,
+		0),
+#endif
+
 /* Control/Bulk transport for all SubClass values */
 USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
 USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -101,6 +101,9 @@
 #ifdef CONFIG_USB_STORAGE_KARMA
 #include "karma.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+#include "cypress_atacb.h"
+#endif
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -708,6 +711,13 @@ static int get_protocol(struct us_data *
 		break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+	case US_SC_CYP_ATACB:
+		us->protocol_name = "Transparent SCSI with Cypress ATACB";
+		us->proto_handler = cypress_atacb_passthrough;
+		break;
+#endif
+
 	default:
 		return -EIO;
 	}
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -85,6 +85,7 @@ enum { US_DO_ALL_FLAGS };
 #define US_SC_LOCKABLE	0x07		/* Password-protected */
 
 #define US_SC_ISD200    0xf0		/* ISD200 ATA */
+#define US_SC_CYP_ATACB 0xf1		/* Cypress ATACB */
 #define US_SC_DEVICE	0xff		/* Use device's value */
 
 /* Protocols */


Patches currently in gregkh-2.6 which might be from castet.matthieu@free.fr are

usb/usb-mass-storage-emulation-of-sat-scsi_pass_thru-with-atacb.patch

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2008-03-20 21:40 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-08 17:32 [PATCH] mass storage : emulation of sat scsi_pass_thru with ATACB matthieu castet
2008-03-08 18:31 ` Matthew Dharm
2008-03-08 20:08   ` matthieu castet
2008-03-08 21:21     ` Matthew Dharm
2008-03-09  8:21       ` matthieu castet
2008-03-09 18:45         ` Matthew Dharm
2008-03-09 21:42           ` matthieu castet
2008-03-10  1:20             ` Matthew Dharm
2008-03-13 21:22               ` matthieu castet
2008-03-14  0:51                 ` Matthew Dharm
     [not found]                   ` <20080318221207.GY2820@one-eyed-alien.net>
2008-03-19 18:40                     ` matthieu castet
2008-03-19 20:02                       ` Matthew Dharm
2008-03-20 21:39                       ` patch usb-mass-storage-emulation-of-sat-scsi_pass_thru-with-atacb.patch added to gregkh-2.6 tree gregkh
2008-03-09 10:13   ` [PATCH] mass storage : emulation of sat scsi_pass_thru with ATACB Alan Cox

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).