diff options
Diffstat (limited to 'drivers/usb/storage/sddr09.c')
-rw-r--r-- | drivers/usb/storage/sddr09.c | 1608 |
1 files changed, 1608 insertions, 0 deletions
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c new file mode 100644 index 000000000000..0ea2f5ab66ba --- /dev/null +++ b/drivers/usb/storage/sddr09.c @@ -0,0 +1,1608 @@ +/* Driver for SanDisk SDDR-09 SmartMedia reader + * + * $Id: sddr09.c,v 1.24 2002/04/22 03:39:43 mdharm Exp $ + * (c) 2000, 2001 Robert Baruch (autophile@starband.net) + * (c) 2002 Andries Brouwer (aeb@cwi.nl) + * Developed with the assistance of: + * (c) 2002 Alan Stern <stern@rowland.org> + * + * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. + * This chip is a programmable USB controller. In the SDDR-09, it has + * been programmed to obey a certain limited set of SCSI commands. + * This driver translates the "real" SCSI commands to the SDDR-09 SCSI + * commands. + * + * 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. + */ + +/* + * Known vendor commands: 12 bytes, first byte is opcode + * + * E7: read scatter gather + * E8: read + * E9: write + * EA: erase + * EB: reset + * EC: read status + * ED: read ID + * EE: write CIS (?) + * EF: compute checksum (?) + */ + +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/slab.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> + +#include "usb.h" +#include "transport.h" +#include "protocol.h" +#include "debug.h" +#include "sddr09.h" + + +#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) +#define LSB_of(s) ((s)&0xFF) +#define MSB_of(s) ((s)>>8) + +/* #define US_DEBUGP printk */ + +/* + * First some stuff that does not belong here: + * data on SmartMedia and other cards, completely + * unrelated to this driver. + * Similar stuff occurs in <linux/mtd/nand_ids.h>. + */ + +struct nand_flash_dev { + int model_id; + int chipshift; /* 1<<cs bytes total capacity */ + char pageshift; /* 1<<ps bytes in a page */ + char blockshift; /* 1<<bs pages in an erase block */ + char zoneshift; /* 1<<zs blocks in a zone */ + /* # of logical blocks is 125/128 of this */ + char pageadrlen; /* length of an address in bytes - 1 */ +}; + +/* + * NAND Flash Manufacturer ID Codes + */ +#define NAND_MFR_AMD 0x01 +#define NAND_MFR_NATSEMI 0x8f +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec + +static inline char *nand_flash_manufacturer(int manuf_id) { + switch(manuf_id) { + case NAND_MFR_AMD: + return "AMD"; + case NAND_MFR_NATSEMI: + return "NATSEMI"; + case NAND_MFR_TOSHIBA: + return "Toshiba"; + case NAND_MFR_SAMSUNG: + return "Samsung"; + default: + return "unknown"; + } +} + +/* + * It looks like it is unnecessary to attach manufacturer to the + * remaining data: SSFDC prescribes manufacturer-independent id codes. + * + * 256 MB NAND flash has a 5-byte ID with 2nd byte 0xaa, 0xba, 0xca or 0xda. + */ + +static struct nand_flash_dev nand_flash_ids[] = { + /* NAND flash */ + { 0x6e, 20, 8, 4, 8, 2}, /* 1 MB */ + { 0xe8, 20, 8, 4, 8, 2}, /* 1 MB */ + { 0xec, 20, 8, 4, 8, 2}, /* 1 MB */ + { 0x64, 21, 8, 4, 9, 2}, /* 2 MB */ + { 0xea, 21, 8, 4, 9, 2}, /* 2 MB */ + { 0x6b, 22, 9, 4, 9, 2}, /* 4 MB */ + { 0xe3, 22, 9, 4, 9, 2}, /* 4 MB */ + { 0xe5, 22, 9, 4, 9, 2}, /* 4 MB */ + { 0xe6, 23, 9, 4, 10, 2}, /* 8 MB */ + { 0x73, 24, 9, 5, 10, 2}, /* 16 MB */ + { 0x75, 25, 9, 5, 10, 2}, /* 32 MB */ + { 0x76, 26, 9, 5, 10, 3}, /* 64 MB */ + { 0x79, 27, 9, 5, 10, 3}, /* 128 MB */ + + /* MASK ROM */ + { 0x5d, 21, 9, 4, 8, 2}, /* 2 MB */ + { 0xd5, 22, 9, 4, 9, 2}, /* 4 MB */ + { 0xd6, 23, 9, 4, 10, 2}, /* 8 MB */ + { 0x57, 24, 9, 4, 11, 2}, /* 16 MB */ + { 0x58, 25, 9, 4, 12, 2}, /* 32 MB */ + { 0,} +}; + +#define SIZE(a) (sizeof(a)/sizeof((a)[0])) + +static struct nand_flash_dev * +nand_find_id(unsigned char id) { + int i; + + for (i = 0; i < SIZE(nand_flash_ids); i++) + if (nand_flash_ids[i].model_id == id) + return &(nand_flash_ids[i]); + return NULL; +} + +/* + * ECC computation. + */ +static unsigned char parity[256]; +static unsigned char ecc2[256]; + +static void nand_init_ecc(void) { + int i, j, a; + + parity[0] = 0; + for (i = 1; i < 256; i++) + parity[i] = (parity[i&(i-1)] ^ 1); + + for (i = 0; i < 256; i++) { + a = 0; + for (j = 0; j < 8; j++) { + if (i & (1<<j)) { + if ((j & 1) == 0) + a ^= 0x04; + if ((j & 2) == 0) + a ^= 0x10; + if ((j & 4) == 0) + a ^= 0x40; + } + } + ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0)); + } +} + +/* compute 3-byte ecc on 256 bytes */ +static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) { + int i, j, a; + unsigned char par, bit, bits[8]; + + par = 0; + for (j = 0; j < 8; j++) + bits[j] = 0; + + /* collect 16 checksum bits */ + for (i = 0; i < 256; i++) { + par ^= data[i]; + bit = parity[data[i]]; + for (j = 0; j < 8; j++) + if ((i & (1<<j)) == 0) + bits[j] ^= bit; + } + + /* put 4+4+4 = 12 bits in the ecc */ + a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0]; + ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0)); + + a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4]; + ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0)); + + ecc[2] = ecc2[par]; +} + +static int nand_compare_ecc(unsigned char *data, unsigned char *ecc) { + return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]); +} + +static void nand_store_ecc(unsigned char *data, unsigned char *ecc) { + memcpy(data, ecc, 3); +} + +/* + * The actual driver starts here. + */ + +/* + * On my 16MB card, control blocks have size 64 (16 real control bytes, + * and 48 junk bytes). In reality of course the card uses 16 control bytes, + * so the reader makes up the remaining 48. Don't know whether these numbers + * depend on the card. For now a constant. + */ +#define CONTROL_SHIFT 6 + +/* + * On my Combo CF/SM reader, the SM reader has LUN 1. + * (and things fail with LUN 0). + * It seems LUN is irrelevant for others. + */ +#define LUN 1 +#define LUNBITS (LUN << 5) + +/* + * LBA and PBA are unsigned ints. Special values. + */ +#define UNDEF 0xffffffff +#define SPARE 0xfffffffe +#define UNUSABLE 0xfffffffd + +static int erase_bad_lba_entries = 0; + +/* send vendor interface command (0x41) */ +/* called for requests 0, 1, 8 */ +static int +sddr09_send_command(struct us_data *us, + unsigned char request, + unsigned char direction, + unsigned char *xfer_data, + unsigned int xfer_len) { + unsigned int pipe; + unsigned char requesttype = (0x41 | direction); + int rc; + + // Get the receive or send control pipe number + + if (direction == USB_DIR_IN) + pipe = us->recv_ctrl_pipe; + else + pipe = us->send_ctrl_pipe; + + rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype, + 0, 0, xfer_data, xfer_len); + return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : + USB_STOR_TRANSPORT_ERROR); +} + +static int +sddr09_send_scsi_command(struct us_data *us, + unsigned char *command, + unsigned int command_len) { + return sddr09_send_command(us, 0, USB_DIR_OUT, command, command_len); +} + +#if 0 +/* + * Test Unit Ready Command: 12 bytes. + * byte 0: opcode: 00 + */ +static int +sddr09_test_unit_ready(struct us_data *us) { + unsigned char *command = us->iobuf; + int result; + + memset(command, 0, 6); + command[1] = LUNBITS; + + result = sddr09_send_scsi_command(us, command, 6); + + US_DEBUGP("sddr09_test_unit_ready returns %d\n", result); + + return result; +} +#endif + +/* + * Request Sense Command: 12 bytes. + * byte 0: opcode: 03 + * byte 4: data length + */ +static int +sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { + unsigned char *command = us->iobuf; + int result; + + memset(command, 0, 12); + command[0] = 0x03; + command[1] = LUNBITS; + command[4] = buflen; + + result = sddr09_send_scsi_command(us, command, 12); + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("request sense failed\n"); + return result; + } + + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + sensebuf, buflen, NULL); + if (result != USB_STOR_XFER_GOOD) { + US_DEBUGP("request sense bulk in failed\n"); + return USB_STOR_TRANSPORT_ERROR; + } else { + US_DEBUGP("request sense worked\n"); + return USB_STOR_TRANSPORT_GOOD; + } +} + +/* + * Read Command: 12 bytes. + * byte 0: opcode: E8 + * byte 1: last two bits: 00: read data, 01: read blockwise control, + * 10: read both, 11: read pagewise control. + * It turns out we need values 20, 21, 22, 23 here (LUN 1). + * bytes 2-5: address (interpretation depends on byte 1, see below) + * bytes 10-11: count (idem) + * + * A page has 512 data bytes and 64 control bytes (16 control and 48 junk). + * A read data command gets data in 512-byte pages. + * A read control command gets control in 64-byte chunks. + * A read both command gets data+control in 576-byte chunks. + * + * Blocks are groups of 32 pages, and read blockwise control jumps to the + * next block, while read pagewise control jumps to the next page after + * reading a group of 64 control bytes. + * [Here 512 = 1<<pageshift, 32 = 1<<blockshift, 64 is constant?] + * + * (1 MB and 2 MB cards are a bit different, but I have only a 16 MB card.) + */ + +static int +sddr09_readX(struct us_data *us, int x, unsigned long fromaddress, + int nr_of_pages, int bulklen, unsigned char *buf, + int use_sg) { + + unsigned char *command = us->iobuf; + int result; + + command[0] = 0xE8; + command[1] = LUNBITS | x; + command[2] = MSB_of(fromaddress>>16); + command[3] = LSB_of(fromaddress>>16); + command[4] = MSB_of(fromaddress & 0xFFFF); + command[5] = LSB_of(fromaddress & 0xFFFF); + command[6] = 0; + command[7] = 0; + command[8] = 0; + command[9] = 0; + command[10] = MSB_of(nr_of_pages); + command[11] = LSB_of(nr_of_pages); + + result = sddr09_send_scsi_command(us, command, 12); + + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("Result for send_control in sddr09_read2%d %d\n", + x, result); + return result; + } + + result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, + buf, bulklen, use_sg, NULL); + + if (result != USB_STOR_XFER_GOOD) { + US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n", + x, result); + return USB_STOR_TRANSPORT_ERROR; + } + return USB_STOR_TRANSPORT_GOOD; +} + +/* + * Read Data + * + * fromaddress counts data shorts: + * increasing it by 256 shifts the bytestream by 512 bytes; + * the last 8 bits are ignored. + * + * nr_of_pages counts pages of size (1 << pageshift). + */ +static int +sddr09_read20(struct us_data *us, unsigned long fromaddress, + int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { + int bulklen = nr_of_pages << pageshift; + + /* The last 8 bits of fromaddress are ignored. */ + return sddr09_readX(us, 0, fromaddress, nr_of_pages, bulklen, + buf, use_sg); +} + +/* + * Read Blockwise Control + * + * fromaddress gives the starting position (as in read data; + * the last 8 bits are ignored); increasing it by 32*256 shifts + * the output stream by 64 bytes. + * + * count counts control groups of size (1 << controlshift). + * For me, controlshift = 6. Is this constant? + * + * After getting one control group, jump to the next block + * (fromaddress += 8192). + */ +static int +sddr09_read21(struct us_data *us, unsigned long fromaddress, + int count, int controlshift, unsigned char *buf, int use_sg) { + + int bulklen = (count << controlshift); + return sddr09_readX(us, 1, fromaddress, count, bulklen, + buf, use_sg); +} + +/* + * Read both Data and Control + * + * fromaddress counts data shorts, ignoring control: + * increasing it by 256 shifts the bytestream by 576 = 512+64 bytes; + * the last 8 bits are ignored. + * + * nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift). + */ +static int +sddr09_read22(struct us_data *us, unsigned long fromaddress, + int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { + + int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); + US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n", + nr_of_pages, bulklen); + return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen, + buf, use_sg); +} + +#if 0 +/* + * Read Pagewise Control + * + * fromaddress gives the starting position (as in read data; + * the last 8 bits are ignored); increasing it by 256 shifts + * the output stream by 64 bytes. + * + * count counts control groups of size (1 << controlshift). + * For me, controlshift = 6. Is this constant? + * + * After getting one control group, jump to the next page + * (fromaddress += 256). + */ +static int +sddr09_read23(struct us_data *us, unsigned long fromaddress, + int count, int controlshift, unsigned char *buf, int use_sg) { + + int bulklen = (count << controlshift); + return sddr09_readX(us, 3, fromaddress, count, bulklen, + buf, use_sg); +} +#endif + +/* + * Erase Command: 12 bytes. + * byte 0: opcode: EA + * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). + * + * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored. + * The byte address being erased is 2*Eaddress. + * The CIS cannot be erased. + */ +static int +sddr09_erase(struct us_data *us, unsigned long Eaddress) { + unsigned char *command = us->iobuf; + int result; + + US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress); + + memset(command, 0, 12); + command[0] = 0xEA; + command[1] = LUNBITS; + command[6] = MSB_of(Eaddress>>16); + command[7] = LSB_of(Eaddress>>16); + command[8] = MSB_of(Eaddress & 0xFFFF); + command[9] = LSB_of(Eaddress & 0xFFFF); + + result = sddr09_send_scsi_command(us, command, 12); + + if (result != USB_STOR_TRANSPORT_GOOD) + US_DEBUGP("Result for send_control in sddr09_erase %d\n", + result); + + return result; +} + +/* + * Write CIS Command: 12 bytes. + * byte 0: opcode: EE + * bytes 2-5: write address in shorts + * bytes 10-11: sector count + * + * This writes at the indicated address. Don't know how it differs + * from E9. Maybe it does not erase? However, it will also write to + * the CIS. + * + * When two such commands on the same page follow each other directly, + * the second one is not done. + */ + +/* + * Write Command: 12 bytes. + * byte 0: opcode: E9 + * bytes 2-5: write address (big-endian, counting shorts, sector aligned). + * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). + * bytes 10-11: sector count (big-endian, in 512-byte sectors). + * + * If write address equals erase address, the erase is done first, + * otherwise the write is done first. When erase address equals zero + * no erase is done? + */ +static int +sddr09_writeX(struct us_data *us, + unsigned long Waddress, unsigned long Eaddress, + int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) { + + unsigned char *command = us->iobuf; + int result; + + command[0] = 0xE9; + command[1] = LUNBITS; + + command[2] = MSB_of(Waddress>>16); + command[3] = LSB_of(Waddress>>16); + command[4] = MSB_of(Waddress & 0xFFFF); + command[5] = LSB_of(Waddress & 0xFFFF); + + command[6] = MSB_of(Eaddress>>16); + command[7] = LSB_of(Eaddress>>16); + command[8] = MSB_of(Eaddress & 0xFFFF); + command[9] = LSB_of(Eaddress & 0xFFFF); + + command[10] = MSB_of(nr_of_pages); + command[11] = LSB_of(nr_of_pages); + + result = sddr09_send_scsi_command(us, command, 12); + + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("Result for send_control in sddr09_writeX %d\n", + result); + return result; + } + + result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, + buf, bulklen, use_sg, NULL); + + if (result != USB_STOR_XFER_GOOD) { + US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n", + result); + return USB_STOR_TRANSPORT_ERROR; + } + return USB_STOR_TRANSPORT_GOOD; +} + +/* erase address, write same address */ +static int +sddr09_write_inplace(struct us_data *us, unsigned long address, + int nr_of_pages, int pageshift, unsigned char *buf, + int use_sg) { + int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); + return sddr09_writeX(us, address, address, nr_of_pages, bulklen, + buf, use_sg); +} + +#if 0 +/* + * Read Scatter Gather Command: 3+4n bytes. + * byte 0: opcode E7 + * byte 2: n + * bytes 4i-1,4i,4i+1: page address + * byte 4i+2: page count + * (i=1..n) + * + * This reads several pages from the card to a single memory buffer. + * The last two bits of byte 1 have the same meaning as for E8. + */ +static int +sddr09_read_sg_test_only(struct us_data *us) { + unsigned char *command = us->iobuf; + int result, bulklen, nsg, ct; + unsigned char *buf; + unsigned long address; + + nsg = bulklen = 0; + command[0] = 0xE7; + command[1] = LUNBITS; + command[2] = 0; + address = 040000; ct = 1; + nsg++; + bulklen += (ct << 9); + command[4*nsg+2] = ct; + command[4*nsg+1] = ((address >> 9) & 0xFF); + command[4*nsg+0] = ((address >> 17) & 0xFF); + command[4*nsg-1] = ((address >> 25) & 0xFF); + + address = 0340000; ct = 1; + nsg++; + bulklen += (ct << 9); + command[4*nsg+2] = ct; + command[4*nsg+1] = ((address >> 9) & 0xFF); + command[4*nsg+0] = ((address >> 17) & 0xFF); + command[4*nsg-1] = ((address >> 25) & 0xFF); + + address = 01000000; ct = 2; + nsg++; + bulklen += (ct << 9); + command[4*nsg+2] = ct; + command[4*nsg+1] = ((address >> 9) & 0xFF); + command[4*nsg+0] = ((address >> 17) & 0xFF); + command[4*nsg-1] = ((address >> 25) & 0xFF); + + command[2] = nsg; + + result = sddr09_send_scsi_command(us, command, 4*nsg+3); + + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("Result for send_control in sddr09_read_sg %d\n", + result); + return result; + } + + buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO); + if (!buf) + return USB_STOR_TRANSPORT_ERROR; + + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + buf, bulklen, NULL); + kfree(buf); + if (result != USB_STOR_XFER_GOOD) { + US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n", + result); + return USB_STOR_TRANSPORT_ERROR; + } + + return USB_STOR_TRANSPORT_GOOD; +} +#endif + +/* + * Read Status Command: 12 bytes. + * byte 0: opcode: EC + * + * Returns 64 bytes, all zero except for the first. + * bit 0: 1: Error + * bit 5: 1: Suspended + * bit 6: 1: Ready + * bit 7: 1: Not write-protected + */ + +static int +sddr09_read_status(struct us_data *us, unsigned char *status) { + + unsigned char *command = us->iobuf; + unsigned char *data = us->iobuf; + int result; + + US_DEBUGP("Reading status...\n"); + + memset(command, 0, 12); + command[0] = 0xEC; + command[1] = LUNBITS; + + result = sddr09_send_scsi_command(us, command, 12); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, 64, NULL); + *status = data[0]; + return (result == USB_STOR_XFER_GOOD ? + USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); +} + +static int +sddr09_read_data(struct us_data *us, + unsigned long address, + unsigned int sectors) { + + struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; + unsigned char *buffer; + unsigned int lba, maxlba, pba; + unsigned int page, pages; + unsigned int len, index, offset; + int result; + + // Since we only read in one block at a time, we have to create + // a bounce buffer and move the data a piece at a time between the + // bounce buffer and the actual transfer buffer. + + len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; + buffer = kmalloc(len, GFP_NOIO); + if (buffer == NULL) { + printk("sddr09_read_data: Out of memory\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + // Figure out the initial LBA and page + lba = address >> info->blockshift; + page = (address & info->blockmask); + maxlba = info->capacity >> (info->pageshift + info->blockshift); + + // This could be made much more efficient by checking for + // contiguous LBA's. Another exercise left to the student. + + result = USB_STOR_TRANSPORT_GOOD; + index = offset = 0; + + while (sectors > 0) { + + /* Find number of pages we can read in this block */ + pages = min(sectors, info->blocksize - page); + len = pages << info->pageshift; + + /* Not overflowing capacity? */ + if (lba >= maxlba) { + US_DEBUGP("Error: Requested lba %u exceeds " + "maximum %u\n", lba, maxlba); + result = USB_STOR_TRANSPORT_ERROR; + break; + } + + /* Find where this lba lives on disk */ + pba = info->lba_to_pba[lba]; + + if (pba == UNDEF) { /* this lba was never written */ + + US_DEBUGP("Read %d zero pages (LBA %d) page %d\n", + pages, lba, page); + + /* This is not really an error. It just means + that the block has never been written. + Instead of returning USB_STOR_TRANSPORT_ERROR + it is better to return all zero data. */ + + memset(buffer, 0, len); + + } else { + US_DEBUGP("Read %d pages, from PBA %d" + " (LBA %d) page %d\n", + pages, pba, lba, page); + + address = ((pba << info->blockshift) + page) << + info->pageshift; + + result = sddr09_read20(us, address>>1, + pages, info->pageshift, buffer, 0); + if (result != USB_STOR_TRANSPORT_GOOD) + break; + } + + // Store the data in the transfer buffer + usb_stor_access_xfer_buf(buffer, len, us->srb, + &index, &offset, TO_XFER_BUF); + + page = 0; + lba++; + sectors -= pages; + } + + kfree(buffer); + return result; +} + +static unsigned int +sddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) { + static unsigned int lastpba = 1; + int zonestart, end, i; + + zonestart = (lba/1000) << 10; + end = info->capacity >> (info->blockshift + info->pageshift); + end -= zonestart; + if (end > 1024) + end = 1024; + + for (i = lastpba+1; i < end; i++) { + if (info->pba_to_lba[zonestart+i] == UNDEF) { + lastpba = i; + return zonestart+i; + } + } + for (i = 0; i <= lastpba; i++) { + if (info->pba_to_lba[zonestart+i] == UNDEF) { + lastpba = i; + return zonestart+i; + } + } + return 0; +} + +static int +sddr09_write_lba(struct us_data *us, unsigned int lba, + unsigned int page, unsigned int pages, + unsigned char *ptr, unsigned char *blockbuffer) { + + struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; + unsigned long address; + unsigned int pba, lbap; + unsigned int pagelen; + unsigned char *bptr, *cptr, *xptr; + unsigned char ecc[3]; + int i, result, isnew; + + lbap = ((lba % 1000) << 1) | 0x1000; + if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) + lbap ^= 1; + pba = info->lba_to_pba[lba]; + isnew = 0; + + if (pba == UNDEF) { + pba = sddr09_find_unused_pba(info, lba); + if (!pba) { + printk("sddr09_write_lba: Out of unused blocks\n"); + return USB_STOR_TRANSPORT_ERROR; + } + info->pba_to_lba[pba] = lba; + info->lba_to_pba[lba] = pba; + isnew = 1; + } + + if (pba == 1) { + /* Maybe it is impossible to write to PBA 1. + Fake success, but don't do anything. */ + printk("sddr09: avoid writing to pba 1\n"); + return USB_STOR_TRANSPORT_GOOD; + } + + pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); + + /* read old contents */ + address = (pba << (info->pageshift + info->blockshift)); + result = sddr09_read22(us, address>>1, info->blocksize, + info->pageshift, blockbuffer, 0); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + + /* check old contents and fill lba */ + for (i = 0; i < info->blocksize; i++) { + bptr = blockbuffer + i*pagelen; + cptr = bptr + info->pagesize; + nand_compute_ecc(bptr, ecc); + if (!nand_compare_ecc(cptr+13, ecc)) { + US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n", + i, pba); + nand_store_ecc(cptr+13, ecc); + } + nand_compute_ecc(bptr+(info->pagesize / 2), ecc); + if (!nand_compare_ecc(cptr+8, ecc)) { + US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n", + i, pba); + nand_store_ecc(cptr+8, ecc); + } + cptr[6] = cptr[11] = MSB_of(lbap); + cptr[7] = cptr[12] = LSB_of(lbap); + } + + /* copy in new stuff and compute ECC */ + xptr = ptr; + for (i = page; i < page+pages; i++) { + bptr = blockbuffer + i*pagelen; + cptr = bptr + info->pagesize; + memcpy(bptr, xptr, info->pagesize); + xptr += info->pagesize; + nand_compute_ecc(bptr, ecc); + nand_store_ecc(cptr+13, ecc); + nand_compute_ecc(bptr+(info->pagesize / 2), ecc); + nand_store_ecc(cptr+8, ecc); + } + + US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba); + + result = sddr09_write_inplace(us, address>>1, info->blocksize, + info->pageshift, blockbuffer, 0); + + US_DEBUGP("sddr09_write_inplace returns %d\n", result); + +#if 0 + { + unsigned char status = 0; + int result2 = sddr09_read_status(us, &status); + if (result2 != USB_STOR_TRANSPORT_GOOD) + US_DEBUGP("sddr09_write_inplace: cannot read status\n"); + else if (status != 0xc0) + US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n", + status); + } +#endif + +#if 0 + { + int result2 = sddr09_test_unit_ready(us); + } +#endif + + return result; +} + +static int +sddr09_write_data(struct us_data *us, + unsigned long address, + unsigned int sectors) { + + struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; + unsigned int lba, page, pages; + unsigned int pagelen, blocklen; + unsigned char *blockbuffer; + unsigned char *buffer; + unsigned int len, index, offset; + int result; + + // blockbuffer is used for reading in the old data, overwriting + // with the new data, and performing ECC calculations + + /* TODO: instead of doing kmalloc/kfree for each write, + add a bufferpointer to the info structure */ + + pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); + blocklen = (pagelen << info->blockshift); + blockbuffer = kmalloc(blocklen, GFP_NOIO); + if (!blockbuffer) { + printk("sddr09_write_data: Out of memory\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + // Since we don't write the user data directly to the device, + // we have to create a bounce buffer and move the data a piece + // at a time between the bounce buffer and the actual transfer buffer. + + len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; + buffer = kmalloc(len, GFP_NOIO); + if (buffer == NULL) { + printk("sddr09_write_data: Out of memory\n"); + kfree(blockbuffer); + return USB_STOR_TRANSPORT_ERROR; + } + + // Figure out the initial LBA and page + lba = address >> info->blockshift; + page = (address & info->blockmask); + + result = USB_STOR_TRANSPORT_GOOD; + index = offset = 0; + + while (sectors > 0) { + + // Write as many sectors as possible in this block + + pages = min(sectors, info->blocksize - page); + len = (pages << info->pageshift); + + // Get the data from the transfer buffer + usb_stor_access_xfer_buf(buffer, len, us->srb, + &index, &offset, FROM_XFER_BUF); + + result = sddr09_write_lba(us, lba, page, pages, + buffer, blockbuffer); + if (result != USB_STOR_TRANSPORT_GOOD) + break; + + page = 0; + lba++; + sectors -= pages; + } + + kfree(buffer); + kfree(blockbuffer); + + return result; +} + +static int +sddr09_read_control(struct us_data *us, + unsigned long address, + unsigned int blocks, + unsigned char *content, + int use_sg) { + + US_DEBUGP("Read control address %lu, blocks %d\n", + address, blocks); + + return sddr09_read21(us, address, blocks, + CONTROL_SHIFT, content, use_sg); +} + +/* + * Read Device ID Command: 12 bytes. + * byte 0: opcode: ED + * + * Returns 2 bytes: Manufacturer ID and Device ID. + * On more recent cards 3 bytes: the third byte is an option code A5 + * signifying that the secret command to read an 128-bit ID is available. + * On still more recent cards 4 bytes: the fourth byte C0 means that + * a second read ID cmd is available. + */ +static int +sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { + unsigned char *command = us->iobuf; + unsigned char *content = us->iobuf; + int result, i; + + memset(command, 0, 12); + command[0] = 0xED; + command[1] = LUNBITS; + + result = sddr09_send_scsi_command(us, command, 12); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + content, 64, NULL); + + for (i = 0; i < 4; i++) + deviceID[i] = content[i]; + + return (result == USB_STOR_XFER_GOOD ? + USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); +} + +static int +sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) { + int result; + unsigned char status; + + result = sddr09_read_status(us, &status); + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("sddr09_get_wp: read_status fails\n"); + return result; + } + US_DEBUGP("sddr09_get_wp: status 0x%02X", status); + if ((status & 0x80) == 0) { + info->flags |= SDDR09_WP; /* write protected */ + US_DEBUGP(" WP"); + } + if (status & 0x40) + US_DEBUGP(" Ready"); + if (status & LUNBITS) + US_DEBUGP(" Suspended"); + if (status & 0x1) + US_DEBUGP(" Error"); + US_DEBUGP("\n"); + return USB_STOR_TRANSPORT_GOOD; +} + +#if 0 +/* + * Reset Command: 12 bytes. + * byte 0: opcode: EB + */ +static int +sddr09_reset(struct us_data *us) { + + unsigned char *command = us->iobuf; + + memset(command, 0, 12); + command[0] = 0xEB; + command[1] = LUNBITS; + + return sddr09_send_scsi_command(us, command, 12); +} +#endif + +static struct nand_flash_dev * +sddr09_get_cardinfo(struct us_data *us, unsigned char flags) { + struct nand_flash_dev *cardinfo; + unsigned char deviceID[4]; + char blurbtxt[256]; + int result; + + US_DEBUGP("Reading capacity...\n"); + + result = sddr09_read_deviceID(us, deviceID); + + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("Result of read_deviceID is %d\n", result); + printk("sddr09: could not read card info\n"); + return NULL; + } + + sprintf(blurbtxt, "sddr09: Found Flash card, ID = %02X %02X %02X %02X", + deviceID[0], deviceID[1], deviceID[2], deviceID[3]); + + /* Byte 0 is the manufacturer */ + sprintf(blurbtxt + strlen(blurbtxt), + ": Manuf. %s", + nand_flash_manufacturer(deviceID[0])); + + /* Byte 1 is the device type */ + cardinfo = nand_find_id(deviceID[1]); + if (cardinfo) { + /* MB or MiB? It is neither. A 16 MB card has + 17301504 raw bytes, of which 16384000 are + usable for user data. */ + sprintf(blurbtxt + strlen(blurbtxt), + ", %d MB", 1<<(cardinfo->chipshift - 20)); + } else { + sprintf(blurbtxt + strlen(blurbtxt), + ", type unrecognized"); + } + + /* Byte 2 is code to signal availability of 128-bit ID */ + if (deviceID[2] == 0xa5) { + sprintf(blurbtxt + strlen(blurbtxt), + ", 128-bit ID"); + } + + /* Byte 3 announces the availability of another read ID command */ + if (deviceID[3] == 0xc0) { + sprintf(blurbtxt + strlen(blurbtxt), + ", extra cmd"); + } + + if (flags & SDDR09_WP) + sprintf(blurbtxt + strlen(blurbtxt), + ", WP"); + + printk("%s\n", blurbtxt); + + return cardinfo; +} + +static int +sddr09_read_map(struct us_data *us) { + + struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; + int numblocks, alloc_len, alloc_blocks; + int i, j, result; + unsigned char *buffer, *buffer_end, *ptr; + unsigned int lba, lbact; + + if (!info->capacity) + return -1; + + // size of a block is 1 << (blockshift + pageshift) bytes + // divide into the total capacity to get the number of blocks + + numblocks = info->capacity >> (info->blockshift + info->pageshift); + + // read 64 bytes for every block (actually 1 << CONTROL_SHIFT) + // but only use a 64 KB buffer + // buffer size used must be a multiple of (1 << CONTROL_SHIFT) +#define SDDR09_READ_MAP_BUFSZ 65536 + + alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT); + alloc_len = (alloc_blocks << CONTROL_SHIFT); + buffer = kmalloc(alloc_len, GFP_NOIO); + if (buffer == NULL) { + printk("sddr09_read_map: out of memory\n"); + result = -1; + goto done; + } + buffer_end = buffer + alloc_len; + +#undef SDDR09_READ_MAP_BUFSZ + + kfree(info->lba_to_pba); + kfree(info->pba_to_lba); + info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); + info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); + + if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { + printk("sddr09_read_map: out of memory\n"); + result = -1; + goto done; + } + + for (i = 0; i < numblocks; i++) + info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF; + + /* + * Define lba-pba translation table + */ + + ptr = buffer_end; + for (i = 0; i < numblocks; i++) { + ptr += (1 << CONTROL_SHIFT); + if (ptr >= buffer_end) { + unsigned long address; + + address = i << (info->pageshift + info->blockshift); + result = sddr09_read_control( + us, address>>1, + min(alloc_blocks, numblocks - i), + buffer, 0); + if (result != USB_STOR_TRANSPORT_GOOD) { + result = -1; + goto done; + } + ptr = buffer; + } + + if (i == 0 || i == 1) { + info->pba_to_lba[i] = UNUSABLE; + continue; + } + + /* special PBAs have control field 0^16 */ + for (j = 0; j < 16; j++) + if (ptr[j] != 0) + goto nonz; + info->pba_to_lba[i] = UNUSABLE; + printk("sddr09: PBA %d has no logical mapping\n", i); + continue; + + nonz: + /* unwritten PBAs have control field FF^16 */ + for (j = 0; j < 16; j++) + if (ptr[j] != 0xff) + goto nonff; + continue; + + nonff: + /* normal PBAs start with six FFs */ + if (j < 6) { + printk("sddr09: PBA %d has no logical mapping: " + "reserved area = %02X%02X%02X%02X " + "data status %02X block status %02X\n", + i, ptr[0], ptr[1], ptr[2], ptr[3], + ptr[4], ptr[5]); + info->pba_to_lba[i] = UNUSABLE; + continue; + } + + if ((ptr[6] >> 4) != 0x01) { + printk("sddr09: PBA %d has invalid address field " + "%02X%02X/%02X%02X\n", + i, ptr[6], ptr[7], ptr[11], ptr[12]); + info->pba_to_lba[i] = UNUSABLE; + continue; + } + + /* check even parity */ + if (parity[ptr[6] ^ ptr[7]]) { + printk("sddr09: Bad parity in LBA for block %d" + " (%02X %02X)\n", i, ptr[6], ptr[7]); + info->pba_to_lba[i] = UNUSABLE; + continue; + } + + lba = short_pack(ptr[7], ptr[6]); + lba = (lba & 0x07FF) >> 1; + + /* + * Every 1024 physical blocks ("zone"), the LBA numbers + * go back to zero, but are within a higher block of LBA's. + * Also, there is a maximum of 1000 LBA's per zone. + * In other words, in PBA 1024-2047 you will find LBA 0-999 + * which are really LBA 1000-1999. This allows for 24 bad + * or special physical blocks per zone. + */ + + if (lba >= 1000) { + printk("sddr09: Bad low LBA %d for block %d\n", + lba, i); + goto possibly_erase; + } + + lba += 1000*(i/0x400); + + if (info->lba_to_pba[lba] != UNDEF) { + printk("sddr09: LBA %d seen for PBA %d and %d\n", + lba, info->lba_to_pba[lba], i); + goto possibly_erase; + } + + info->pba_to_lba[i] = lba; + info->lba_to_pba[lba] = i; + continue; + + possibly_erase: + if (erase_bad_lba_entries) { + unsigned long address; + + address = (i << (info->pageshift + info->blockshift)); + sddr09_erase(us, address>>1); + info->pba_to_lba[i] = UNDEF; + } else + info->pba_to_lba[i] = UNUSABLE; + } + + /* + * Approximate capacity. This is not entirely correct yet, + * since a zone with less than 1000 usable pages leads to + * missing LBAs. Especially if it is the last zone, some + * LBAs can be past capacity. + */ + lbact = 0; + for (i = 0; i < numblocks; i += 1024) { + int ct = 0; + + for (j = 0; j < 1024 && i+j < numblocks; j++) { + if (info->pba_to_lba[i+j] != UNUSABLE) { + if (ct >= 1000) + info->pba_to_lba[i+j] = SPARE; + else + ct++; + } + } + lbact += ct; + } + info->lbact = lbact; + US_DEBUGP("Found %d LBA's\n", lbact); + result = 0; + + done: + if (result != 0) { + kfree(info->lba_to_pba); + kfree(info->pba_to_lba); + info->lba_to_pba = NULL; + info->pba_to_lba = NULL; + } + kfree(buffer); + return result; +} + +static void +sddr09_card_info_destructor(void *extra) { + struct sddr09_card_info *info = (struct sddr09_card_info *)extra; + + if (!info) + return; + + kfree(info->lba_to_pba); + kfree(info->pba_to_lba); +} + +static void +sddr09_init_card_info(struct us_data *us) { + if (!us->extra) { + us->extra = kmalloc(sizeof(struct sddr09_card_info), GFP_NOIO); + if (us->extra) { + memset(us->extra, 0, sizeof(struct sddr09_card_info)); + us->extra_destructor = sddr09_card_info_destructor; + } + } +} + +/* + * This is needed at a very early stage. If this is not listed in the + * unusual devices list but called from here then LUN 0 of the combo reader + * is not recognized. But I do not know what precisely these calls do. + */ +int +sddr09_init(struct us_data *us) { + int result; + unsigned char *data = us->iobuf; + + result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("sddr09_init: send_command fails\n"); + return result; + } + + US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); + // get 07 02 + + result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2); + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("sddr09_init: 2nd send_command fails\n"); + return result; + } + + US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); + // get 07 00 + + result = sddr09_request_sense(us, data, 18); + if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) { + int j; + for (j=0; j<18; j++) + printk(" %02X", data[j]); + printk("\n"); + // get 70 00 00 00 00 00 00 * 00 00 00 00 00 00 + // 70: current command + // sense key 0, sense code 0, extd sense code 0 + // additional transfer length * = sizeof(data) - 7 + // Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00 + // sense key 06, sense code 28: unit attention, + // not ready to ready transition + } + + // test unit ready + + return USB_STOR_TRANSPORT_GOOD; /* not result */ +} + +/* + * Transport for the Sandisk SDDR-09 + */ +int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) +{ + static unsigned char sensekey = 0, sensecode = 0; + static unsigned char havefakesense = 0; + int result, i; + unsigned char *ptr = us->iobuf; + unsigned long capacity; + unsigned int page, pages; + + struct sddr09_card_info *info; + + static unsigned char inquiry_response[8] = { + 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00 + }; + + /* note: no block descriptor support */ + static unsigned char mode_page_01[19] = { + 0x00, 0x0F, 0x00, 0x0, 0x0, 0x0, 0x00, + 0x01, 0x0A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + info = (struct sddr09_card_info *)us->extra; + if (!info) { + nand_init_ecc(); + sddr09_init_card_info(us); + info = (struct sddr09_card_info *)us->extra; + if (!info) + return USB_STOR_TRANSPORT_ERROR; + } + + if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) { + /* for a faked command, we have to follow with a faked sense */ + memset(ptr, 0, 18); + ptr[0] = 0x70; + ptr[2] = sensekey; + ptr[7] = 11; + ptr[12] = sensecode; + usb_stor_set_xfer_buf(ptr, 18, srb); + sensekey = sensecode = havefakesense = 0; + return USB_STOR_TRANSPORT_GOOD; + } + + havefakesense = 1; + + /* Dummy up a response for INQUIRY since SDDR09 doesn't + respond to INQUIRY commands */ + + if (srb->cmnd[0] == INQUIRY) { + memcpy(ptr, inquiry_response, 8); + fill_inquiry_response(us, ptr, 36); + return USB_STOR_TRANSPORT_GOOD; + } + + if (srb->cmnd[0] == READ_CAPACITY) { + struct nand_flash_dev *cardinfo; + + sddr09_get_wp(us, info); /* read WP bit */ + + cardinfo = sddr09_get_cardinfo(us, info->flags); + if (!cardinfo) { + /* probably no media */ + init_error: + sensekey = 0x02; /* not ready */ + sensecode = 0x3a; /* medium not present */ + return USB_STOR_TRANSPORT_FAILED; + } + + info->capacity = (1 << cardinfo->chipshift); + info->pageshift = cardinfo->pageshift; + info->pagesize = (1 << info->pageshift); + info->blockshift = cardinfo->blockshift; + info->blocksize = (1 << info->blockshift); + info->blockmask = info->blocksize - 1; + + // map initialization, must follow get_cardinfo() + if (sddr09_read_map(us)) { + /* probably out of memory */ + goto init_error; + } + + // Report capacity + + capacity = (info->lbact << info->blockshift) - 1; + + ((__be32 *) ptr)[0] = cpu_to_be32(capacity); + + // Report page size + + ((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize); + usb_stor_set_xfer_buf(ptr, 8, srb); + + return USB_STOR_TRANSPORT_GOOD; + } + + if (srb->cmnd[0] == MODE_SENSE_10) { + int modepage = (srb->cmnd[2] & 0x3F); + + /* They ask for the Read/Write error recovery page, + or for all pages. */ + /* %% We should check DBD %% */ + if (modepage == 0x01 || modepage == 0x3F) { + US_DEBUGP("SDDR09: Dummy up request for " + "mode page 0x%x\n", modepage); + + memcpy(ptr, mode_page_01, sizeof(mode_page_01)); + ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); + ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0; + usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); + return USB_STOR_TRANSPORT_GOOD; + } + + sensekey = 0x05; /* illegal request */ + sensecode = 0x24; /* invalid field in CDB */ + return USB_STOR_TRANSPORT_FAILED; + } + + if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) + return USB_STOR_TRANSPORT_GOOD; + + havefakesense = 0; + + if (srb->cmnd[0] == READ_10) { + + page = short_pack(srb->cmnd[3], srb->cmnd[2]); + page <<= 16; + page |= short_pack(srb->cmnd[5], srb->cmnd[4]); + pages = short_pack(srb->cmnd[8], srb->cmnd[7]); + + US_DEBUGP("READ_10: read page %d pagect %d\n", + page, pages); + + return sddr09_read_data(us, page, pages); + } + + if (srb->cmnd[0] == WRITE_10) { + + page = short_pack(srb->cmnd[3], srb->cmnd[2]); + page <<= 16; + page |= short_pack(srb->cmnd[5], srb->cmnd[4]); + pages = short_pack(srb->cmnd[8], srb->cmnd[7]); + + US_DEBUGP("WRITE_10: write page %d pagect %d\n", + page, pages); + + return sddr09_write_data(us, page, pages); + } + + /* catch-all for all other commands, except + * pass TEST_UNIT_READY and REQUEST_SENSE through + */ + if (srb->cmnd[0] != TEST_UNIT_READY && + srb->cmnd[0] != REQUEST_SENSE) { + sensekey = 0x05; /* illegal request */ + sensecode = 0x20; /* invalid command */ + havefakesense = 1; + return USB_STOR_TRANSPORT_FAILED; + } + + for (; srb->cmd_len<12; srb->cmd_len++) + srb->cmnd[srb->cmd_len] = 0; + + srb->cmnd[1] = LUNBITS; + + ptr[0] = 0; + for (i=0; i<12; i++) + sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]); + + US_DEBUGP("SDDR09: Send control for command %s\n", ptr); + + result = sddr09_send_scsi_command(us, srb->cmnd, 12); + if (result != USB_STOR_TRANSPORT_GOOD) { + US_DEBUGP("sddr09_transport: sddr09_send_scsi_command " + "returns %d\n", result); + return result; + } + + if (srb->request_bufflen == 0) + return USB_STOR_TRANSPORT_GOOD; + + if (srb->sc_data_direction == DMA_TO_DEVICE || + srb->sc_data_direction == DMA_FROM_DEVICE) { + unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) + ? us->send_bulk_pipe : us->recv_bulk_pipe; + + US_DEBUGP("SDDR09: %s %d bytes\n", + (srb->sc_data_direction == DMA_TO_DEVICE) ? + "sending" : "receiving", + srb->request_bufflen); + + result = usb_stor_bulk_transfer_sg(us, pipe, + srb->request_buffer, + srb->request_bufflen, + srb->use_sg, &srb->resid); + + return (result == USB_STOR_XFER_GOOD ? + USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); + } + + return USB_STOR_TRANSPORT_GOOD; +} + |