From: matthieu castet <castet.matthieu@free.fr>
To: linux-usb@vger.kernel.org
Cc: Linux Kernel list <linux-kernel@vger.kernel.org>
Subject: [PATCH] mass storage : emulation of sat scsi_pass_thru with ATACB
Date: Sat, 08 Mar 2008 18:32:05 +0100 [thread overview]
Message-ID: <47D2CD95.9070701@free.fr> (raw)
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),
next reply other threads:[~2008-03-08 17:32 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-03-08 17:32 matthieu castet [this message]
2008-03-08 18:31 ` [PATCH] mass storage : emulation of sat scsi_pass_thru with ATACB 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
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=47D2CD95.9070701@free.fr \
--to=castet.matthieu@free.fr \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.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.