All of lore.kernel.org
 help / color / mirror / Atom feed
From: matthieu castet <castet.matthieu-GANU6spQydw@public.gmane.org>
To: linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-scsi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Alan Stern
	<stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org>
Subject: Re: [RFC] mass storage : emulation of sat scsi_pass_thru with ATACB
Date: Fri, 29 Feb 2008 22:30:14 +0100	[thread overview]
Message-ID: <47C87966.6070106@free.fr> (raw)
In-Reply-To: <47C332E3.2070705-GANU6spQydw@public.gmane.org>

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

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). 
> 
> 
> First I start to add support for atacb in applications like smartctl.
> But there is some disadvantages :
> - I need to patch all application
> - 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).
> 
> So the idea to implement a SAT emulation for such device came to my mind.
> 
> First I want to ask, are there usb mass storage device that support SAT ?
> After some reading it seems impossible. Mass storage transparent scsi
> requires spc2 that only support fixed sense (starting with 0x70 or 0x71).
> But SAT need a sense with descriptor defined in spc3 (starting with 0x72
> or 0x73).
> 
> So SAT is not compatible with the sense format of mass storage ?
> 
> 
> 
> For doing the emulation, I want to provide a special proto_handler.
> 
> But I don't know what the best way to send command in my emulation layer :
> should I use usb_stor_invoke_transport or directly use us->transport.
> using usb_stor_invoke_transport save me lot's trouble of implementing
> error handling, but I can't control what I do.
> 
> What should I do if I got an error after sending the first command and
> ck_cond is set ? Should I still try to read the register ?
> 
> Is it safe to try to read the register if the first command did
> autosense ? Or should I only send the command, and read the register and
> compute the sense key, asc and ascq from registers ?
> 
> For the moment, my "draft" code look something like [1].
> 
> Any comments ?
> 
I attach a updated version of the driver.

I register the handler with an unsual entry. I don't know if it is the 
best way to do that (we need an entry for each device supporting atacb).

Another solution could have been to put the emulation in 
usb_stor_transparent_scsi_command, and if the device report invalidCDB 
don't try to use it again.

Any comments ?


Matthieu

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

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-02-29 22:18:02.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);
 }
 
+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;
+
+	srb->cmnd[0] = 0x24; /* XXX this value can change */
+	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 */
+			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;
+
+	/* realy needed ? isd200 don't do that */
+	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 ((srb->result != (DID_ERROR << 16) &&
+				srb->result != (DID_ABORT << 16)) &&
+			save_cmnd[2] & 0x20) { /* ck_cond */
+		/* read regs and put them in sense */
+		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;
+
+		if (srb->result == SAM_STAT_GOOD) {
+			/* OK */
+			sk = RECOVERED_ERROR;
+			asc = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+			ascq = 0x1D;
+		}
+		else {
+			/* save sense info */
+			/* XXX we get only 0, we should use regs status and error
+			 */
+#if 0
+			sk = sb[2];
+			asc = sb[12];
+			ascq = sb[13];
+#else
+			sk = ILLEGAL_REQUEST;
+			asc = 0x24;
+			ascq = 0;
+#endif
+		}
+
+
+		/* 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, sizeof(srb->sense_buffer));
+		/* XXX we should generate sk, asc, ascq from status and error
+		 * regs
+		 * (see 11.1 Error translation ­ ATA device error to SCSI error map)
+		 */
+		sb[1] = sk;
+		sb[2] = asc;
+		sb[3] = ascq;
+		sb[0] = 0x72;
+		desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+		sb[7] = 14;
+		desc[1] = 12;
+
+		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-02-29 22:16:03.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,13 @@
 	US_DEBUGP("usb_control_msg performing result is %d\n", result);
 	return (result ? 0 : -1);
 }
+
+/* This places register the atacb proto callback */
+int usb_atacb_init(struct us_data *us)
+{
+	/* XXX get atacb command from eeprom
+	 * ATM we assume the default : 0x24
+	 */
+	us->proto_handler = usb_stor_transparent_scsi_command_atacb;
+	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-02-29 22:16:03.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 places 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),

           reply	other threads:[~2008-02-29 21:30 UTC|newest]

Thread overview: expand[flat|nested]  mbox.gz  Atom feed
 [parent not found: <47C332E3.2070705-GANU6spQydw@public.gmane.org>]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=47C87966.6070106@free.fr \
    --to=castet.matthieu-ganu6spqydw@public.gmane.org \
    --cc=linux-scsi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.