Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: mass storage: emulation of sat scsi_pass_thru with ATACB

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>

authored by

matthieu castet and committed by
Greg Kroah-Hartman
d277064e dda43a0e

+259 -2
+11
drivers/usb/storage/Kconfig
··· 145 145 on the resulting scsi device node returns the Karma to normal 146 146 operation. 147 147 148 + config USB_STORAGE_CYPRESS_ATACB 149 + bool "SAT emulation on Cypress USB/ATA Bridge with ATACB" 150 + depends on USB_STORAGE 151 + ---help--- 152 + Say Y here if you want to use SAT (ata pass through) on devices based 153 + on the Cypress USB/ATA bridge supporting ATACB. This will allow you 154 + to use tools to tune and monitor your drive (like hdparm or smartctl). 155 + 156 + If you say no here your device will still work with the standard usb 157 + mass storage class. 158 + 148 159 config USB_LIBUSUAL 149 160 bool "The shared table of common (or usual) storage devices" 150 161 depends on USB
+1
drivers/usb/storage/Makefile
··· 21 21 usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o 22 22 usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o 23 23 usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o 24 + usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o 24 25 25 26 usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ 26 27 initializers.o $(usb-storage-obj-y)
+200
drivers/usb/storage/cypress_atacb.c
··· 1 + /* 2 + * Support for emulating SAT (ata pass through) on devices based 3 + * on the Cypress USB/ATA bridge supporting ATACB. 4 + * 5 + * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr) 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License as published by the 9 + * Free Software Foundation; either version 2, or (at your option) any 10 + * later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, but 13 + * WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 + * General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License along 18 + * with this program; if not, write to the Free Software Foundation, Inc., 19 + * 675 Mass Ave, Cambridge, MA 02139, USA. 20 + */ 21 + 22 + #include <scsi/scsi.h> 23 + #include <scsi/scsi_cmnd.h> 24 + #include <scsi/scsi_eh.h> 25 + #include <linux/ata.h> 26 + 27 + #include "usb.h" 28 + #include "protocol.h" 29 + #include "scsiglue.h" 30 + #include "debug.h" 31 + 32 + /* 33 + * ATACB is a protocol used on cypress usb<->ata bridge to 34 + * send raw ATA command over mass storage 35 + * There is a ATACB2 protocol that support LBA48 on newer chip. 36 + * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf 37 + * datasheet from cypress.com. 38 + */ 39 + void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) 40 + { 41 + unsigned char save_cmnd[MAX_COMMAND_SIZE]; 42 + 43 + if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) { 44 + usb_stor_transparent_scsi_command(srb, us); 45 + return; 46 + } 47 + 48 + memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd)); 49 + memset(srb->cmnd, 0, sizeof(srb->cmnd)); 50 + 51 + /* check if we support the command */ 52 + if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */ 53 + goto invalid_fld; 54 + /* check protocol */ 55 + switch((save_cmnd[1] >> 1) & 0xf) { 56 + case 3: /*no DATA */ 57 + case 4: /* PIO in */ 58 + case 5: /* PIO out */ 59 + break; 60 + default: 61 + goto invalid_fld; 62 + } 63 + 64 + /* first build the ATACB command */ 65 + srb->cmd_len = 16; 66 + 67 + srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command 68 + this value can change, but most(all ?) manufacturers 69 + keep the cypress default : 0x24 */ 70 + srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */ 71 + 72 + srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med 73 + lba high, device, command are valid */ 74 + srb->cmnd[4] = 1; /* TransferBlockCount : 512 */ 75 + 76 + if (save_cmnd[0] == ATA_16) { 77 + srb->cmnd[ 6] = save_cmnd[ 4]; /* features */ 78 + srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */ 79 + srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */ 80 + srb->cmnd[ 9] = save_cmnd[10]; /* lba med */ 81 + srb->cmnd[10] = save_cmnd[12]; /* lba high */ 82 + srb->cmnd[11] = save_cmnd[13]; /* device */ 83 + srb->cmnd[12] = save_cmnd[14]; /* command */ 84 + 85 + if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */ 86 + /* this could be supported by atacb2 */ 87 + if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9] 88 + || save_cmnd[11]) 89 + goto invalid_fld; 90 + } 91 + } 92 + else { /* ATA12 */ 93 + srb->cmnd[ 6] = save_cmnd[3]; /* features */ 94 + srb->cmnd[ 7] = save_cmnd[4]; /* sector count */ 95 + srb->cmnd[ 8] = save_cmnd[5]; /* lba low */ 96 + srb->cmnd[ 9] = save_cmnd[6]; /* lba med */ 97 + srb->cmnd[10] = save_cmnd[7]; /* lba high */ 98 + srb->cmnd[11] = save_cmnd[8]; /* device */ 99 + srb->cmnd[12] = save_cmnd[9]; /* command */ 100 + 101 + } 102 + /* Filter SET_FEATURES - XFER MODE command */ 103 + if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES) 104 + && (srb->cmnd[6] == SETFEATURES_XFER)) 105 + goto invalid_fld; 106 + 107 + if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI) 108 + srb->cmnd[2] |= (1<<7); /* set IdentifyPacketDevice for these cmds */ 109 + 110 + 111 + usb_stor_transparent_scsi_command(srb, us); 112 + 113 + /* if the device doesn't support ATACB 114 + */ 115 + if (srb->result == SAM_STAT_CHECK_CONDITION && 116 + memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB, 117 + sizeof(usb_stor_sense_invalidCDB)) == 0) { 118 + US_DEBUGP("cypress atacb not supported ???\n"); 119 + goto end; 120 + } 121 + 122 + /* if ck_cond flags is set, and there wasn't critical error, 123 + * build the special sense 124 + */ 125 + if ((srb->result != (DID_ERROR << 16) && 126 + srb->result != (DID_ABORT << 16)) && 127 + save_cmnd[2] & 0x20) { 128 + struct scsi_eh_save ses; 129 + unsigned char regs[8]; 130 + unsigned char *sb = srb->sense_buffer; 131 + unsigned char *desc = sb + 8; 132 + int tmp_result; 133 + 134 + /* build the command for 135 + * reading the ATA registers */ 136 + scsi_eh_prep_cmnd(srb, &ses, NULL, 0, 0); 137 + srb->sdb.length = sizeof(regs); 138 + sg_init_one(&ses.sense_sgl, regs, srb->sdb.length); 139 + srb->sdb.table.sgl = &ses.sense_sgl; 140 + srb->sc_data_direction = DMA_FROM_DEVICE; 141 + srb->sdb.table.nents = 1; 142 + /* we use the same command as before, but we set 143 + * the read taskfile bit, for not executing atacb command, 144 + * but reading register selected in srb->cmnd[4] 145 + */ 146 + srb->cmnd[2] = 1; 147 + 148 + usb_stor_transparent_scsi_command(srb, us); 149 + tmp_result = srb->result; 150 + scsi_eh_restore_cmnd(srb, &ses); 151 + /* we fail to get registers, report invalid command */ 152 + if (tmp_result != SAM_STAT_GOOD) 153 + goto invalid_fld; 154 + 155 + /* build the sense */ 156 + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); 157 + 158 + /* set sk, asc for a good command */ 159 + sb[1] = RECOVERED_ERROR; 160 + sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */ 161 + sb[3] = 0x1D; 162 + 163 + /* XXX we should generate sk, asc, ascq from status and error 164 + * regs 165 + * (see 11.1 Error translation � ATA device error to SCSI error map) 166 + * and ata_to_sense_error from libata. 167 + */ 168 + 169 + /* Sense data is current and format is descriptor. */ 170 + sb[0] = 0x72; 171 + desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */ 172 + 173 + /* set length of additional sense data */ 174 + sb[7] = 14; 175 + desc[1] = 12; 176 + 177 + /* Copy registers into sense buffer. */ 178 + desc[ 2] = 0x00; 179 + desc[ 3] = regs[1]; /* features */ 180 + desc[ 5] = regs[2]; /* sector count */ 181 + desc[ 7] = regs[3]; /* lba low */ 182 + desc[ 9] = regs[4]; /* lba med */ 183 + desc[11] = regs[5]; /* lba high */ 184 + desc[12] = regs[6]; /* device */ 185 + desc[13] = regs[7]; /* command */ 186 + 187 + srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 188 + } 189 + goto end; 190 + invalid_fld: 191 + srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 192 + 193 + memcpy(srb->sense_buffer, 194 + usb_stor_sense_invalidCDB, 195 + sizeof(usb_stor_sense_invalidCDB)); 196 + end: 197 + memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd)); 198 + if (srb->cmnd[0] == ATA_12) 199 + srb->cmd_len = 12; 200 + }
+25
drivers/usb/storage/cypress_atacb.h
··· 1 + /* 2 + * Support for emulating SAT (ata pass through) on devices based 3 + * on the Cypress USB/ATA bridge supporting ATACB. 4 + * 5 + * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr) 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License as published by the 9 + * Free Software Foundation; either version 2, or (at your option) any 10 + * later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, but 13 + * WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 + * General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License along 18 + * with this program; if not, write to the Free Software Foundation, Inc., 19 + * 675 Mass Ave, Cambridge, MA 02139, USA. 20 + */ 21 + 22 + #ifndef _CYPRESS_ATACB_H_ 23 + #define _CYPRESS_ATACB_H_ 24 + extern void cypress_atacb_passthrough(struct scsi_cmnd*, struct us_data*); 25 + #endif
+1 -1
drivers/usb/storage/scsiglue.c
··· 132 132 /* Disk-type devices use MODE SENSE(6) if the protocol 133 133 * (SubClass) is Transparent SCSI, otherwise they use 134 134 * MODE SENSE(10). */ 135 - if (us->subclass != US_SC_SCSI) 135 + if (us->subclass != US_SC_SCSI && us->subclass != US_SC_CYP_ATACB) 136 136 sdev->use_10_for_ms = 1; 137 137 138 138 /* Many disks only accept MODE SENSE transfer lengths of
+2 -1
drivers/usb/storage/transport.c
··· 603 603 scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE); 604 604 605 605 /* FIXME: we must do the protocol translation here */ 606 - if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI) 606 + if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI || 607 + us->subclass == US_SC_CYP_ATACB) 607 608 srb->cmd_len = 6; 608 609 else 609 610 srb->cmd_len = 12;
+8
drivers/usb/storage/unusual_devs.h
··· 1719 1719 US_SC_DEVICE, US_PR_DEVICE, NULL, 1720 1720 US_FL_CAPACITY_HEURISTICS), 1721 1721 1722 + #ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB 1723 + UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999, 1724 + "Cypress", 1725 + "Cypress AT2LP", 1726 + US_SC_CYP_ATACB, US_PR_BULK, NULL, 1727 + 0), 1728 + #endif 1729 + 1722 1730 /* Control/Bulk transport for all SubClass values */ 1723 1731 USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR), 1724 1732 USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
+10
drivers/usb/storage/usb.c
··· 101 101 #ifdef CONFIG_USB_STORAGE_KARMA 102 102 #include "karma.h" 103 103 #endif 104 + #ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB 105 + #include "cypress_atacb.h" 106 + #endif 104 107 105 108 /* Some informational data */ 106 109 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); ··· 708 705 case US_SC_ISD200: 709 706 us->protocol_name = "ISD200 ATA/ATAPI"; 710 707 us->proto_handler = isd200_ata_command; 708 + break; 709 + #endif 710 + 711 + #ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB 712 + case US_SC_CYP_ATACB: 713 + us->protocol_name = "Transparent SCSI with Cypress ATACB"; 714 + us->proto_handler = cypress_atacb_passthrough; 711 715 break; 712 716 #endif 713 717
+1
include/linux/usb_usual.h
··· 85 85 #define US_SC_LOCKABLE 0x07 /* Password-protected */ 86 86 87 87 #define US_SC_ISD200 0xf0 /* ISD200 ATA */ 88 + #define US_SC_CYP_ATACB 0xf1 /* Cypress ATACB */ 88 89 #define US_SC_DEVICE 0xff /* Use device's value */ 89 90 90 91 /* Protocols */