Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 93314
b: refs/heads/master
c: d277064
h: refs/heads/master
v: v3
  • Loading branch information
matthieu castet authored and Greg Kroah-Hartman committed Apr 25, 2008
1 parent bb794da commit 78f3663
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: dda43a0e03a33dd716fb34f812b1af614f74daff
refs/heads/master: d277064e7e16d02e0078a6bc1820764ae00dea87
11 changes: 11 additions & 0 deletions trunk/drivers/usb/storage/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/usb/storage/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
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)
Expand Down
200 changes: 200 additions & 0 deletions trunk/drivers/usb/storage/cypress_atacb.c
Original file line number Diff line number Diff line change
@@ -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;
}
25 changes: 25 additions & 0 deletions trunk/drivers/usb/storage/cypress_atacb.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion trunk/drivers/usb/storage/scsiglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ static int slave_configure(struct scsi_device *sdev)
/* 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
Expand Down
3 changes: 2 additions & 1 deletion trunk/drivers/usb/storage/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
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;
Expand Down
8 changes: 8 additions & 0 deletions trunk/drivers/usb/storage/unusual_devs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,14 @@ UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001,
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),
Expand Down
10 changes: 10 additions & 0 deletions trunk/drivers/usb/storage/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>");
Expand Down Expand Up @@ -708,6 +711,13 @@ static int get_protocol(struct us_data *us)
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;
}
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/usb_usual.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit 78f3663

Please sign in to comment.