162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for SanDisk SDDR-09 SmartMedia reader 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) 2000, 2001 Robert Baruch (autophile@starband.net) 662306a36Sopenharmony_ci * (c) 2002 Andries Brouwer (aeb@cwi.nl) 762306a36Sopenharmony_ci * Developed with the assistance of: 862306a36Sopenharmony_ci * (c) 2002 Alan Stern <stern@rowland.org> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. 1162306a36Sopenharmony_ci * This chip is a programmable USB controller. In the SDDR-09, it has 1262306a36Sopenharmony_ci * been programmed to obey a certain limited set of SCSI commands. 1362306a36Sopenharmony_ci * This driver translates the "real" SCSI commands to the SDDR-09 SCSI 1462306a36Sopenharmony_ci * commands. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Known vendor commands: 12 bytes, first byte is opcode 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * E7: read scatter gather 2162306a36Sopenharmony_ci * E8: read 2262306a36Sopenharmony_ci * E9: write 2362306a36Sopenharmony_ci * EA: erase 2462306a36Sopenharmony_ci * EB: reset 2562306a36Sopenharmony_ci * EC: read status 2662306a36Sopenharmony_ci * ED: read ID 2762306a36Sopenharmony_ci * EE: write CIS (?) 2862306a36Sopenharmony_ci * EF: compute checksum (?) 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/errno.h> 3262306a36Sopenharmony_ci#include <linux/module.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <scsi/scsi.h> 3662306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 3762306a36Sopenharmony_ci#include <scsi/scsi_device.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "usb.h" 4062306a36Sopenharmony_ci#include "transport.h" 4162306a36Sopenharmony_ci#include "protocol.h" 4262306a36Sopenharmony_ci#include "debug.h" 4362306a36Sopenharmony_ci#include "scsiglue.h" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define DRV_NAME "ums-sddr09" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader"); 4862306a36Sopenharmony_ciMODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>"); 4962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5062306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int usb_stor_sddr09_dpcm_init(struct us_data *us); 5362306a36Sopenharmony_cistatic int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); 5462306a36Sopenharmony_cistatic int usb_stor_sddr09_init(struct us_data *us); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * The table of devices 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 6162306a36Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 6262306a36Sopenharmony_ci initFunction, flags) \ 6362306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 6462306a36Sopenharmony_ci .driver_info = (flags) } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic struct usb_device_id sddr09_usb_ids[] = { 6762306a36Sopenharmony_ci# include "unusual_sddr09.h" 6862306a36Sopenharmony_ci { } /* Terminating entry */ 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, sddr09_usb_ids); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#undef UNUSUAL_DEV 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * The flags table 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 7862306a36Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 7962306a36Sopenharmony_ci init_function, Flags) \ 8062306a36Sopenharmony_ci{ \ 8162306a36Sopenharmony_ci .vendorName = vendor_name, \ 8262306a36Sopenharmony_ci .productName = product_name, \ 8362306a36Sopenharmony_ci .useProtocol = use_protocol, \ 8462306a36Sopenharmony_ci .useTransport = use_transport, \ 8562306a36Sopenharmony_ci .initFunction = init_function, \ 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic struct us_unusual_dev sddr09_unusual_dev_list[] = { 8962306a36Sopenharmony_ci# include "unusual_sddr09.h" 9062306a36Sopenharmony_ci { } /* Terminating entry */ 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#undef UNUSUAL_DEV 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) 9762306a36Sopenharmony_ci#define LSB_of(s) ((s)&0xFF) 9862306a36Sopenharmony_ci#define MSB_of(s) ((s)>>8) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * First some stuff that does not belong here: 10262306a36Sopenharmony_ci * data on SmartMedia and other cards, completely 10362306a36Sopenharmony_ci * unrelated to this driver. 10462306a36Sopenharmony_ci * Similar stuff occurs in <linux/mtd/nand_ids.h>. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistruct nand_flash_dev { 10862306a36Sopenharmony_ci int model_id; 10962306a36Sopenharmony_ci int chipshift; /* 1<<cs bytes total capacity */ 11062306a36Sopenharmony_ci char pageshift; /* 1<<ps bytes in a page */ 11162306a36Sopenharmony_ci char blockshift; /* 1<<bs pages in an erase block */ 11262306a36Sopenharmony_ci char zoneshift; /* 1<<zs blocks in a zone */ 11362306a36Sopenharmony_ci /* # of logical blocks is 125/128 of this */ 11462306a36Sopenharmony_ci char pageadrlen; /* length of an address in bytes - 1 */ 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * NAND Flash Manufacturer ID Codes 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci#define NAND_MFR_AMD 0x01 12162306a36Sopenharmony_ci#define NAND_MFR_NATSEMI 0x8f 12262306a36Sopenharmony_ci#define NAND_MFR_TOSHIBA 0x98 12362306a36Sopenharmony_ci#define NAND_MFR_SAMSUNG 0xec 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline char *nand_flash_manufacturer(int manuf_id) { 12662306a36Sopenharmony_ci switch(manuf_id) { 12762306a36Sopenharmony_ci case NAND_MFR_AMD: 12862306a36Sopenharmony_ci return "AMD"; 12962306a36Sopenharmony_ci case NAND_MFR_NATSEMI: 13062306a36Sopenharmony_ci return "NATSEMI"; 13162306a36Sopenharmony_ci case NAND_MFR_TOSHIBA: 13262306a36Sopenharmony_ci return "Toshiba"; 13362306a36Sopenharmony_ci case NAND_MFR_SAMSUNG: 13462306a36Sopenharmony_ci return "Samsung"; 13562306a36Sopenharmony_ci default: 13662306a36Sopenharmony_ci return "unknown"; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * It looks like it is unnecessary to attach manufacturer to the 14262306a36Sopenharmony_ci * remaining data: SSFDC prescribes manufacturer-independent id codes. 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * 256 MB NAND flash has a 5-byte ID with 2nd byte 0xaa, 0xba, 0xca or 0xda. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic struct nand_flash_dev nand_flash_ids[] = { 14862306a36Sopenharmony_ci /* NAND flash */ 14962306a36Sopenharmony_ci { 0x6e, 20, 8, 4, 8, 2}, /* 1 MB */ 15062306a36Sopenharmony_ci { 0xe8, 20, 8, 4, 8, 2}, /* 1 MB */ 15162306a36Sopenharmony_ci { 0xec, 20, 8, 4, 8, 2}, /* 1 MB */ 15262306a36Sopenharmony_ci { 0x64, 21, 8, 4, 9, 2}, /* 2 MB */ 15362306a36Sopenharmony_ci { 0xea, 21, 8, 4, 9, 2}, /* 2 MB */ 15462306a36Sopenharmony_ci { 0x6b, 22, 9, 4, 9, 2}, /* 4 MB */ 15562306a36Sopenharmony_ci { 0xe3, 22, 9, 4, 9, 2}, /* 4 MB */ 15662306a36Sopenharmony_ci { 0xe5, 22, 9, 4, 9, 2}, /* 4 MB */ 15762306a36Sopenharmony_ci { 0xe6, 23, 9, 4, 10, 2}, /* 8 MB */ 15862306a36Sopenharmony_ci { 0x73, 24, 9, 5, 10, 2}, /* 16 MB */ 15962306a36Sopenharmony_ci { 0x75, 25, 9, 5, 10, 2}, /* 32 MB */ 16062306a36Sopenharmony_ci { 0x76, 26, 9, 5, 10, 3}, /* 64 MB */ 16162306a36Sopenharmony_ci { 0x79, 27, 9, 5, 10, 3}, /* 128 MB */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* MASK ROM */ 16462306a36Sopenharmony_ci { 0x5d, 21, 9, 4, 8, 2}, /* 2 MB */ 16562306a36Sopenharmony_ci { 0xd5, 22, 9, 4, 9, 2}, /* 4 MB */ 16662306a36Sopenharmony_ci { 0xd6, 23, 9, 4, 10, 2}, /* 8 MB */ 16762306a36Sopenharmony_ci { 0x57, 24, 9, 4, 11, 2}, /* 16 MB */ 16862306a36Sopenharmony_ci { 0x58, 25, 9, 4, 12, 2}, /* 32 MB */ 16962306a36Sopenharmony_ci { 0,} 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic struct nand_flash_dev * 17362306a36Sopenharmony_cinand_find_id(unsigned char id) { 17462306a36Sopenharmony_ci int i; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(nand_flash_ids); i++) 17762306a36Sopenharmony_ci if (nand_flash_ids[i].model_id == id) 17862306a36Sopenharmony_ci return &(nand_flash_ids[i]); 17962306a36Sopenharmony_ci return NULL; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * ECC computation. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistatic unsigned char parity[256]; 18662306a36Sopenharmony_cistatic unsigned char ecc2[256]; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void nand_init_ecc(void) { 18962306a36Sopenharmony_ci int i, j, a; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci parity[0] = 0; 19262306a36Sopenharmony_ci for (i = 1; i < 256; i++) 19362306a36Sopenharmony_ci parity[i] = (parity[i&(i-1)] ^ 1); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci for (i = 0; i < 256; i++) { 19662306a36Sopenharmony_ci a = 0; 19762306a36Sopenharmony_ci for (j = 0; j < 8; j++) { 19862306a36Sopenharmony_ci if (i & (1<<j)) { 19962306a36Sopenharmony_ci if ((j & 1) == 0) 20062306a36Sopenharmony_ci a ^= 0x04; 20162306a36Sopenharmony_ci if ((j & 2) == 0) 20262306a36Sopenharmony_ci a ^= 0x10; 20362306a36Sopenharmony_ci if ((j & 4) == 0) 20462306a36Sopenharmony_ci a ^= 0x40; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0)); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/* compute 3-byte ecc on 256 bytes */ 21262306a36Sopenharmony_cistatic void nand_compute_ecc(unsigned char *data, unsigned char *ecc) { 21362306a36Sopenharmony_ci int i, j, a; 21462306a36Sopenharmony_ci unsigned char par = 0, bit, bits[8] = {0}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* collect 16 checksum bits */ 21762306a36Sopenharmony_ci for (i = 0; i < 256; i++) { 21862306a36Sopenharmony_ci par ^= data[i]; 21962306a36Sopenharmony_ci bit = parity[data[i]]; 22062306a36Sopenharmony_ci for (j = 0; j < 8; j++) 22162306a36Sopenharmony_ci if ((i & (1<<j)) == 0) 22262306a36Sopenharmony_ci bits[j] ^= bit; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* put 4+4+4 = 12 bits in the ecc */ 22662306a36Sopenharmony_ci a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0]; 22762306a36Sopenharmony_ci ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0)); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4]; 23062306a36Sopenharmony_ci ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0)); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci ecc[2] = ecc2[par]; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int nand_compare_ecc(unsigned char *data, unsigned char *ecc) { 23662306a36Sopenharmony_ci return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void nand_store_ecc(unsigned char *data, unsigned char *ecc) { 24062306a36Sopenharmony_ci memcpy(data, ecc, 3); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* 24462306a36Sopenharmony_ci * The actual driver starts here. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistruct sddr09_card_info { 24862306a36Sopenharmony_ci unsigned long capacity; /* Size of card in bytes */ 24962306a36Sopenharmony_ci int pagesize; /* Size of page in bytes */ 25062306a36Sopenharmony_ci int pageshift; /* log2 of pagesize */ 25162306a36Sopenharmony_ci int blocksize; /* Size of block in pages */ 25262306a36Sopenharmony_ci int blockshift; /* log2 of blocksize */ 25362306a36Sopenharmony_ci int blockmask; /* 2^blockshift - 1 */ 25462306a36Sopenharmony_ci int *lba_to_pba; /* logical to physical map */ 25562306a36Sopenharmony_ci int *pba_to_lba; /* physical to logical map */ 25662306a36Sopenharmony_ci int lbact; /* number of available pages */ 25762306a36Sopenharmony_ci int flags; 25862306a36Sopenharmony_ci#define SDDR09_WP 1 /* write protected */ 25962306a36Sopenharmony_ci}; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* 26262306a36Sopenharmony_ci * On my 16MB card, control blocks have size 64 (16 real control bytes, 26362306a36Sopenharmony_ci * and 48 junk bytes). In reality of course the card uses 16 control bytes, 26462306a36Sopenharmony_ci * so the reader makes up the remaining 48. Don't know whether these numbers 26562306a36Sopenharmony_ci * depend on the card. For now a constant. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci#define CONTROL_SHIFT 6 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* 27062306a36Sopenharmony_ci * On my Combo CF/SM reader, the SM reader has LUN 1. 27162306a36Sopenharmony_ci * (and things fail with LUN 0). 27262306a36Sopenharmony_ci * It seems LUN is irrelevant for others. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci#define LUN 1 27562306a36Sopenharmony_ci#define LUNBITS (LUN << 5) 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/* 27862306a36Sopenharmony_ci * LBA and PBA are unsigned ints. Special values. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci#define UNDEF 0xffffffff 28162306a36Sopenharmony_ci#define SPARE 0xfffffffe 28262306a36Sopenharmony_ci#define UNUSABLE 0xfffffffd 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic const int erase_bad_lba_entries = 0; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* send vendor interface command (0x41) */ 28762306a36Sopenharmony_ci/* called for requests 0, 1, 8 */ 28862306a36Sopenharmony_cistatic int 28962306a36Sopenharmony_cisddr09_send_command(struct us_data *us, 29062306a36Sopenharmony_ci unsigned char request, 29162306a36Sopenharmony_ci unsigned char direction, 29262306a36Sopenharmony_ci unsigned char *xfer_data, 29362306a36Sopenharmony_ci unsigned int xfer_len) { 29462306a36Sopenharmony_ci unsigned int pipe; 29562306a36Sopenharmony_ci unsigned char requesttype = (0x41 | direction); 29662306a36Sopenharmony_ci int rc; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci // Get the receive or send control pipe number 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (direction == USB_DIR_IN) 30162306a36Sopenharmony_ci pipe = us->recv_ctrl_pipe; 30262306a36Sopenharmony_ci else 30362306a36Sopenharmony_ci pipe = us->send_ctrl_pipe; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype, 30662306a36Sopenharmony_ci 0, 0, xfer_data, xfer_len); 30762306a36Sopenharmony_ci switch (rc) { 30862306a36Sopenharmony_ci case USB_STOR_XFER_GOOD: return 0; 30962306a36Sopenharmony_ci case USB_STOR_XFER_STALLED: return -EPIPE; 31062306a36Sopenharmony_ci default: return -EIO; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int 31562306a36Sopenharmony_cisddr09_send_scsi_command(struct us_data *us, 31662306a36Sopenharmony_ci unsigned char *command, 31762306a36Sopenharmony_ci unsigned int command_len) { 31862306a36Sopenharmony_ci return sddr09_send_command(us, 0, USB_DIR_OUT, command, command_len); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci#if 0 32262306a36Sopenharmony_ci/* 32362306a36Sopenharmony_ci * Test Unit Ready Command: 12 bytes. 32462306a36Sopenharmony_ci * byte 0: opcode: 00 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_cistatic int 32762306a36Sopenharmony_cisddr09_test_unit_ready(struct us_data *us) { 32862306a36Sopenharmony_ci unsigned char *command = us->iobuf; 32962306a36Sopenharmony_ci int result; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci memset(command, 0, 6); 33262306a36Sopenharmony_ci command[1] = LUNBITS; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 6); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci usb_stor_dbg(us, "sddr09_test_unit_ready returns %d\n", result); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return result; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci#endif 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/* 34362306a36Sopenharmony_ci * Request Sense Command: 12 bytes. 34462306a36Sopenharmony_ci * byte 0: opcode: 03 34562306a36Sopenharmony_ci * byte 4: data length 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_cistatic int 34862306a36Sopenharmony_cisddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { 34962306a36Sopenharmony_ci unsigned char *command = us->iobuf; 35062306a36Sopenharmony_ci int result; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci memset(command, 0, 12); 35362306a36Sopenharmony_ci command[0] = 0x03; 35462306a36Sopenharmony_ci command[1] = LUNBITS; 35562306a36Sopenharmony_ci command[4] = buflen; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 12); 35862306a36Sopenharmony_ci if (result) 35962306a36Sopenharmony_ci return result; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 36262306a36Sopenharmony_ci sensebuf, buflen, NULL); 36362306a36Sopenharmony_ci return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/* 36762306a36Sopenharmony_ci * Read Command: 12 bytes. 36862306a36Sopenharmony_ci * byte 0: opcode: E8 36962306a36Sopenharmony_ci * byte 1: last two bits: 00: read data, 01: read blockwise control, 37062306a36Sopenharmony_ci * 10: read both, 11: read pagewise control. 37162306a36Sopenharmony_ci * It turns out we need values 20, 21, 22, 23 here (LUN 1). 37262306a36Sopenharmony_ci * bytes 2-5: address (interpretation depends on byte 1, see below) 37362306a36Sopenharmony_ci * bytes 10-11: count (idem) 37462306a36Sopenharmony_ci * 37562306a36Sopenharmony_ci * A page has 512 data bytes and 64 control bytes (16 control and 48 junk). 37662306a36Sopenharmony_ci * A read data command gets data in 512-byte pages. 37762306a36Sopenharmony_ci * A read control command gets control in 64-byte chunks. 37862306a36Sopenharmony_ci * A read both command gets data+control in 576-byte chunks. 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * Blocks are groups of 32 pages, and read blockwise control jumps to the 38162306a36Sopenharmony_ci * next block, while read pagewise control jumps to the next page after 38262306a36Sopenharmony_ci * reading a group of 64 control bytes. 38362306a36Sopenharmony_ci * [Here 512 = 1<<pageshift, 32 = 1<<blockshift, 64 is constant?] 38462306a36Sopenharmony_ci * 38562306a36Sopenharmony_ci * (1 MB and 2 MB cards are a bit different, but I have only a 16 MB card.) 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int 38962306a36Sopenharmony_cisddr09_readX(struct us_data *us, int x, unsigned long fromaddress, 39062306a36Sopenharmony_ci int nr_of_pages, int bulklen, unsigned char *buf, 39162306a36Sopenharmony_ci int use_sg) { 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci unsigned char *command = us->iobuf; 39462306a36Sopenharmony_ci int result; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci command[0] = 0xE8; 39762306a36Sopenharmony_ci command[1] = LUNBITS | x; 39862306a36Sopenharmony_ci command[2] = MSB_of(fromaddress>>16); 39962306a36Sopenharmony_ci command[3] = LSB_of(fromaddress>>16); 40062306a36Sopenharmony_ci command[4] = MSB_of(fromaddress & 0xFFFF); 40162306a36Sopenharmony_ci command[5] = LSB_of(fromaddress & 0xFFFF); 40262306a36Sopenharmony_ci command[6] = 0; 40362306a36Sopenharmony_ci command[7] = 0; 40462306a36Sopenharmony_ci command[8] = 0; 40562306a36Sopenharmony_ci command[9] = 0; 40662306a36Sopenharmony_ci command[10] = MSB_of(nr_of_pages); 40762306a36Sopenharmony_ci command[11] = LSB_of(nr_of_pages); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 12); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (result) { 41262306a36Sopenharmony_ci usb_stor_dbg(us, "Result for send_control in sddr09_read2%d %d\n", 41362306a36Sopenharmony_ci x, result); 41462306a36Sopenharmony_ci return result; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, 41862306a36Sopenharmony_ci buf, bulklen, use_sg, NULL); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) { 42162306a36Sopenharmony_ci usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read2%d %d\n", 42262306a36Sopenharmony_ci x, result); 42362306a36Sopenharmony_ci return -EIO; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* 42962306a36Sopenharmony_ci * Read Data 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci * fromaddress counts data shorts: 43262306a36Sopenharmony_ci * increasing it by 256 shifts the bytestream by 512 bytes; 43362306a36Sopenharmony_ci * the last 8 bits are ignored. 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * nr_of_pages counts pages of size (1 << pageshift). 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_cistatic int 43862306a36Sopenharmony_cisddr09_read20(struct us_data *us, unsigned long fromaddress, 43962306a36Sopenharmony_ci int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { 44062306a36Sopenharmony_ci int bulklen = nr_of_pages << pageshift; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* The last 8 bits of fromaddress are ignored. */ 44362306a36Sopenharmony_ci return sddr09_readX(us, 0, fromaddress, nr_of_pages, bulklen, 44462306a36Sopenharmony_ci buf, use_sg); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/* 44862306a36Sopenharmony_ci * Read Blockwise Control 44962306a36Sopenharmony_ci * 45062306a36Sopenharmony_ci * fromaddress gives the starting position (as in read data; 45162306a36Sopenharmony_ci * the last 8 bits are ignored); increasing it by 32*256 shifts 45262306a36Sopenharmony_ci * the output stream by 64 bytes. 45362306a36Sopenharmony_ci * 45462306a36Sopenharmony_ci * count counts control groups of size (1 << controlshift). 45562306a36Sopenharmony_ci * For me, controlshift = 6. Is this constant? 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci * After getting one control group, jump to the next block 45862306a36Sopenharmony_ci * (fromaddress += 8192). 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_cistatic int 46162306a36Sopenharmony_cisddr09_read21(struct us_data *us, unsigned long fromaddress, 46262306a36Sopenharmony_ci int count, int controlshift, unsigned char *buf, int use_sg) { 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci int bulklen = (count << controlshift); 46562306a36Sopenharmony_ci return sddr09_readX(us, 1, fromaddress, count, bulklen, 46662306a36Sopenharmony_ci buf, use_sg); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* 47062306a36Sopenharmony_ci * Read both Data and Control 47162306a36Sopenharmony_ci * 47262306a36Sopenharmony_ci * fromaddress counts data shorts, ignoring control: 47362306a36Sopenharmony_ci * increasing it by 256 shifts the bytestream by 576 = 512+64 bytes; 47462306a36Sopenharmony_ci * the last 8 bits are ignored. 47562306a36Sopenharmony_ci * 47662306a36Sopenharmony_ci * nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift). 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic int 47962306a36Sopenharmony_cisddr09_read22(struct us_data *us, unsigned long fromaddress, 48062306a36Sopenharmony_ci int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); 48362306a36Sopenharmony_ci usb_stor_dbg(us, "reading %d pages, %d bytes\n", nr_of_pages, bulklen); 48462306a36Sopenharmony_ci return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen, 48562306a36Sopenharmony_ci buf, use_sg); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci#if 0 48962306a36Sopenharmony_ci/* 49062306a36Sopenharmony_ci * Read Pagewise Control 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * fromaddress gives the starting position (as in read data; 49362306a36Sopenharmony_ci * the last 8 bits are ignored); increasing it by 256 shifts 49462306a36Sopenharmony_ci * the output stream by 64 bytes. 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * count counts control groups of size (1 << controlshift). 49762306a36Sopenharmony_ci * For me, controlshift = 6. Is this constant? 49862306a36Sopenharmony_ci * 49962306a36Sopenharmony_ci * After getting one control group, jump to the next page 50062306a36Sopenharmony_ci * (fromaddress += 256). 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_cistatic int 50362306a36Sopenharmony_cisddr09_read23(struct us_data *us, unsigned long fromaddress, 50462306a36Sopenharmony_ci int count, int controlshift, unsigned char *buf, int use_sg) { 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci int bulklen = (count << controlshift); 50762306a36Sopenharmony_ci return sddr09_readX(us, 3, fromaddress, count, bulklen, 50862306a36Sopenharmony_ci buf, use_sg); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci#endif 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci/* 51362306a36Sopenharmony_ci * Erase Command: 12 bytes. 51462306a36Sopenharmony_ci * byte 0: opcode: EA 51562306a36Sopenharmony_ci * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored. 51862306a36Sopenharmony_ci * The byte address being erased is 2*Eaddress. 51962306a36Sopenharmony_ci * The CIS cannot be erased. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_cistatic int 52262306a36Sopenharmony_cisddr09_erase(struct us_data *us, unsigned long Eaddress) { 52362306a36Sopenharmony_ci unsigned char *command = us->iobuf; 52462306a36Sopenharmony_ci int result; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci usb_stor_dbg(us, "erase address %lu\n", Eaddress); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci memset(command, 0, 12); 52962306a36Sopenharmony_ci command[0] = 0xEA; 53062306a36Sopenharmony_ci command[1] = LUNBITS; 53162306a36Sopenharmony_ci command[6] = MSB_of(Eaddress>>16); 53262306a36Sopenharmony_ci command[7] = LSB_of(Eaddress>>16); 53362306a36Sopenharmony_ci command[8] = MSB_of(Eaddress & 0xFFFF); 53462306a36Sopenharmony_ci command[9] = LSB_of(Eaddress & 0xFFFF); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 12); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (result) 53962306a36Sopenharmony_ci usb_stor_dbg(us, "Result for send_control in sddr09_erase %d\n", 54062306a36Sopenharmony_ci result); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return result; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/* 54662306a36Sopenharmony_ci * Write CIS Command: 12 bytes. 54762306a36Sopenharmony_ci * byte 0: opcode: EE 54862306a36Sopenharmony_ci * bytes 2-5: write address in shorts 54962306a36Sopenharmony_ci * bytes 10-11: sector count 55062306a36Sopenharmony_ci * 55162306a36Sopenharmony_ci * This writes at the indicated address. Don't know how it differs 55262306a36Sopenharmony_ci * from E9. Maybe it does not erase? However, it will also write to 55362306a36Sopenharmony_ci * the CIS. 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * When two such commands on the same page follow each other directly, 55662306a36Sopenharmony_ci * the second one is not done. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/* 56062306a36Sopenharmony_ci * Write Command: 12 bytes. 56162306a36Sopenharmony_ci * byte 0: opcode: E9 56262306a36Sopenharmony_ci * bytes 2-5: write address (big-endian, counting shorts, sector aligned). 56362306a36Sopenharmony_ci * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). 56462306a36Sopenharmony_ci * bytes 10-11: sector count (big-endian, in 512-byte sectors). 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci * If write address equals erase address, the erase is done first, 56762306a36Sopenharmony_ci * otherwise the write is done first. When erase address equals zero 56862306a36Sopenharmony_ci * no erase is done? 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_cistatic int 57162306a36Sopenharmony_cisddr09_writeX(struct us_data *us, 57262306a36Sopenharmony_ci unsigned long Waddress, unsigned long Eaddress, 57362306a36Sopenharmony_ci int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) { 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci unsigned char *command = us->iobuf; 57662306a36Sopenharmony_ci int result; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci command[0] = 0xE9; 57962306a36Sopenharmony_ci command[1] = LUNBITS; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci command[2] = MSB_of(Waddress>>16); 58262306a36Sopenharmony_ci command[3] = LSB_of(Waddress>>16); 58362306a36Sopenharmony_ci command[4] = MSB_of(Waddress & 0xFFFF); 58462306a36Sopenharmony_ci command[5] = LSB_of(Waddress & 0xFFFF); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci command[6] = MSB_of(Eaddress>>16); 58762306a36Sopenharmony_ci command[7] = LSB_of(Eaddress>>16); 58862306a36Sopenharmony_ci command[8] = MSB_of(Eaddress & 0xFFFF); 58962306a36Sopenharmony_ci command[9] = LSB_of(Eaddress & 0xFFFF); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci command[10] = MSB_of(nr_of_pages); 59262306a36Sopenharmony_ci command[11] = LSB_of(nr_of_pages); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 12); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (result) { 59762306a36Sopenharmony_ci usb_stor_dbg(us, "Result for send_control in sddr09_writeX %d\n", 59862306a36Sopenharmony_ci result); 59962306a36Sopenharmony_ci return result; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, 60362306a36Sopenharmony_ci buf, bulklen, use_sg, NULL); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) { 60662306a36Sopenharmony_ci usb_stor_dbg(us, "Result for bulk_transfer in sddr09_writeX %d\n", 60762306a36Sopenharmony_ci result); 60862306a36Sopenharmony_ci return -EIO; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/* erase address, write same address */ 61462306a36Sopenharmony_cistatic int 61562306a36Sopenharmony_cisddr09_write_inplace(struct us_data *us, unsigned long address, 61662306a36Sopenharmony_ci int nr_of_pages, int pageshift, unsigned char *buf, 61762306a36Sopenharmony_ci int use_sg) { 61862306a36Sopenharmony_ci int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); 61962306a36Sopenharmony_ci return sddr09_writeX(us, address, address, nr_of_pages, bulklen, 62062306a36Sopenharmony_ci buf, use_sg); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci#if 0 62462306a36Sopenharmony_ci/* 62562306a36Sopenharmony_ci * Read Scatter Gather Command: 3+4n bytes. 62662306a36Sopenharmony_ci * byte 0: opcode E7 62762306a36Sopenharmony_ci * byte 2: n 62862306a36Sopenharmony_ci * bytes 4i-1,4i,4i+1: page address 62962306a36Sopenharmony_ci * byte 4i+2: page count 63062306a36Sopenharmony_ci * (i=1..n) 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * This reads several pages from the card to a single memory buffer. 63362306a36Sopenharmony_ci * The last two bits of byte 1 have the same meaning as for E8. 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_cistatic int 63662306a36Sopenharmony_cisddr09_read_sg_test_only(struct us_data *us) { 63762306a36Sopenharmony_ci unsigned char *command = us->iobuf; 63862306a36Sopenharmony_ci int result, bulklen, nsg, ct; 63962306a36Sopenharmony_ci unsigned char *buf; 64062306a36Sopenharmony_ci unsigned long address; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci nsg = bulklen = 0; 64362306a36Sopenharmony_ci command[0] = 0xE7; 64462306a36Sopenharmony_ci command[1] = LUNBITS; 64562306a36Sopenharmony_ci command[2] = 0; 64662306a36Sopenharmony_ci address = 040000; ct = 1; 64762306a36Sopenharmony_ci nsg++; 64862306a36Sopenharmony_ci bulklen += (ct << 9); 64962306a36Sopenharmony_ci command[4*nsg+2] = ct; 65062306a36Sopenharmony_ci command[4*nsg+1] = ((address >> 9) & 0xFF); 65162306a36Sopenharmony_ci command[4*nsg+0] = ((address >> 17) & 0xFF); 65262306a36Sopenharmony_ci command[4*nsg-1] = ((address >> 25) & 0xFF); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci address = 0340000; ct = 1; 65562306a36Sopenharmony_ci nsg++; 65662306a36Sopenharmony_ci bulklen += (ct << 9); 65762306a36Sopenharmony_ci command[4*nsg+2] = ct; 65862306a36Sopenharmony_ci command[4*nsg+1] = ((address >> 9) & 0xFF); 65962306a36Sopenharmony_ci command[4*nsg+0] = ((address >> 17) & 0xFF); 66062306a36Sopenharmony_ci command[4*nsg-1] = ((address >> 25) & 0xFF); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci address = 01000000; ct = 2; 66362306a36Sopenharmony_ci nsg++; 66462306a36Sopenharmony_ci bulklen += (ct << 9); 66562306a36Sopenharmony_ci command[4*nsg+2] = ct; 66662306a36Sopenharmony_ci command[4*nsg+1] = ((address >> 9) & 0xFF); 66762306a36Sopenharmony_ci command[4*nsg+0] = ((address >> 17) & 0xFF); 66862306a36Sopenharmony_ci command[4*nsg-1] = ((address >> 25) & 0xFF); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci command[2] = nsg; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 4*nsg+3); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (result) { 67562306a36Sopenharmony_ci usb_stor_dbg(us, "Result for send_control in sddr09_read_sg %d\n", 67662306a36Sopenharmony_ci result); 67762306a36Sopenharmony_ci return result; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci buf = kmalloc(bulklen, GFP_NOIO); 68162306a36Sopenharmony_ci if (!buf) 68262306a36Sopenharmony_ci return -ENOMEM; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 68562306a36Sopenharmony_ci buf, bulklen, NULL); 68662306a36Sopenharmony_ci kfree(buf); 68762306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) { 68862306a36Sopenharmony_ci usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read_sg %d\n", 68962306a36Sopenharmony_ci result); 69062306a36Sopenharmony_ci return -EIO; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci#endif 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/* 69862306a36Sopenharmony_ci * Read Status Command: 12 bytes. 69962306a36Sopenharmony_ci * byte 0: opcode: EC 70062306a36Sopenharmony_ci * 70162306a36Sopenharmony_ci * Returns 64 bytes, all zero except for the first. 70262306a36Sopenharmony_ci * bit 0: 1: Error 70362306a36Sopenharmony_ci * bit 5: 1: Suspended 70462306a36Sopenharmony_ci * bit 6: 1: Ready 70562306a36Sopenharmony_ci * bit 7: 1: Not write-protected 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic int 70962306a36Sopenharmony_cisddr09_read_status(struct us_data *us, unsigned char *status) { 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci unsigned char *command = us->iobuf; 71262306a36Sopenharmony_ci unsigned char *data = us->iobuf; 71362306a36Sopenharmony_ci int result; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci usb_stor_dbg(us, "Reading status...\n"); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci memset(command, 0, 12); 71862306a36Sopenharmony_ci command[0] = 0xEC; 71962306a36Sopenharmony_ci command[1] = LUNBITS; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 12); 72262306a36Sopenharmony_ci if (result) 72362306a36Sopenharmony_ci return result; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 72662306a36Sopenharmony_ci data, 64, NULL); 72762306a36Sopenharmony_ci *status = data[0]; 72862306a36Sopenharmony_ci return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int 73262306a36Sopenharmony_cisddr09_read_data(struct us_data *us, 73362306a36Sopenharmony_ci unsigned long address, 73462306a36Sopenharmony_ci unsigned int sectors) { 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; 73762306a36Sopenharmony_ci unsigned char *buffer; 73862306a36Sopenharmony_ci unsigned int lba, maxlba, pba; 73962306a36Sopenharmony_ci unsigned int page, pages; 74062306a36Sopenharmony_ci unsigned int len, offset; 74162306a36Sopenharmony_ci struct scatterlist *sg; 74262306a36Sopenharmony_ci int result; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci // Figure out the initial LBA and page 74562306a36Sopenharmony_ci lba = address >> info->blockshift; 74662306a36Sopenharmony_ci page = (address & info->blockmask); 74762306a36Sopenharmony_ci maxlba = info->capacity >> (info->pageshift + info->blockshift); 74862306a36Sopenharmony_ci if (lba >= maxlba) 74962306a36Sopenharmony_ci return -EIO; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci // Since we only read in one block at a time, we have to create 75262306a36Sopenharmony_ci // a bounce buffer and move the data a piece at a time between the 75362306a36Sopenharmony_ci // bounce buffer and the actual transfer buffer. 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; 75662306a36Sopenharmony_ci buffer = kmalloc(len, GFP_NOIO); 75762306a36Sopenharmony_ci if (!buffer) 75862306a36Sopenharmony_ci return -ENOMEM; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci // This could be made much more efficient by checking for 76162306a36Sopenharmony_ci // contiguous LBA's. Another exercise left to the student. 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci result = 0; 76462306a36Sopenharmony_ci offset = 0; 76562306a36Sopenharmony_ci sg = NULL; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci while (sectors > 0) { 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Find number of pages we can read in this block */ 77062306a36Sopenharmony_ci pages = min(sectors, info->blocksize - page); 77162306a36Sopenharmony_ci len = pages << info->pageshift; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* Not overflowing capacity? */ 77462306a36Sopenharmony_ci if (lba >= maxlba) { 77562306a36Sopenharmony_ci usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", 77662306a36Sopenharmony_ci lba, maxlba); 77762306a36Sopenharmony_ci result = -EIO; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* Find where this lba lives on disk */ 78262306a36Sopenharmony_ci pba = info->lba_to_pba[lba]; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (pba == UNDEF) { /* this lba was never written */ 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n", 78762306a36Sopenharmony_ci pages, lba, page); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* 79062306a36Sopenharmony_ci * This is not really an error. It just means 79162306a36Sopenharmony_ci * that the block has never been written. 79262306a36Sopenharmony_ci * Instead of returning an error 79362306a36Sopenharmony_ci * it is better to return all zero data. 79462306a36Sopenharmony_ci */ 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci memset(buffer, 0, len); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci } else { 79962306a36Sopenharmony_ci usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n", 80062306a36Sopenharmony_ci pages, pba, lba, page); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci address = ((pba << info->blockshift) + page) << 80362306a36Sopenharmony_ci info->pageshift; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci result = sddr09_read20(us, address>>1, 80662306a36Sopenharmony_ci pages, info->pageshift, buffer, 0); 80762306a36Sopenharmony_ci if (result) 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci // Store the data in the transfer buffer 81262306a36Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 81362306a36Sopenharmony_ci &sg, &offset, TO_XFER_BUF); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci page = 0; 81662306a36Sopenharmony_ci lba++; 81762306a36Sopenharmony_ci sectors -= pages; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci kfree(buffer); 82162306a36Sopenharmony_ci return result; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic unsigned int 82562306a36Sopenharmony_cisddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) { 82662306a36Sopenharmony_ci static unsigned int lastpba = 1; 82762306a36Sopenharmony_ci int zonestart, end, i; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci zonestart = (lba/1000) << 10; 83062306a36Sopenharmony_ci end = info->capacity >> (info->blockshift + info->pageshift); 83162306a36Sopenharmony_ci end -= zonestart; 83262306a36Sopenharmony_ci if (end > 1024) 83362306a36Sopenharmony_ci end = 1024; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci for (i = lastpba+1; i < end; i++) { 83662306a36Sopenharmony_ci if (info->pba_to_lba[zonestart+i] == UNDEF) { 83762306a36Sopenharmony_ci lastpba = i; 83862306a36Sopenharmony_ci return zonestart+i; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci for (i = 0; i <= lastpba; i++) { 84262306a36Sopenharmony_ci if (info->pba_to_lba[zonestart+i] == UNDEF) { 84362306a36Sopenharmony_ci lastpba = i; 84462306a36Sopenharmony_ci return zonestart+i; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int 85162306a36Sopenharmony_cisddr09_write_lba(struct us_data *us, unsigned int lba, 85262306a36Sopenharmony_ci unsigned int page, unsigned int pages, 85362306a36Sopenharmony_ci unsigned char *ptr, unsigned char *blockbuffer) { 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; 85662306a36Sopenharmony_ci unsigned long address; 85762306a36Sopenharmony_ci unsigned int pba, lbap; 85862306a36Sopenharmony_ci unsigned int pagelen; 85962306a36Sopenharmony_ci unsigned char *bptr, *cptr, *xptr; 86062306a36Sopenharmony_ci unsigned char ecc[3]; 86162306a36Sopenharmony_ci int i, result; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci lbap = ((lba % 1000) << 1) | 0x1000; 86462306a36Sopenharmony_ci if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) 86562306a36Sopenharmony_ci lbap ^= 1; 86662306a36Sopenharmony_ci pba = info->lba_to_pba[lba]; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (pba == UNDEF) { 86962306a36Sopenharmony_ci pba = sddr09_find_unused_pba(info, lba); 87062306a36Sopenharmony_ci if (!pba) { 87162306a36Sopenharmony_ci printk(KERN_WARNING 87262306a36Sopenharmony_ci "sddr09_write_lba: Out of unused blocks\n"); 87362306a36Sopenharmony_ci return -ENOSPC; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci info->pba_to_lba[pba] = lba; 87662306a36Sopenharmony_ci info->lba_to_pba[lba] = pba; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (pba == 1) { 88062306a36Sopenharmony_ci /* 88162306a36Sopenharmony_ci * Maybe it is impossible to write to PBA 1. 88262306a36Sopenharmony_ci * Fake success, but don't do anything. 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci printk(KERN_WARNING "sddr09: avoid writing to pba 1\n"); 88562306a36Sopenharmony_ci return 0; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* read old contents */ 89162306a36Sopenharmony_ci address = (pba << (info->pageshift + info->blockshift)); 89262306a36Sopenharmony_ci result = sddr09_read22(us, address>>1, info->blocksize, 89362306a36Sopenharmony_ci info->pageshift, blockbuffer, 0); 89462306a36Sopenharmony_ci if (result) 89562306a36Sopenharmony_ci return result; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* check old contents and fill lba */ 89862306a36Sopenharmony_ci for (i = 0; i < info->blocksize; i++) { 89962306a36Sopenharmony_ci bptr = blockbuffer + i*pagelen; 90062306a36Sopenharmony_ci cptr = bptr + info->pagesize; 90162306a36Sopenharmony_ci nand_compute_ecc(bptr, ecc); 90262306a36Sopenharmony_ci if (!nand_compare_ecc(cptr+13, ecc)) { 90362306a36Sopenharmony_ci usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n", 90462306a36Sopenharmony_ci i, pba); 90562306a36Sopenharmony_ci nand_store_ecc(cptr+13, ecc); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci nand_compute_ecc(bptr+(info->pagesize / 2), ecc); 90862306a36Sopenharmony_ci if (!nand_compare_ecc(cptr+8, ecc)) { 90962306a36Sopenharmony_ci usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n", 91062306a36Sopenharmony_ci i, pba); 91162306a36Sopenharmony_ci nand_store_ecc(cptr+8, ecc); 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci cptr[6] = cptr[11] = MSB_of(lbap); 91462306a36Sopenharmony_ci cptr[7] = cptr[12] = LSB_of(lbap); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* copy in new stuff and compute ECC */ 91862306a36Sopenharmony_ci xptr = ptr; 91962306a36Sopenharmony_ci for (i = page; i < page+pages; i++) { 92062306a36Sopenharmony_ci bptr = blockbuffer + i*pagelen; 92162306a36Sopenharmony_ci cptr = bptr + info->pagesize; 92262306a36Sopenharmony_ci memcpy(bptr, xptr, info->pagesize); 92362306a36Sopenharmony_ci xptr += info->pagesize; 92462306a36Sopenharmony_ci nand_compute_ecc(bptr, ecc); 92562306a36Sopenharmony_ci nand_store_ecc(cptr+13, ecc); 92662306a36Sopenharmony_ci nand_compute_ecc(bptr+(info->pagesize / 2), ecc); 92762306a36Sopenharmony_ci nand_store_ecc(cptr+8, ecc); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci usb_stor_dbg(us, "Rewrite PBA %d (LBA %d)\n", pba, lba); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci result = sddr09_write_inplace(us, address>>1, info->blocksize, 93362306a36Sopenharmony_ci info->pageshift, blockbuffer, 0); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci usb_stor_dbg(us, "sddr09_write_inplace returns %d\n", result); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci#if 0 93862306a36Sopenharmony_ci { 93962306a36Sopenharmony_ci unsigned char status = 0; 94062306a36Sopenharmony_ci int result2 = sddr09_read_status(us, &status); 94162306a36Sopenharmony_ci if (result2) 94262306a36Sopenharmony_ci usb_stor_dbg(us, "cannot read status\n"); 94362306a36Sopenharmony_ci else if (status != 0xc0) 94462306a36Sopenharmony_ci usb_stor_dbg(us, "status after write: 0x%x\n", status); 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci#endif 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci#if 0 94962306a36Sopenharmony_ci { 95062306a36Sopenharmony_ci int result2 = sddr09_test_unit_ready(us); 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci#endif 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return result; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic int 95862306a36Sopenharmony_cisddr09_write_data(struct us_data *us, 95962306a36Sopenharmony_ci unsigned long address, 96062306a36Sopenharmony_ci unsigned int sectors) { 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; 96362306a36Sopenharmony_ci unsigned int lba, maxlba, page, pages; 96462306a36Sopenharmony_ci unsigned int pagelen, blocklen; 96562306a36Sopenharmony_ci unsigned char *blockbuffer; 96662306a36Sopenharmony_ci unsigned char *buffer; 96762306a36Sopenharmony_ci unsigned int len, offset; 96862306a36Sopenharmony_ci struct scatterlist *sg; 96962306a36Sopenharmony_ci int result; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* Figure out the initial LBA and page */ 97262306a36Sopenharmony_ci lba = address >> info->blockshift; 97362306a36Sopenharmony_ci page = (address & info->blockmask); 97462306a36Sopenharmony_ci maxlba = info->capacity >> (info->pageshift + info->blockshift); 97562306a36Sopenharmony_ci if (lba >= maxlba) 97662306a36Sopenharmony_ci return -EIO; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* 97962306a36Sopenharmony_ci * blockbuffer is used for reading in the old data, overwriting 98062306a36Sopenharmony_ci * with the new data, and performing ECC calculations 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* 98462306a36Sopenharmony_ci * TODO: instead of doing kmalloc/kfree for each write, 98562306a36Sopenharmony_ci * add a bufferpointer to the info structure 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); 98962306a36Sopenharmony_ci blocklen = (pagelen << info->blockshift); 99062306a36Sopenharmony_ci blockbuffer = kmalloc(blocklen, GFP_NOIO); 99162306a36Sopenharmony_ci if (!blockbuffer) 99262306a36Sopenharmony_ci return -ENOMEM; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* 99562306a36Sopenharmony_ci * Since we don't write the user data directly to the device, 99662306a36Sopenharmony_ci * we have to create a bounce buffer and move the data a piece 99762306a36Sopenharmony_ci * at a time between the bounce buffer and the actual transfer buffer. 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; 100162306a36Sopenharmony_ci buffer = kmalloc(len, GFP_NOIO); 100262306a36Sopenharmony_ci if (!buffer) { 100362306a36Sopenharmony_ci kfree(blockbuffer); 100462306a36Sopenharmony_ci return -ENOMEM; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci result = 0; 100862306a36Sopenharmony_ci offset = 0; 100962306a36Sopenharmony_ci sg = NULL; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci while (sectors > 0) { 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* Write as many sectors as possible in this block */ 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci pages = min(sectors, info->blocksize - page); 101662306a36Sopenharmony_ci len = (pages << info->pageshift); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* Not overflowing capacity? */ 101962306a36Sopenharmony_ci if (lba >= maxlba) { 102062306a36Sopenharmony_ci usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", 102162306a36Sopenharmony_ci lba, maxlba); 102262306a36Sopenharmony_ci result = -EIO; 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* Get the data from the transfer buffer */ 102762306a36Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 102862306a36Sopenharmony_ci &sg, &offset, FROM_XFER_BUF); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci result = sddr09_write_lba(us, lba, page, pages, 103162306a36Sopenharmony_ci buffer, blockbuffer); 103262306a36Sopenharmony_ci if (result) 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci page = 0; 103662306a36Sopenharmony_ci lba++; 103762306a36Sopenharmony_ci sectors -= pages; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci kfree(buffer); 104162306a36Sopenharmony_ci kfree(blockbuffer); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci return result; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic int 104762306a36Sopenharmony_cisddr09_read_control(struct us_data *us, 104862306a36Sopenharmony_ci unsigned long address, 104962306a36Sopenharmony_ci unsigned int blocks, 105062306a36Sopenharmony_ci unsigned char *content, 105162306a36Sopenharmony_ci int use_sg) { 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci usb_stor_dbg(us, "Read control address %lu, blocks %d\n", 105462306a36Sopenharmony_ci address, blocks); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci return sddr09_read21(us, address, blocks, 105762306a36Sopenharmony_ci CONTROL_SHIFT, content, use_sg); 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci/* 106162306a36Sopenharmony_ci * Read Device ID Command: 12 bytes. 106262306a36Sopenharmony_ci * byte 0: opcode: ED 106362306a36Sopenharmony_ci * 106462306a36Sopenharmony_ci * Returns 2 bytes: Manufacturer ID and Device ID. 106562306a36Sopenharmony_ci * On more recent cards 3 bytes: the third byte is an option code A5 106662306a36Sopenharmony_ci * signifying that the secret command to read an 128-bit ID is available. 106762306a36Sopenharmony_ci * On still more recent cards 4 bytes: the fourth byte C0 means that 106862306a36Sopenharmony_ci * a second read ID cmd is available. 106962306a36Sopenharmony_ci */ 107062306a36Sopenharmony_cistatic int 107162306a36Sopenharmony_cisddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { 107262306a36Sopenharmony_ci unsigned char *command = us->iobuf; 107362306a36Sopenharmony_ci unsigned char *content = us->iobuf; 107462306a36Sopenharmony_ci int result, i; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci memset(command, 0, 12); 107762306a36Sopenharmony_ci command[0] = 0xED; 107862306a36Sopenharmony_ci command[1] = LUNBITS; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, command, 12); 108162306a36Sopenharmony_ci if (result) 108262306a36Sopenharmony_ci return result; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 108562306a36Sopenharmony_ci content, 64, NULL); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 108862306a36Sopenharmony_ci deviceID[i] = content[i]; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic int 109462306a36Sopenharmony_cisddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) { 109562306a36Sopenharmony_ci int result; 109662306a36Sopenharmony_ci unsigned char status; 109762306a36Sopenharmony_ci const char *wp_fmt; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci result = sddr09_read_status(us, &status); 110062306a36Sopenharmony_ci if (result) { 110162306a36Sopenharmony_ci usb_stor_dbg(us, "read_status fails\n"); 110262306a36Sopenharmony_ci return result; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci if ((status & 0x80) == 0) { 110562306a36Sopenharmony_ci info->flags |= SDDR09_WP; /* write protected */ 110662306a36Sopenharmony_ci wp_fmt = " WP"; 110762306a36Sopenharmony_ci } else { 110862306a36Sopenharmony_ci wp_fmt = ""; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci usb_stor_dbg(us, "status 0x%02X%s%s%s%s\n", status, wp_fmt, 111162306a36Sopenharmony_ci status & 0x40 ? " Ready" : "", 111262306a36Sopenharmony_ci status & LUNBITS ? " Suspended" : "", 111362306a36Sopenharmony_ci status & 0x01 ? " Error" : ""); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci#if 0 111962306a36Sopenharmony_ci/* 112062306a36Sopenharmony_ci * Reset Command: 12 bytes. 112162306a36Sopenharmony_ci * byte 0: opcode: EB 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_cistatic int 112462306a36Sopenharmony_cisddr09_reset(struct us_data *us) { 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci unsigned char *command = us->iobuf; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci memset(command, 0, 12); 112962306a36Sopenharmony_ci command[0] = 0xEB; 113062306a36Sopenharmony_ci command[1] = LUNBITS; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci return sddr09_send_scsi_command(us, command, 12); 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci#endif 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic struct nand_flash_dev * 113762306a36Sopenharmony_cisddr09_get_cardinfo(struct us_data *us, unsigned char flags) { 113862306a36Sopenharmony_ci struct nand_flash_dev *cardinfo; 113962306a36Sopenharmony_ci unsigned char deviceID[4]; 114062306a36Sopenharmony_ci char blurbtxt[256]; 114162306a36Sopenharmony_ci int result; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci usb_stor_dbg(us, "Reading capacity...\n"); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci result = sddr09_read_deviceID(us, deviceID); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (result) { 114862306a36Sopenharmony_ci usb_stor_dbg(us, "Result of read_deviceID is %d\n", result); 114962306a36Sopenharmony_ci printk(KERN_WARNING "sddr09: could not read card info\n"); 115062306a36Sopenharmony_ci return NULL; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci sprintf(blurbtxt, "sddr09: Found Flash card, ID = %4ph", deviceID); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* Byte 0 is the manufacturer */ 115662306a36Sopenharmony_ci sprintf(blurbtxt + strlen(blurbtxt), 115762306a36Sopenharmony_ci ": Manuf. %s", 115862306a36Sopenharmony_ci nand_flash_manufacturer(deviceID[0])); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* Byte 1 is the device type */ 116162306a36Sopenharmony_ci cardinfo = nand_find_id(deviceID[1]); 116262306a36Sopenharmony_ci if (cardinfo) { 116362306a36Sopenharmony_ci /* 116462306a36Sopenharmony_ci * MB or MiB? It is neither. A 16 MB card has 116562306a36Sopenharmony_ci * 17301504 raw bytes, of which 16384000 are 116662306a36Sopenharmony_ci * usable for user data. 116762306a36Sopenharmony_ci */ 116862306a36Sopenharmony_ci sprintf(blurbtxt + strlen(blurbtxt), 116962306a36Sopenharmony_ci ", %d MB", 1<<(cardinfo->chipshift - 20)); 117062306a36Sopenharmony_ci } else { 117162306a36Sopenharmony_ci sprintf(blurbtxt + strlen(blurbtxt), 117262306a36Sopenharmony_ci ", type unrecognized"); 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* Byte 2 is code to signal availability of 128-bit ID */ 117662306a36Sopenharmony_ci if (deviceID[2] == 0xa5) { 117762306a36Sopenharmony_ci sprintf(blurbtxt + strlen(blurbtxt), 117862306a36Sopenharmony_ci ", 128-bit ID"); 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* Byte 3 announces the availability of another read ID command */ 118262306a36Sopenharmony_ci if (deviceID[3] == 0xc0) { 118362306a36Sopenharmony_ci sprintf(blurbtxt + strlen(blurbtxt), 118462306a36Sopenharmony_ci ", extra cmd"); 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (flags & SDDR09_WP) 118862306a36Sopenharmony_ci sprintf(blurbtxt + strlen(blurbtxt), 118962306a36Sopenharmony_ci ", WP"); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci printk(KERN_WARNING "%s\n", blurbtxt); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci return cardinfo; 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic int 119762306a36Sopenharmony_cisddr09_read_map(struct us_data *us) { 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; 120062306a36Sopenharmony_ci int numblocks, alloc_len, alloc_blocks; 120162306a36Sopenharmony_ci int i, j, result; 120262306a36Sopenharmony_ci unsigned char *buffer, *buffer_end, *ptr; 120362306a36Sopenharmony_ci unsigned int lba, lbact; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (!info->capacity) 120662306a36Sopenharmony_ci return -1; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci /* 120962306a36Sopenharmony_ci * size of a block is 1 << (blockshift + pageshift) bytes 121062306a36Sopenharmony_ci * divide into the total capacity to get the number of blocks 121162306a36Sopenharmony_ci */ 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci numblocks = info->capacity >> (info->blockshift + info->pageshift); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* 121662306a36Sopenharmony_ci * read 64 bytes for every block (actually 1 << CONTROL_SHIFT) 121762306a36Sopenharmony_ci * but only use a 64 KB buffer 121862306a36Sopenharmony_ci * buffer size used must be a multiple of (1 << CONTROL_SHIFT) 121962306a36Sopenharmony_ci */ 122062306a36Sopenharmony_ci#define SDDR09_READ_MAP_BUFSZ 65536 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT); 122362306a36Sopenharmony_ci alloc_len = (alloc_blocks << CONTROL_SHIFT); 122462306a36Sopenharmony_ci buffer = kmalloc(alloc_len, GFP_NOIO); 122562306a36Sopenharmony_ci if (!buffer) { 122662306a36Sopenharmony_ci result = -1; 122762306a36Sopenharmony_ci goto done; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci buffer_end = buffer + alloc_len; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci#undef SDDR09_READ_MAP_BUFSZ 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci kfree(info->lba_to_pba); 123462306a36Sopenharmony_ci kfree(info->pba_to_lba); 123562306a36Sopenharmony_ci info->lba_to_pba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO); 123662306a36Sopenharmony_ci info->pba_to_lba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { 123962306a36Sopenharmony_ci printk(KERN_WARNING "sddr09_read_map: out of memory\n"); 124062306a36Sopenharmony_ci result = -1; 124162306a36Sopenharmony_ci goto done; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci for (i = 0; i < numblocks; i++) 124562306a36Sopenharmony_ci info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci /* 124862306a36Sopenharmony_ci * Define lba-pba translation table 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci ptr = buffer_end; 125262306a36Sopenharmony_ci for (i = 0; i < numblocks; i++) { 125362306a36Sopenharmony_ci ptr += (1 << CONTROL_SHIFT); 125462306a36Sopenharmony_ci if (ptr >= buffer_end) { 125562306a36Sopenharmony_ci unsigned long address; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci address = i << (info->pageshift + info->blockshift); 125862306a36Sopenharmony_ci result = sddr09_read_control( 125962306a36Sopenharmony_ci us, address>>1, 126062306a36Sopenharmony_ci min(alloc_blocks, numblocks - i), 126162306a36Sopenharmony_ci buffer, 0); 126262306a36Sopenharmony_ci if (result) { 126362306a36Sopenharmony_ci result = -1; 126462306a36Sopenharmony_ci goto done; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci ptr = buffer; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (i == 0 || i == 1) { 127062306a36Sopenharmony_ci info->pba_to_lba[i] = UNUSABLE; 127162306a36Sopenharmony_ci continue; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* special PBAs have control field 0^16 */ 127562306a36Sopenharmony_ci for (j = 0; j < 16; j++) 127662306a36Sopenharmony_ci if (ptr[j] != 0) 127762306a36Sopenharmony_ci goto nonz; 127862306a36Sopenharmony_ci info->pba_to_lba[i] = UNUSABLE; 127962306a36Sopenharmony_ci printk(KERN_WARNING "sddr09: PBA %d has no logical mapping\n", 128062306a36Sopenharmony_ci i); 128162306a36Sopenharmony_ci continue; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci nonz: 128462306a36Sopenharmony_ci /* unwritten PBAs have control field FF^16 */ 128562306a36Sopenharmony_ci for (j = 0; j < 16; j++) 128662306a36Sopenharmony_ci if (ptr[j] != 0xff) 128762306a36Sopenharmony_ci goto nonff; 128862306a36Sopenharmony_ci continue; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci nonff: 129162306a36Sopenharmony_ci /* normal PBAs start with six FFs */ 129262306a36Sopenharmony_ci if (j < 6) { 129362306a36Sopenharmony_ci printk(KERN_WARNING 129462306a36Sopenharmony_ci "sddr09: PBA %d has no logical mapping: " 129562306a36Sopenharmony_ci "reserved area = %02X%02X%02X%02X " 129662306a36Sopenharmony_ci "data status %02X block status %02X\n", 129762306a36Sopenharmony_ci i, ptr[0], ptr[1], ptr[2], ptr[3], 129862306a36Sopenharmony_ci ptr[4], ptr[5]); 129962306a36Sopenharmony_ci info->pba_to_lba[i] = UNUSABLE; 130062306a36Sopenharmony_ci continue; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if ((ptr[6] >> 4) != 0x01) { 130462306a36Sopenharmony_ci printk(KERN_WARNING 130562306a36Sopenharmony_ci "sddr09: PBA %d has invalid address field " 130662306a36Sopenharmony_ci "%02X%02X/%02X%02X\n", 130762306a36Sopenharmony_ci i, ptr[6], ptr[7], ptr[11], ptr[12]); 130862306a36Sopenharmony_ci info->pba_to_lba[i] = UNUSABLE; 130962306a36Sopenharmony_ci continue; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* check even parity */ 131362306a36Sopenharmony_ci if (parity[ptr[6] ^ ptr[7]]) { 131462306a36Sopenharmony_ci printk(KERN_WARNING 131562306a36Sopenharmony_ci "sddr09: Bad parity in LBA for block %d" 131662306a36Sopenharmony_ci " (%02X %02X)\n", i, ptr[6], ptr[7]); 131762306a36Sopenharmony_ci info->pba_to_lba[i] = UNUSABLE; 131862306a36Sopenharmony_ci continue; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci lba = short_pack(ptr[7], ptr[6]); 132262306a36Sopenharmony_ci lba = (lba & 0x07FF) >> 1; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* 132562306a36Sopenharmony_ci * Every 1024 physical blocks ("zone"), the LBA numbers 132662306a36Sopenharmony_ci * go back to zero, but are within a higher block of LBA's. 132762306a36Sopenharmony_ci * Also, there is a maximum of 1000 LBA's per zone. 132862306a36Sopenharmony_ci * In other words, in PBA 1024-2047 you will find LBA 0-999 132962306a36Sopenharmony_ci * which are really LBA 1000-1999. This allows for 24 bad 133062306a36Sopenharmony_ci * or special physical blocks per zone. 133162306a36Sopenharmony_ci */ 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (lba >= 1000) { 133462306a36Sopenharmony_ci printk(KERN_WARNING 133562306a36Sopenharmony_ci "sddr09: Bad low LBA %d for block %d\n", 133662306a36Sopenharmony_ci lba, i); 133762306a36Sopenharmony_ci goto possibly_erase; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci lba += 1000*(i/0x400); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (info->lba_to_pba[lba] != UNDEF) { 134362306a36Sopenharmony_ci printk(KERN_WARNING 134462306a36Sopenharmony_ci "sddr09: LBA %d seen for PBA %d and %d\n", 134562306a36Sopenharmony_ci lba, info->lba_to_pba[lba], i); 134662306a36Sopenharmony_ci goto possibly_erase; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci info->pba_to_lba[i] = lba; 135062306a36Sopenharmony_ci info->lba_to_pba[lba] = i; 135162306a36Sopenharmony_ci continue; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci possibly_erase: 135462306a36Sopenharmony_ci if (erase_bad_lba_entries) { 135562306a36Sopenharmony_ci unsigned long address; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci address = (i << (info->pageshift + info->blockshift)); 135862306a36Sopenharmony_ci sddr09_erase(us, address>>1); 135962306a36Sopenharmony_ci info->pba_to_lba[i] = UNDEF; 136062306a36Sopenharmony_ci } else 136162306a36Sopenharmony_ci info->pba_to_lba[i] = UNUSABLE; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci /* 136562306a36Sopenharmony_ci * Approximate capacity. This is not entirely correct yet, 136662306a36Sopenharmony_ci * since a zone with less than 1000 usable pages leads to 136762306a36Sopenharmony_ci * missing LBAs. Especially if it is the last zone, some 136862306a36Sopenharmony_ci * LBAs can be past capacity. 136962306a36Sopenharmony_ci */ 137062306a36Sopenharmony_ci lbact = 0; 137162306a36Sopenharmony_ci for (i = 0; i < numblocks; i += 1024) { 137262306a36Sopenharmony_ci int ct = 0; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci for (j = 0; j < 1024 && i+j < numblocks; j++) { 137562306a36Sopenharmony_ci if (info->pba_to_lba[i+j] != UNUSABLE) { 137662306a36Sopenharmony_ci if (ct >= 1000) 137762306a36Sopenharmony_ci info->pba_to_lba[i+j] = SPARE; 137862306a36Sopenharmony_ci else 137962306a36Sopenharmony_ci ct++; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci lbact += ct; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci info->lbact = lbact; 138562306a36Sopenharmony_ci usb_stor_dbg(us, "Found %d LBA's\n", lbact); 138662306a36Sopenharmony_ci result = 0; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci done: 138962306a36Sopenharmony_ci if (result != 0) { 139062306a36Sopenharmony_ci kfree(info->lba_to_pba); 139162306a36Sopenharmony_ci kfree(info->pba_to_lba); 139262306a36Sopenharmony_ci info->lba_to_pba = NULL; 139362306a36Sopenharmony_ci info->pba_to_lba = NULL; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci kfree(buffer); 139662306a36Sopenharmony_ci return result; 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic void 140062306a36Sopenharmony_cisddr09_card_info_destructor(void *extra) { 140162306a36Sopenharmony_ci struct sddr09_card_info *info = (struct sddr09_card_info *)extra; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (!info) 140462306a36Sopenharmony_ci return; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci kfree(info->lba_to_pba); 140762306a36Sopenharmony_ci kfree(info->pba_to_lba); 140862306a36Sopenharmony_ci} 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_cistatic int 141162306a36Sopenharmony_cisddr09_common_init(struct us_data *us) { 141262306a36Sopenharmony_ci int result; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci /* set the configuration -- STALL is an acceptable response here */ 141562306a36Sopenharmony_ci if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) { 141662306a36Sopenharmony_ci usb_stor_dbg(us, "active config #%d != 1 ??\n", 141762306a36Sopenharmony_ci us->pusb_dev->actconfig->desc.bConfigurationValue); 141862306a36Sopenharmony_ci return -EINVAL; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci result = usb_reset_configuration(us->pusb_dev); 142262306a36Sopenharmony_ci usb_stor_dbg(us, "Result of usb_reset_configuration is %d\n", result); 142362306a36Sopenharmony_ci if (result == -EPIPE) { 142462306a36Sopenharmony_ci usb_stor_dbg(us, "-- stall on control interface\n"); 142562306a36Sopenharmony_ci } else if (result != 0) { 142662306a36Sopenharmony_ci /* it's not a stall, but another error -- time to bail */ 142762306a36Sopenharmony_ci usb_stor_dbg(us, "-- Unknown error. Rejecting device\n"); 142862306a36Sopenharmony_ci return -EINVAL; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO); 143262306a36Sopenharmony_ci if (!us->extra) 143362306a36Sopenharmony_ci return -ENOMEM; 143462306a36Sopenharmony_ci us->extra_destructor = sddr09_card_info_destructor; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci nand_init_ecc(); 143762306a36Sopenharmony_ci return 0; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci/* 144262306a36Sopenharmony_ci * This is needed at a very early stage. If this is not listed in the 144362306a36Sopenharmony_ci * unusual devices list but called from here then LUN 0 of the combo reader 144462306a36Sopenharmony_ci * is not recognized. But I do not know what precisely these calls do. 144562306a36Sopenharmony_ci */ 144662306a36Sopenharmony_cistatic int 144762306a36Sopenharmony_ciusb_stor_sddr09_dpcm_init(struct us_data *us) { 144862306a36Sopenharmony_ci int result; 144962306a36Sopenharmony_ci unsigned char *data = us->iobuf; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci result = sddr09_common_init(us); 145262306a36Sopenharmony_ci if (result) 145362306a36Sopenharmony_ci return result; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); 145662306a36Sopenharmony_ci if (result) { 145762306a36Sopenharmony_ci usb_stor_dbg(us, "send_command fails\n"); 145862306a36Sopenharmony_ci return result; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]); 146262306a36Sopenharmony_ci // get 07 02 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2); 146562306a36Sopenharmony_ci if (result) { 146662306a36Sopenharmony_ci usb_stor_dbg(us, "2nd send_command fails\n"); 146762306a36Sopenharmony_ci return result; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]); 147162306a36Sopenharmony_ci // get 07 00 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci result = sddr09_request_sense(us, data, 18); 147462306a36Sopenharmony_ci if (result == 0 && data[2] != 0) { 147562306a36Sopenharmony_ci int j; 147662306a36Sopenharmony_ci for (j=0; j<18; j++) 147762306a36Sopenharmony_ci printk(" %02X", data[j]); 147862306a36Sopenharmony_ci printk("\n"); 147962306a36Sopenharmony_ci // get 70 00 00 00 00 00 00 * 00 00 00 00 00 00 148062306a36Sopenharmony_ci // 70: current command 148162306a36Sopenharmony_ci // sense key 0, sense code 0, extd sense code 0 148262306a36Sopenharmony_ci // additional transfer length * = sizeof(data) - 7 148362306a36Sopenharmony_ci // Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00 148462306a36Sopenharmony_ci // sense key 06, sense code 28: unit attention, 148562306a36Sopenharmony_ci // not ready to ready transition 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci // test unit ready 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci return 0; /* not result */ 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci/* 149462306a36Sopenharmony_ci * Transport for the Microtech DPCM-USB 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_cistatic int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci int ret; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci usb_stor_dbg(us, "LUN=%d\n", (u8)srb->device->lun); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci switch (srb->device->lun) { 150362306a36Sopenharmony_ci case 0: 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci /* 150662306a36Sopenharmony_ci * LUN 0 corresponds to the CompactFlash card reader. 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_ci ret = usb_stor_CB_transport(srb, us); 150962306a36Sopenharmony_ci break; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci case 1: 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci /* 151462306a36Sopenharmony_ci * LUN 1 corresponds to the SmartMedia card reader. 151562306a36Sopenharmony_ci */ 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci /* 151862306a36Sopenharmony_ci * Set the LUN to 0 (just in case). 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_ci srb->device->lun = 0; 152162306a36Sopenharmony_ci ret = sddr09_transport(srb, us); 152262306a36Sopenharmony_ci srb->device->lun = 1; 152362306a36Sopenharmony_ci break; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci default: 152662306a36Sopenharmony_ci usb_stor_dbg(us, "Invalid LUN %d\n", (u8)srb->device->lun); 152762306a36Sopenharmony_ci ret = USB_STOR_TRANSPORT_ERROR; 152862306a36Sopenharmony_ci break; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci return ret; 153162306a36Sopenharmony_ci} 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci/* 153562306a36Sopenharmony_ci * Transport for the Sandisk SDDR-09 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_cistatic int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci static unsigned char sensekey = 0, sensecode = 0; 154062306a36Sopenharmony_ci static unsigned char havefakesense = 0; 154162306a36Sopenharmony_ci int result, i; 154262306a36Sopenharmony_ci unsigned char *ptr = us->iobuf; 154362306a36Sopenharmony_ci unsigned long capacity; 154462306a36Sopenharmony_ci unsigned int page, pages; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci struct sddr09_card_info *info; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci static unsigned char inquiry_response[8] = { 154962306a36Sopenharmony_ci 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00 155062306a36Sopenharmony_ci }; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci /* note: no block descriptor support */ 155362306a36Sopenharmony_ci static unsigned char mode_page_01[19] = { 155462306a36Sopenharmony_ci 0x00, 0x0F, 0x00, 0x0, 0x0, 0x0, 0x00, 155562306a36Sopenharmony_ci 0x01, 0x0A, 155662306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 155762306a36Sopenharmony_ci }; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci info = (struct sddr09_card_info *)us->extra; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) { 156262306a36Sopenharmony_ci /* for a faked command, we have to follow with a faked sense */ 156362306a36Sopenharmony_ci memset(ptr, 0, 18); 156462306a36Sopenharmony_ci ptr[0] = 0x70; 156562306a36Sopenharmony_ci ptr[2] = sensekey; 156662306a36Sopenharmony_ci ptr[7] = 11; 156762306a36Sopenharmony_ci ptr[12] = sensecode; 156862306a36Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 18, srb); 156962306a36Sopenharmony_ci sensekey = sensecode = havefakesense = 0; 157062306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci havefakesense = 1; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci /* 157662306a36Sopenharmony_ci * Dummy up a response for INQUIRY since SDDR09 doesn't 157762306a36Sopenharmony_ci * respond to INQUIRY commands 157862306a36Sopenharmony_ci */ 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (srb->cmnd[0] == INQUIRY) { 158162306a36Sopenharmony_ci memcpy(ptr, inquiry_response, 8); 158262306a36Sopenharmony_ci fill_inquiry_response(us, ptr, 36); 158362306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci if (srb->cmnd[0] == READ_CAPACITY) { 158762306a36Sopenharmony_ci struct nand_flash_dev *cardinfo; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci sddr09_get_wp(us, info); /* read WP bit */ 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci cardinfo = sddr09_get_cardinfo(us, info->flags); 159262306a36Sopenharmony_ci if (!cardinfo) { 159362306a36Sopenharmony_ci /* probably no media */ 159462306a36Sopenharmony_ci init_error: 159562306a36Sopenharmony_ci sensekey = 0x02; /* not ready */ 159662306a36Sopenharmony_ci sensecode = 0x3a; /* medium not present */ 159762306a36Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci info->capacity = (1 << cardinfo->chipshift); 160162306a36Sopenharmony_ci info->pageshift = cardinfo->pageshift; 160262306a36Sopenharmony_ci info->pagesize = (1 << info->pageshift); 160362306a36Sopenharmony_ci info->blockshift = cardinfo->blockshift; 160462306a36Sopenharmony_ci info->blocksize = (1 << info->blockshift); 160562306a36Sopenharmony_ci info->blockmask = info->blocksize - 1; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci // map initialization, must follow get_cardinfo() 160862306a36Sopenharmony_ci if (sddr09_read_map(us)) { 160962306a36Sopenharmony_ci /* probably out of memory */ 161062306a36Sopenharmony_ci goto init_error; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci // Report capacity 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci capacity = (info->lbact << info->blockshift) - 1; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci ((__be32 *) ptr)[0] = cpu_to_be32(capacity); 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci // Report page size 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci ((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize); 162262306a36Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 8, srb); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (srb->cmnd[0] == MODE_SENSE_10) { 162862306a36Sopenharmony_ci int modepage = (srb->cmnd[2] & 0x3F); 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci /* 163162306a36Sopenharmony_ci * They ask for the Read/Write error recovery page, 163262306a36Sopenharmony_ci * or for all pages. 163362306a36Sopenharmony_ci */ 163462306a36Sopenharmony_ci /* %% We should check DBD %% */ 163562306a36Sopenharmony_ci if (modepage == 0x01 || modepage == 0x3F) { 163662306a36Sopenharmony_ci usb_stor_dbg(us, "Dummy up request for mode page 0x%x\n", 163762306a36Sopenharmony_ci modepage); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci memcpy(ptr, mode_page_01, sizeof(mode_page_01)); 164062306a36Sopenharmony_ci ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); 164162306a36Sopenharmony_ci ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0; 164262306a36Sopenharmony_ci usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); 164362306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci sensekey = 0x05; /* illegal request */ 164762306a36Sopenharmony_ci sensecode = 0x24; /* invalid field in CDB */ 164862306a36Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) 165262306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci havefakesense = 0; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci if (srb->cmnd[0] == READ_10) { 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci page = short_pack(srb->cmnd[3], srb->cmnd[2]); 165962306a36Sopenharmony_ci page <<= 16; 166062306a36Sopenharmony_ci page |= short_pack(srb->cmnd[5], srb->cmnd[4]); 166162306a36Sopenharmony_ci pages = short_pack(srb->cmnd[8], srb->cmnd[7]); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci usb_stor_dbg(us, "READ_10: read page %d pagect %d\n", 166462306a36Sopenharmony_ci page, pages); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci result = sddr09_read_data(us, page, pages); 166762306a36Sopenharmony_ci return (result == 0 ? USB_STOR_TRANSPORT_GOOD : 166862306a36Sopenharmony_ci USB_STOR_TRANSPORT_ERROR); 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci if (srb->cmnd[0] == WRITE_10) { 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci page = short_pack(srb->cmnd[3], srb->cmnd[2]); 167462306a36Sopenharmony_ci page <<= 16; 167562306a36Sopenharmony_ci page |= short_pack(srb->cmnd[5], srb->cmnd[4]); 167662306a36Sopenharmony_ci pages = short_pack(srb->cmnd[8], srb->cmnd[7]); 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci usb_stor_dbg(us, "WRITE_10: write page %d pagect %d\n", 167962306a36Sopenharmony_ci page, pages); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci result = sddr09_write_data(us, page, pages); 168262306a36Sopenharmony_ci return (result == 0 ? USB_STOR_TRANSPORT_GOOD : 168362306a36Sopenharmony_ci USB_STOR_TRANSPORT_ERROR); 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci /* 168762306a36Sopenharmony_ci * catch-all for all other commands, except 168862306a36Sopenharmony_ci * pass TEST_UNIT_READY and REQUEST_SENSE through 168962306a36Sopenharmony_ci */ 169062306a36Sopenharmony_ci if (srb->cmnd[0] != TEST_UNIT_READY && 169162306a36Sopenharmony_ci srb->cmnd[0] != REQUEST_SENSE) { 169262306a36Sopenharmony_ci sensekey = 0x05; /* illegal request */ 169362306a36Sopenharmony_ci sensecode = 0x20; /* invalid command */ 169462306a36Sopenharmony_ci havefakesense = 1; 169562306a36Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci for (; srb->cmd_len<12; srb->cmd_len++) 169962306a36Sopenharmony_ci srb->cmnd[srb->cmd_len] = 0; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci srb->cmnd[1] = LUNBITS; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci ptr[0] = 0; 170462306a36Sopenharmony_ci for (i=0; i<12; i++) 170562306a36Sopenharmony_ci sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci usb_stor_dbg(us, "Send control for command %s\n", ptr); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci result = sddr09_send_scsi_command(us, srb->cmnd, 12); 171062306a36Sopenharmony_ci if (result) { 171162306a36Sopenharmony_ci usb_stor_dbg(us, "sddr09_send_scsi_command returns %d\n", 171262306a36Sopenharmony_ci result); 171362306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci if (scsi_bufflen(srb) == 0) 171762306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if (srb->sc_data_direction == DMA_TO_DEVICE || 172062306a36Sopenharmony_ci srb->sc_data_direction == DMA_FROM_DEVICE) { 172162306a36Sopenharmony_ci unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) 172262306a36Sopenharmony_ci ? us->send_bulk_pipe : us->recv_bulk_pipe; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci usb_stor_dbg(us, "%s %d bytes\n", 172562306a36Sopenharmony_ci (srb->sc_data_direction == DMA_TO_DEVICE) ? 172662306a36Sopenharmony_ci "sending" : "receiving", 172762306a36Sopenharmony_ci scsi_bufflen(srb)); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci result = usb_stor_bulk_srb(us, pipe, srb); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci return (result == USB_STOR_XFER_GOOD ? 173262306a36Sopenharmony_ci USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci/* 173962306a36Sopenharmony_ci * Initialization routine for the sddr09 subdriver 174062306a36Sopenharmony_ci */ 174162306a36Sopenharmony_cistatic int 174262306a36Sopenharmony_ciusb_stor_sddr09_init(struct us_data *us) { 174362306a36Sopenharmony_ci return sddr09_common_init(us); 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_cistatic struct scsi_host_template sddr09_host_template; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_cistatic int sddr09_probe(struct usb_interface *intf, 174962306a36Sopenharmony_ci const struct usb_device_id *id) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci struct us_data *us; 175262306a36Sopenharmony_ci int result; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 175562306a36Sopenharmony_ci (id - sddr09_usb_ids) + sddr09_unusual_dev_list, 175662306a36Sopenharmony_ci &sddr09_host_template); 175762306a36Sopenharmony_ci if (result) 175862306a36Sopenharmony_ci return result; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci if (us->protocol == USB_PR_DPCM_USB) { 176162306a36Sopenharmony_ci us->transport_name = "Control/Bulk-EUSB/SDDR09"; 176262306a36Sopenharmony_ci us->transport = dpcm_transport; 176362306a36Sopenharmony_ci us->transport_reset = usb_stor_CB_reset; 176462306a36Sopenharmony_ci us->max_lun = 1; 176562306a36Sopenharmony_ci } else { 176662306a36Sopenharmony_ci us->transport_name = "EUSB/SDDR09"; 176762306a36Sopenharmony_ci us->transport = sddr09_transport; 176862306a36Sopenharmony_ci us->transport_reset = usb_stor_CB_reset; 176962306a36Sopenharmony_ci us->max_lun = 0; 177062306a36Sopenharmony_ci } 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci result = usb_stor_probe2(us); 177362306a36Sopenharmony_ci return result; 177462306a36Sopenharmony_ci} 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_cistatic struct usb_driver sddr09_driver = { 177762306a36Sopenharmony_ci .name = DRV_NAME, 177862306a36Sopenharmony_ci .probe = sddr09_probe, 177962306a36Sopenharmony_ci .disconnect = usb_stor_disconnect, 178062306a36Sopenharmony_ci .suspend = usb_stor_suspend, 178162306a36Sopenharmony_ci .resume = usb_stor_resume, 178262306a36Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 178362306a36Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 178462306a36Sopenharmony_ci .post_reset = usb_stor_post_reset, 178562306a36Sopenharmony_ci .id_table = sddr09_usb_ids, 178662306a36Sopenharmony_ci .soft_unbind = 1, 178762306a36Sopenharmony_ci .no_dynamic_id = 1, 178862306a36Sopenharmony_ci}; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_cimodule_usb_stor_driver(sddr09_driver, sddr09_host_template, DRV_NAME); 1791