| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Driver for SanDisk SDDR-09 SmartMedia reader |
| * |
| * (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. |
| */ |
| |
| /* |
| * 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/errno.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| |
| #include <scsi/scsi.h> |
| #include <scsi/scsi_cmnd.h> |
| #include <scsi/scsi_device.h> |
| |
| #include "usb.h" |
| #include "transport.h" |
| #include "protocol.h" |
| #include "debug.h" |
| #include "scsiglue.h" |
| |
| #define DRV_NAME "ums-sddr09" |
| |
| MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader"); |
| MODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>"); |
| MODULE_LICENSE("GPL"); |
| MODULE_IMPORT_NS(USB_STORAGE); |
| |
| static int usb_stor_sddr09_dpcm_init(struct us_data *us); |
| static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); |
| static int usb_stor_sddr09_init(struct us_data *us); |
| |
| |
| /* |
| * The table of devices |
| */ |
| #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ |
| vendorName, productName, useProtocol, useTransport, \ |
| initFunction, flags) \ |
| { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ |
| .driver_info = (flags) } |
| |
| static const struct usb_device_id sddr09_usb_ids[] = { |
| # include "unusual_sddr09.h" |
| { } /* Terminating entry */ |
| }; |
| MODULE_DEVICE_TABLE(usb, sddr09_usb_ids); |
| |
| #undef UNUSUAL_DEV |
| |
| /* |
| * The flags table |
| */ |
| #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ |
| vendor_name, product_name, use_protocol, use_transport, \ |
| init_function, Flags) \ |
| { \ |
| .vendorName = vendor_name, \ |
| .productName = product_name, \ |
| .useProtocol = use_protocol, \ |
| .useTransport = use_transport, \ |
| .initFunction = init_function, \ |
| } |
| |
| static const struct us_unusual_dev sddr09_unusual_dev_list[] = { |
| # include "unusual_sddr09.h" |
| { } /* Terminating entry */ |
| }; |
| |
| #undef UNUSUAL_DEV |
| |
| |
| #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) |
| #define LSB_of(s) ((s)&0xFF) |
| #define MSB_of(s) ((s)>>8) |
| |
| /* |
| * 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,} |
| }; |
| |
| static struct nand_flash_dev * |
| nand_find_id(unsigned char id) { |
| int i; |
| |
| for (i = 0; i < ARRAY_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 = 0, bit, bits[8] = {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. |
| */ |
| |
| struct sddr09_card_info { |
| unsigned long capacity; /* Size of card in bytes */ |
| int pagesize; /* Size of page in bytes */ |
| int pageshift; /* log2 of pagesize */ |
| int blocksize; /* Size of block in pages */ |
| int blockshift; /* log2 of blocksize */ |
| int blockmask; /* 2^blockshift - 1 */ |
| int *lba_to_pba; /* logical to physical map */ |
| int *pba_to_lba; /* physical to logical map */ |
| int lbact; /* number of available pages */ |
| int flags; |
| #define SDDR09_WP 1 /* write protected */ |
| }; |
| |
| /* |
| * 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 const 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); |
| switch (rc) { |
| case USB_STOR_XFER_GOOD: return 0; |
| case USB_STOR_XFER_STALLED: return -EPIPE; |
| default: return -EIO; |
| } |
| } |
| |
| 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); |
| |
| usb_stor_dbg(us, "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) |
| return result; |
| |
| result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, |
| sensebuf, buflen, NULL); |
| return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); |
| } |
| |
| /* |
| * 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_dbg(us, "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) { |
| usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read2%d %d\n", |
| x, result); |
| return -EIO; |
| } |
| return 0; |
| } |
| |
| /* |
| * 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); |
| usb_stor_dbg(us, "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; |
| |
| usb_stor_dbg(us, "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_dbg(us, "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_dbg(us, "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) { |
| usb_stor_dbg(us, "Result for bulk_transfer in sddr09_writeX %d\n", |
| result); |
| return -EIO; |
| } |
| return 0; |
| } |
| |
| /* 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_dbg(us, "Result for send_control in sddr09_read_sg %d\n", |
| result); |
| return result; |
| } |
| |
| buf = kmalloc(bulklen, GFP_NOIO); |
| if (!buf) |
| return -ENOMEM; |
| |
| result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, |
| buf, bulklen, NULL); |
| kfree(buf); |
| if (result != USB_STOR_XFER_GOOD) { |
| usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read_sg %d\n", |
| result); |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| #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; |
| |
| usb_stor_dbg(us, "Reading status...\n"); |
| |
| memset(command, 0, 12); |
| command[0] = 0xEC; |
| command[1] = LUNBITS; |
| |
| result = sddr09_send_scsi_command(us, command, 12); |
| if (result) |
| 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 ? 0 : -EIO); |
| } |
| |
| 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, offset; |
| struct scatterlist *sg; |
| int result; |
| |
| // Figure out the initial LBA and page |
| lba = address >> info->blockshift; |
| page = (address & info->blockmask); |
| maxlba = info->capacity >> (info->pageshift + info->blockshift); |
| if (lba >= maxlba) |
| return -EIO; |
| |
| // 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) |
| return -ENOMEM; |
| |
| // This could be made much more efficient by checking for |
| // contiguous LBA's. Another exercise left to the student. |
| |
| result = 0; |
| offset = 0; |
| sg = NULL; |
| |
| 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) { |
| usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", |
| lba, maxlba); |
| result = -EIO; |
| break; |
| } |
| |
| /* Find where this lba lives on disk */ |
| pba = info->lba_to_pba[lba]; |
| |
| if (pba == UNDEF) { /* this lba was never written */ |
| |
| usb_stor_dbg(us, "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 an error |
| * it is better to return all zero data. |
| */ |
| |
| memset(buffer, 0, len); |
| |
| } else { |
| usb_stor_dbg(us, "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) |
| break; |
| } |
| |
| // Store the data in the transfer buffer |
| usb_stor_access_xfer_buf(buffer, len, us->srb, |
| &sg, &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; |
| |
| lbap = ((lba % 1000) << 1) | 0x1000; |
| if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) |
| lbap ^= 1; |
| pba = info->lba_to_pba[lba]; |
| |
| if (pba == UNDEF) { |
| pba = sddr09_find_unused_pba(info, lba); |
| if (!pba) { |
| printk(KERN_WARNING |
| "sddr09_write_lba: Out of unused blocks\n"); |
| return -ENOSPC; |
| } |
| info->pba_to_lba[pba] = lba; |
| info->lba_to_pba[lba] = pba; |
| } |
| |
| if (pba == 1) { |
| /* |
| * Maybe it is impossible to write to PBA 1. |
| * Fake success, but don't do anything. |
| */ |
| printk(KERN_WARNING "sddr09: avoid writing to pba 1\n"); |
| return 0; |
| } |
| |
| 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) |
| 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)) { |
| usb_stor_dbg(us, "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)) { |
| usb_stor_dbg(us, "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); |
| } |
| |
| usb_stor_dbg(us, "Rewrite PBA %d (LBA %d)\n", pba, lba); |
| |
| result = sddr09_write_inplace(us, address>>1, info->blocksize, |
| info->pageshift, blockbuffer, 0); |
| |
| usb_stor_dbg(us, "sddr09_write_inplace returns %d\n", result); |
| |
| #if 0 |
| { |
| unsigned char status = 0; |
| int result2 = sddr09_read_status(us, &status); |
| if (result2) |
| usb_stor_dbg(us, "cannot read status\n"); |
| else if (status != 0xc0) |
| usb_stor_dbg(us, "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, maxlba, page, pages; |
| unsigned int pagelen, blocklen; |
| unsigned char *blockbuffer; |
| unsigned char *buffer; |
| unsigned int len, offset; |
| struct scatterlist *sg; |
| int result; |
| |
| /* Figure out the initial LBA and page */ |
| lba = address >> info->blockshift; |
| page = (address & info->blockmask); |
| maxlba = info->capacity >> (info->pageshift + info->blockshift); |
| if (lba >= maxlba) |
| return -EIO; |
| |
| /* |
| * 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) |
| return -ENOMEM; |
| |
| /* |
| * 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) { |
| kfree(blockbuffer); |
| return -ENOMEM; |
| } |
| |
| result = 0; |
| offset = 0; |
| sg = NULL; |
| |
| while (sectors > 0) { |
| |
| /* Write as many sectors as possible in this block */ |
| |
| pages = min(sectors, info->blocksize - page); |
| len = (pages << info->pageshift); |
| |
| /* Not overflowing capacity? */ |
| if (lba >= maxlba) { |
| usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", |
| lba, maxlba); |
| result = -EIO; |
| break; |
| } |
| |
| /* Get the data from the transfer buffer */ |
| usb_stor_access_xfer_buf(buffer, len, us->srb, |
| &sg, &offset, FROM_XFER_BUF); |
| |
| result = sddr09_write_lba(us, lba, page, pages, |
| buffer, blockbuffer); |
| if (result) |
| 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) { |
| |
| usb_stor_dbg(us, "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) |
| 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 ? 0 : -EIO); |
| } |
| |
| static int |
| sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) { |
| int result; |
| unsigned char status; |
| const char *wp_fmt; |
| |
| result = sddr09_read_status(us, &status); |
| if (result) { |
| usb_stor_dbg(us, "read_status fails\n"); |
| return result; |
| } |
| if ((status & 0x80) == 0) { |
| info->flags |= SDDR09_WP; /* write protected */ |
| wp_fmt = " WP"; |
| } else { |
| wp_fmt = ""; |
| } |
| usb_stor_dbg(us, "status 0x%02X%s%s%s%s\n", status, wp_fmt, |
| status & 0x40 ? " Ready" : "", |
| status & LUNBITS ? " Suspended" : "", |
| status & 0x01 ? " Error" : ""); |
| |
| return 0; |
| } |
| |
| #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; |
| |
| usb_stor_dbg(us, "Reading capacity...\n"); |
| |
| result = sddr09_read_deviceID(us, deviceID); |
| |
| if (result) { |
| usb_stor_dbg(us, "Result of read_deviceID is %d\n", result); |
| printk(KERN_WARNING "sddr09: could not read card info\n"); |
| return NULL; |
| } |
| |
| sprintf(blurbtxt, "sddr09: Found Flash card, ID = %4ph", deviceID); |
| |
| /* 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(KERN_WARNING "%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) { |
| 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_array(numblocks, sizeof(int), GFP_NOIO); |
| info->pba_to_lba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO); |
| |
| if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { |
| printk(KERN_WARNING "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) { |
| 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(KERN_WARNING "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(KERN_WARNING |
| "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(KERN_WARNING |
| "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(KERN_WARNING |
| "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(KERN_WARNING |
| "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(KERN_WARNING |
| "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; |
| usb_stor_dbg(us, "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 int |
| sddr09_common_init(struct us_data *us) { |
| int result; |
| |
| /* set the configuration -- STALL is an acceptable response here */ |
| if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) { |
| usb_stor_dbg(us, "active config #%d != 1 ??\n", |
| us->pusb_dev->actconfig->desc.bConfigurationValue); |
| return -EINVAL; |
| } |
| |
| result = usb_reset_configuration(us->pusb_dev); |
| usb_stor_dbg(us, "Result of usb_reset_configuration is %d\n", result); |
| if (result == -EPIPE) { |
| usb_stor_dbg(us, "-- stall on control interface\n"); |
| } else if (result != 0) { |
| /* it's not a stall, but another error -- time to bail */ |
| usb_stor_dbg(us, "-- Unknown error. Rejecting device\n"); |
| return -EINVAL; |
| } |
| |
| us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO); |
| if (!us->extra) |
| return -ENOMEM; |
| us->extra_destructor = sddr09_card_info_destructor; |
| |
| nand_init_ecc(); |
| return 0; |
| } |
| |
| |
| /* |
| * 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. |
| */ |
| static int |
| usb_stor_sddr09_dpcm_init(struct us_data *us) { |
| int result; |
| unsigned char *data = us->iobuf; |
| |
| result = sddr09_common_init(us); |
| if (result) |
| return result; |
| |
| result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); |
| if (result) { |
| usb_stor_dbg(us, "send_command fails\n"); |
| return result; |
| } |
| |
| usb_stor_dbg(us, "%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_dbg(us, "2nd send_command fails\n"); |
| return result; |
| } |
| |
| usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]); |
| // get 07 00 |
| |
| result = sddr09_request_sense(us, data, 18); |
| if (result == 0 && 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 0; /* not result */ |
| } |
| |
| /* |
| * Transport for the Microtech DPCM-USB |
| */ |
| static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) |
| { |
| int ret; |
| |
| usb_stor_dbg(us, "LUN=%d\n", (u8)srb->device->lun); |
| |
| switch (srb->device->lun) { |
| case 0: |
| |
| /* |
| * LUN 0 corresponds to the CompactFlash card reader. |
| */ |
| ret = usb_stor_CB_transport(srb, us); |
| break; |
| |
| case 1: |
| |
| /* |
| * LUN 1 corresponds to the SmartMedia card reader. |
| */ |
| |
| /* |
| * Set the LUN to 0 (just in case). |
| */ |
| srb->device->lun = 0; |
| ret = sddr09_transport(srb, us); |
| srb->device->lun = 1; |
| break; |
| |
| default: |
| usb_stor_dbg(us, "Invalid LUN %d\n", (u8)srb->device->lun); |
| ret = USB_STOR_TRANSPORT_ERROR; |
| break; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * Transport for the Sandisk SDDR-09 |
| */ |
| static 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 (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) { |
| usb_stor_dbg(us, "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]); |
| |
| usb_stor_dbg(us, "READ_10: read page %d pagect %d\n", |
| page, pages); |
| |
| result = sddr09_read_data(us, page, pages); |
| return (result == 0 ? USB_STOR_TRANSPORT_GOOD : |
| USB_STOR_TRANSPORT_ERROR); |
| } |
| |
| 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]); |
| |
| usb_stor_dbg(us, "WRITE_10: write page %d pagect %d\n", |
| page, pages); |
| |
| result = sddr09_write_data(us, page, pages); |
| return (result == 0 ? USB_STOR_TRANSPORT_GOOD : |
| USB_STOR_TRANSPORT_ERROR); |
| } |
| |
| /* |
| * 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]); |
| |
| usb_stor_dbg(us, "Send control for command %s\n", ptr); |
| |
| result = sddr09_send_scsi_command(us, srb->cmnd, 12); |
| if (result) { |
| usb_stor_dbg(us, "sddr09_send_scsi_command returns %d\n", |
| result); |
| return USB_STOR_TRANSPORT_ERROR; |
| } |
| |
| if (scsi_bufflen(srb) == 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; |
| |
| usb_stor_dbg(us, "%s %d bytes\n", |
| (srb->sc_data_direction == DMA_TO_DEVICE) ? |
| "sending" : "receiving", |
| scsi_bufflen(srb)); |
| |
| result = usb_stor_bulk_srb(us, pipe, srb); |
| |
| return (result == USB_STOR_XFER_GOOD ? |
| USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); |
| } |
| |
| return USB_STOR_TRANSPORT_GOOD; |
| } |
| |
| /* |
| * Initialization routine for the sddr09 subdriver |
| */ |
| static int |
| usb_stor_sddr09_init(struct us_data *us) { |
| return sddr09_common_init(us); |
| } |
| |
| static struct scsi_host_template sddr09_host_template; |
| |
| static int sddr09_probe(struct usb_interface *intf, |
| const struct usb_device_id *id) |
| { |
| struct us_data *us; |
| int result; |
| |
| result = usb_stor_probe1(&us, intf, id, |
| (id - sddr09_usb_ids) + sddr09_unusual_dev_list, |
| &sddr09_host_template); |
| if (result) |
| return result; |
| |
| if (us->protocol == USB_PR_DPCM_USB) { |
| us->transport_name = "Control/Bulk-EUSB/SDDR09"; |
| us->transport = dpcm_transport; |
| us->transport_reset = usb_stor_CB_reset; |
| us->max_lun = 1; |
| } else { |
| us->transport_name = "EUSB/SDDR09"; |
| us->transport = sddr09_transport; |
| us->transport_reset = usb_stor_CB_reset; |
| us->max_lun = 0; |
| } |
| |
| result = usb_stor_probe2(us); |
| return result; |
| } |
| |
| static struct usb_driver sddr09_driver = { |
| .name = DRV_NAME, |
| .probe = sddr09_probe, |
| .disconnect = usb_stor_disconnect, |
| .suspend = usb_stor_suspend, |
| .resume = usb_stor_resume, |
| .reset_resume = usb_stor_reset_resume, |
| .pre_reset = usb_stor_pre_reset, |
| .post_reset = usb_stor_post_reset, |
| .id_table = sddr09_usb_ids, |
| .soft_unbind = 1, |
| .no_dynamic_id = 1, |
| }; |
| |
| module_usb_stor_driver(sddr09_driver, sddr09_host_template, DRV_NAME); |