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