11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Driver for SanDisk SDDR-09 SmartMedia reader
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (c) 2002 Andries Brouwer (aeb@cwi.nl)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Developed with the assistance of:
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (c) 2002 Alan Stern <stern@rowland.org>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This chip is a programmable USB controller. In the SDDR-09, it has
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * been programmed to obey a certain limited set of SCSI commands.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver translates the "real" SCSI commands to the SDDR-09 SCSI
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * commands.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2, or (at your option) any
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * later version.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc.,
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 675 Mass Ave, Cambridge, MA 02139, USA.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Known vendor commands: 12 bytes, first byte is opcode
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * E7: read scatter gather
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * E8: read
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * E9: write
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EA: erase
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EB: reset
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EC: read status
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ED: read ID
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EE: write CIS (?)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EF: compute checksum (?)
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
440ff71883b2d60136430458413c135d545c69b0c4Alan Stern#include <linux/module.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h>
49c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern#include <scsi/scsi_device.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "usb.h"
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "transport.h"
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "protocol.h"
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "debug.h"
550ff71883b2d60136430458413c135d545c69b0c4Alan Stern
564246b06a33ebdd6593dccaab3aa01eb0c9f8c1c8Maciej GrelaMODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader");
574246b06a33ebdd6593dccaab3aa01eb0c9f8c1c8Maciej GrelaMODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>");
584246b06a33ebdd6593dccaab3aa01eb0c9f8c1c8Maciej GrelaMODULE_LICENSE("GPL");
590ff71883b2d60136430458413c135d545c69b0c4Alan Stern
600ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int usb_stor_sddr09_dpcm_init(struct us_data *us);
610ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
620ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int usb_stor_sddr09_init(struct us_data *us);
630ff71883b2d60136430458413c135d545c69b0c4Alan Stern
640ff71883b2d60136430458413c135d545c69b0c4Alan Stern
650ff71883b2d60136430458413c135d545c69b0c4Alan Stern/*
660ff71883b2d60136430458413c135d545c69b0c4Alan Stern * The table of devices
670ff71883b2d60136430458413c135d545c69b0c4Alan Stern */
680ff71883b2d60136430458413c135d545c69b0c4Alan Stern#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
690ff71883b2d60136430458413c135d545c69b0c4Alan Stern		    vendorName, productName, useProtocol, useTransport, \
700ff71883b2d60136430458413c135d545c69b0c4Alan Stern		    initFunction, flags) \
710ff71883b2d60136430458413c135d545c69b0c4Alan Stern{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
720ff71883b2d60136430458413c135d545c69b0c4Alan Stern  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
730ff71883b2d60136430458413c135d545c69b0c4Alan Stern
746f871f9e30504a86f37d074e45a2aa722d7aed53Felipe Balbistatic struct usb_device_id sddr09_usb_ids[] = {
750ff71883b2d60136430458413c135d545c69b0c4Alan Stern#	include "unusual_sddr09.h"
760ff71883b2d60136430458413c135d545c69b0c4Alan Stern	{ }		/* Terminating entry */
770ff71883b2d60136430458413c135d545c69b0c4Alan Stern};
780ff71883b2d60136430458413c135d545c69b0c4Alan SternMODULE_DEVICE_TABLE(usb, sddr09_usb_ids);
790ff71883b2d60136430458413c135d545c69b0c4Alan Stern
800ff71883b2d60136430458413c135d545c69b0c4Alan Stern#undef UNUSUAL_DEV
810ff71883b2d60136430458413c135d545c69b0c4Alan Stern
820ff71883b2d60136430458413c135d545c69b0c4Alan Stern/*
830ff71883b2d60136430458413c135d545c69b0c4Alan Stern * The flags table
840ff71883b2d60136430458413c135d545c69b0c4Alan Stern */
850ff71883b2d60136430458413c135d545c69b0c4Alan Stern#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
860ff71883b2d60136430458413c135d545c69b0c4Alan Stern		    vendor_name, product_name, use_protocol, use_transport, \
870ff71883b2d60136430458413c135d545c69b0c4Alan Stern		    init_function, Flags) \
880ff71883b2d60136430458413c135d545c69b0c4Alan Stern{ \
890ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.vendorName = vendor_name,	\
900ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.productName = product_name,	\
910ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.useProtocol = use_protocol,	\
920ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.useTransport = use_transport,	\
930ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.initFunction = init_function,	\
940ff71883b2d60136430458413c135d545c69b0c4Alan Stern}
950ff71883b2d60136430458413c135d545c69b0c4Alan Stern
960ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic struct us_unusual_dev sddr09_unusual_dev_list[] = {
970ff71883b2d60136430458413c135d545c69b0c4Alan Stern#	include "unusual_sddr09.h"
980ff71883b2d60136430458413c135d545c69b0c4Alan Stern	{ }		/* Terminating entry */
990ff71883b2d60136430458413c135d545c69b0c4Alan Stern};
1000ff71883b2d60136430458413c135d545c69b0c4Alan Stern
1010ff71883b2d60136430458413c135d545c69b0c4Alan Stern#undef UNUSUAL_DEV
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LSB_of(s) ((s)&0xFF)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MSB_of(s) ((s)>>8)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* #define US_DEBUGP printk */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First some stuff that does not belong here:
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data on SmartMedia and other cards, completely
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unrelated to this driver.
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Similar stuff occurs in <linux/mtd/nand_ids.h>.
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct nand_flash_dev {
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int model_id;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chipshift;		/* 1<<cs bytes total capacity */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char pageshift;		/* 1<<ps bytes in a page */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char blockshift;	/* 1<<bs pages in an erase block */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char zoneshift;		/* 1<<zs blocks in a zone */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* # of logical blocks is 125/128 of this */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char pageadrlen;	/* length of an address in bytes - 1 */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NAND Flash Manufacturer ID Codes
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NAND_MFR_AMD		0x01
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NAND_MFR_NATSEMI	0x8f
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NAND_MFR_TOSHIBA	0x98
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NAND_MFR_SAMSUNG	0xec
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline char *nand_flash_manufacturer(int manuf_id) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(manuf_id) {
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NAND_MFR_AMD:
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return "AMD";
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NAND_MFR_NATSEMI:
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return "NATSEMI";
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NAND_MFR_TOSHIBA:
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return "Toshiba";
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case NAND_MFR_SAMSUNG:
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return "Samsung";
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return "unknown";
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It looks like it is unnecessary to attach manufacturer to the
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * remaining data: SSFDC prescribes manufacturer-independent id codes.
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 256 MB NAND flash has a 5-byte ID with 2nd byte 0xaa, 0xba, 0xca or 0xda.
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_flash_dev nand_flash_ids[] = {
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NAND flash */
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x6e, 20, 8, 4, 8, 2},	/* 1 MB */
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xe8, 20, 8, 4, 8, 2},	/* 1 MB */
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xec, 20, 8, 4, 8, 2},	/* 1 MB */
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x64, 21, 8, 4, 9, 2}, 	/* 2 MB */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xea, 21, 8, 4, 9, 2},	/* 2 MB */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x6b, 22, 9, 4, 9, 2},	/* 4 MB */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xe3, 22, 9, 4, 9, 2},	/* 4 MB */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xe5, 22, 9, 4, 9, 2},	/* 4 MB */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xe6, 23, 9, 4, 10, 2},	/* 8 MB */
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x73, 24, 9, 5, 10, 2},	/* 16 MB */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x75, 25, 9, 5, 10, 2},	/* 32 MB */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x76, 26, 9, 5, 10, 3},	/* 64 MB */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x79, 27, 9, 5, 10, 3},	/* 128 MB */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* MASK ROM */
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x5d, 21, 9, 4, 8, 2},	/* 2 MB */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xd5, 22, 9, 4, 9, 2},	/* 4 MB */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xd6, 23, 9, 4, 10, 2},	/* 8 MB */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x57, 24, 9, 4, 11, 2},	/* 16 MB */
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x58, 25, 9, 4, 12, 2},	/* 32 MB */
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0,}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_flash_dev *
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnand_find_id(unsigned char id) {
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18652950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser	for (i = 0; i < ARRAY_SIZE(nand_flash_ids); i++)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (nand_flash_ids[i].model_id == id)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return &(nand_flash_ids[i]);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ECC computation.
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char parity[256];
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char ecc2[256];
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nand_init_ecc(void) {
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, a;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	parity[0] = 0;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < 256; i++)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parity[i] = (parity[i&(i-1)] ^ 1);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 256; i++) {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		a = 0;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < 8; j++) {
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (i & (1<<j)) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((j & 1) == 0)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					a ^= 0x04;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((j & 2) == 0)
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					a ^= 0x10;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((j & 4) == 0)
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					a ^= 0x40;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0));
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* compute 3-byte ecc on 256 bytes */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, a;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char par, bit, bits[8];
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	par = 0;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = 0; j < 8; j++)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bits[j] = 0;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* collect 16 checksum bits */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 256; i++) {
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		par ^= data[i];
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bit = parity[data[i]];
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < 8; j++)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((i & (1<<j)) == 0)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				bits[j] ^= bit;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* put 4+4+4 = 12 bits in the ecc */
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ecc[2] = ecc2[par];
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nand_compare_ecc(unsigned char *data, unsigned char *ecc) {
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(data, ecc, 3);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The actual driver starts here.
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharmstruct sddr09_card_info {
262f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	unsigned long	capacity;	/* Size of card in bytes */
263f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		pagesize;	/* Size of page in bytes */
264f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		pageshift;	/* log2 of pagesize */
265f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		blocksize;	/* Size of block in pages */
266f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		blockshift;	/* log2 of blocksize */
267f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		blockmask;	/* 2^blockshift - 1 */
268f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		*lba_to_pba;	/* logical to physical map */
269f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		*pba_to_lba;	/* physical to logical map */
270f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		lbact;		/* number of available pages */
271f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int		flags;
272f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm#define	SDDR09_WP	1		/* write protected */
273f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm};
274f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On my 16MB card, control blocks have size 64 (16 real control bytes,
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and 48 junk bytes). In reality of course the card uses 16 control bytes,
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so the reader makes up the remaining 48. Don't know whether these numbers
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * depend on the card. For now a constant.
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_SHIFT 6
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On my Combo CF/SM reader, the SM reader has LUN 1.
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (and things fail with LUN 0).
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It seems LUN is irrelevant for others.
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LUN	1
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LUNBITS	(LUN << 5)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LBA and PBA are unsigned ints. Special values.
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UNDEF    0xffffffff
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SPARE    0xfffffffe
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UNUSABLE 0xfffffffd
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2984c4c9432a6c916729c7296c47fe93b053a73e20cArjan van de Venstatic const int erase_bad_lba_entries = 0;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* send vendor interface command (0x41) */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* called for requests 0, 1, 8 */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_send_command(struct us_data *us,
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    unsigned char request,
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    unsigned char direction,
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    unsigned char *xfer_data,
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    unsigned int xfer_len) {
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pipe;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char requesttype = (0x41 | direction);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Get the receive or send control pipe number
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (direction == USB_DIR_IN)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pipe = us->recv_ctrl_pipe;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pipe = us->send_ctrl_pipe;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype,
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   0, 0, xfer_data, xfer_len);
3210dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	switch (rc) {
3220dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		case USB_STOR_XFER_GOOD:	return 0;
3230dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		case USB_STOR_XFER_STALLED:	return -EPIPE;
3240dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		default:			return -EIO;
3250dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	}
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_send_scsi_command(struct us_data *us,
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned char *command,
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned int command_len) {
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_send_command(us, 0, USB_DIR_OUT, command, command_len);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Test Unit Ready Command: 12 bytes.
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: 00
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_test_unit_ready(struct us_data *us) {
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(command, 0, 6);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 6);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("sddr09_test_unit_ready returns %d\n", result);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Request Sense Command: 12 bytes.
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: 03
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 4: data length
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(command, 0, 12);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0x03;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4] = buflen;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 12);
3720dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result)
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sensebuf, buflen, NULL);
3770dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Command: 12 bytes.
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: E8
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 1: last two bits: 00: read data, 01: read blockwise control,
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			10: read both, 11: read pagewise control.
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 It turns out we need values 20, 21, 22, 23 here (LUN 1).
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 2-5: address (interpretation depends on byte 1, see below)
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 10-11: count (idem)
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A page has 512 data bytes and 64 control bytes (16 control and 48 junk).
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A read data command gets data in 512-byte pages.
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A read control command gets control in 64-byte chunks.
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A read both command gets data+control in 576-byte chunks.
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Blocks are groups of 32 pages, and read blockwise control jumps to the
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * next block, while read pagewise control jumps to the next page after
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reading a group of 64 control bytes.
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * [Here 512 = 1<<pageshift, 32 = 1<<blockshift, 64 is constant?]
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (1 MB and 2 MB cards are a bit different, but I have only a 16 MB card.)
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     int nr_of_pages, int bulklen, unsigned char *buf,
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     int use_sg) {
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0xE8;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS | x;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[2] = MSB_of(fromaddress>>16);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[3] = LSB_of(fromaddress>>16);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4] = MSB_of(fromaddress & 0xFFFF);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[5] = LSB_of(fromaddress & 0xFFFF);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[6] = 0;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[7] = 0;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[8] = 0;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[9] = 0;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[10] = MSB_of(nr_of_pages);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[11] = LSB_of(nr_of_pages);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 12);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4250dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result for send_control in sddr09_read2%d %d\n",
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  x, result);
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       buf, bulklen, use_sg, NULL);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result != USB_STOR_XFER_GOOD) {
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n",
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  x, result);
4370dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return -EIO;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4390dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	return 0;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Data
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fromaddress counts data shorts:
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * increasing it by 256 shifts the bytestream by 512 bytes;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the last 8 bits are ignored.
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nr_of_pages counts pages of size (1 << pageshift).
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read20(struct us_data *us, unsigned long fromaddress,
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bulklen = nr_of_pages << pageshift;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The last 8 bits of fromaddress are ignored. */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_readX(us, 0, fromaddress, nr_of_pages, bulklen,
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    buf, use_sg);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Blockwise Control
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fromaddress gives the starting position (as in read data;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the last 8 bits are ignored); increasing it by 32*256 shifts
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the output stream by 64 bytes.
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * count counts control groups of size (1 << controlshift).
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For me, controlshift = 6. Is this constant?
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After getting one control group, jump to the next block
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (fromaddress += 8192).
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read21(struct us_data *us, unsigned long fromaddress,
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      int count, int controlshift, unsigned char *buf, int use_sg) {
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bulklen = (count << controlshift);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_readX(us, 1, fromaddress, count, bulklen,
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    buf, use_sg);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read both Data and Control
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fromaddress counts data shorts, ignoring control:
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * increasing it by 256 shifts the bytestream by 576 = 512+64 bytes;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the last 8 bits are ignored.
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift).
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read22(struct us_data *us, unsigned long fromaddress,
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n",
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  nr_of_pages, bulklen);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen,
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    buf, use_sg);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Pagewise Control
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fromaddress gives the starting position (as in read data;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the last 8 bits are ignored); increasing it by 256 shifts
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the output stream by 64 bytes.
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * count counts control groups of size (1 << controlshift).
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For me, controlshift = 6. Is this constant?
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After getting one control group, jump to the next page
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (fromaddress += 256).
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read23(struct us_data *us, unsigned long fromaddress,
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      int count, int controlshift, unsigned char *buf, int use_sg) {
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bulklen = (count << controlshift);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_readX(us, 3, fromaddress, count, bulklen,
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    buf, use_sg);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Erase Command: 12 bytes.
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: EA
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored.
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The byte address being erased is 2*Eaddress.
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The CIS cannot be erased.
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_erase(struct us_data *us, unsigned long Eaddress) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(command, 0, 12);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0xEA;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[6] = MSB_of(Eaddress>>16);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[7] = LSB_of(Eaddress>>16);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[8] = MSB_of(Eaddress & 0xFFFF);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[9] = LSB_of(Eaddress & 0xFFFF);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 12);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5530dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result for send_control in sddr09_erase %d\n",
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  result);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write CIS Command: 12 bytes.
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: EE
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 2-5: write address in shorts
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 10-11: sector count
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This writes at the indicated address. Don't know how it differs
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from E9. Maybe it does not erase? However, it will also write to
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the CIS.
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When two such commands on the same page follow each other directly,
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the second one is not done.
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write Command: 12 bytes.
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: E9
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 2-5: write address (big-endian, counting shorts, sector aligned).
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 10-11: sector count (big-endian, in 512-byte sectors).
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If write address equals erase address, the erase is done first,
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * otherwise the write is done first. When erase address equals zero
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no erase is done?
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_writeX(struct us_data *us,
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      unsigned long Waddress, unsigned long Eaddress,
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) {
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0xE9;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[2] = MSB_of(Waddress>>16);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[3] = LSB_of(Waddress>>16);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4] = MSB_of(Waddress & 0xFFFF);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[5] = LSB_of(Waddress & 0xFFFF);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[6] = MSB_of(Eaddress>>16);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[7] = LSB_of(Eaddress>>16);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[8] = MSB_of(Eaddress & 0xFFFF);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[9] = LSB_of(Eaddress & 0xFFFF);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[10] = MSB_of(nr_of_pages);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[11] = LSB_of(nr_of_pages);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 12);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6110dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result for send_control in sddr09_writeX %d\n",
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  result);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       buf, bulklen, use_sg, NULL);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result != USB_STOR_XFER_GOOD) {
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n",
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  result);
6230dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return -EIO;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6250dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	return 0;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* erase address, write same address */
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_write_inplace(struct us_data *us, unsigned long address,
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     int nr_of_pages, int pageshift, unsigned char *buf,
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     int use_sg) {
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_writeX(us, address, address, nr_of_pages, bulklen,
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     buf, use_sg);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Scatter Gather Command: 3+4n bytes.
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode E7
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 2: n
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bytes 4i-1,4i,4i+1: page address
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 4i+2: page count
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (i=1..n)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This reads several pages from the card to a single memory buffer.
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The last two bits of byte 1 have the same meaning as for E8.
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read_sg_test_only(struct us_data *us) {
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result, bulklen, nsg, ct;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buf;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long address;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsg = bulklen = 0;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0xE7;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[2] = 0;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	address = 040000; ct = 1;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsg++;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bulklen += (ct << 9);
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+2] = ct;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+1] = ((address >> 9) & 0xFF);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+0] = ((address >> 17) & 0xFF);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg-1] = ((address >> 25) & 0xFF);
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	address = 0340000; ct = 1;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsg++;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bulklen += (ct << 9);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+2] = ct;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+1] = ((address >> 9) & 0xFF);
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+0] = ((address >> 17) & 0xFF);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg-1] = ((address >> 25) & 0xFF);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	address = 01000000; ct = 2;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nsg++;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bulklen += (ct << 9);
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+2] = ct;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+1] = ((address >> 9) & 0xFF);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg+0] = ((address >> 17) & 0xFF);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[4*nsg-1] = ((address >> 25) & 0xFF);
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[2] = nsg;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 4*nsg+3);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6890dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result for send_control in sddr09_read_sg %d\n",
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  result);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6955cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	buf = kmalloc(bulklen, GFP_NOIO);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buf)
6970dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return -ENOMEM;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       buf, bulklen, NULL);
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buf);
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result != USB_STOR_XFER_GOOD) {
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n",
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  result);
7050dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return -EIO;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7080dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	return 0;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Status Command: 12 bytes.
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: EC
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 64 bytes, all zero except for the first.
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 0: 1: Error
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 5: 1: Suspended
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 6: 1: Ready
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit 7: 1: Not write-protected
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read_status(struct us_data *us, unsigned char *status) {
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = us->iobuf;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("Reading status...\n");
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(command, 0, 12);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0xEC;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 12);
7370dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result)
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       data, 64, NULL);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*status = data[0];
7430dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read_data(struct us_data *us,
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 unsigned long address,
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 unsigned int sectors) {
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buffer;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int lba, maxlba, pba;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int page, pages;
7551f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	unsigned int len, offset;
7561f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	struct scatterlist *sg;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
759a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	// Figure out the initial LBA and page
760a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	lba = address >> info->blockshift;
761a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	page = (address & info->blockmask);
762a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	maxlba = info->capacity >> (info->pageshift + info->blockshift);
763a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	if (lba >= maxlba)
764a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm		return -EIO;
765a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Since we only read in one block at a time, we have to create
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// a bounce buffer and move the data a piece at a time between the
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// bounce buffer and the actual transfer buffer.
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer = kmalloc(len, GFP_NOIO);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buffer == NULL) {
7736f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09_read_data: Out of memory\n");
7740dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return -ENOMEM;
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// This could be made much more efficient by checking for
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// contiguous LBA's. Another exercise left to the student.
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7800dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	result = 0;
7811f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	offset = 0;
7821f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	sg = NULL;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (sectors > 0) {
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Find number of pages we can read in this block */
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pages = min(sectors, info->blocksize - page);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = pages << info->pageshift;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Not overflowing capacity? */
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lba >= maxlba) {
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("Error: Requested lba %u exceeds "
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  "maximum %u\n", lba, maxlba);
7940dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm			result = -EIO;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Find where this lba lives on disk */
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pba = info->lba_to_pba[lba];
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pba == UNDEF) {	/* this lba was never written */
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("Read %d zero pages (LBA %d) page %d\n",
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  pages, lba, page);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* This is not really an error. It just means
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   that the block has never been written.
8080dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm			   Instead of returning an error
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   it is better to return all zero data. */
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memset(buffer, 0, len);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("Read %d pages, from PBA %d"
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  " (LBA %d) page %d\n",
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  pages, pba, lba, page);
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address = ((pba << info->blockshift) + page) <<
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				info->pageshift;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = sddr09_read20(us, address>>1,
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					pages, info->pageshift, buffer, 0);
8230dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm			if (result)
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Store the data in the transfer buffer
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_stor_access_xfer_buf(buffer, len, us->srb,
8291f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe				&sg, &offset, TO_XFER_BUF);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page = 0;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lba++;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sectors -= pages;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buffer);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) {
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned int lastpba = 1;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int zonestart, end, i;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	zonestart = (lba/1000) << 10;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = info->capacity >> (info->blockshift + info->pageshift);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end -= zonestart;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (end > 1024)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		end = 1024;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = lastpba+1; i < end; i++) {
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (info->pba_to_lba[zonestart+i] == UNDEF) {
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lastpba = i;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return zonestart+i;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i <= lastpba; i++) {
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (info->pba_to_lba[zonestart+i] == UNDEF) {
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lastpba = i;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return zonestart+i;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_write_lba(struct us_data *us, unsigned int lba,
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 unsigned int page, unsigned int pages,
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 unsigned char *ptr, unsigned char *blockbuffer) {
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long address;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pba, lbap;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pagelen;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *bptr, *cptr, *xptr;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char ecc[3];
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, result, isnew;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lbap = ((lba % 1000) << 1) | 0x1000;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lbap ^= 1;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pba = info->lba_to_pba[lba];
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	isnew = 0;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pba == UNDEF) {
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pba = sddr09_find_unused_pba(info, lba);
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!pba) {
8886f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			printk(KERN_WARNING
8896f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			       "sddr09_write_lba: Out of unused blocks\n");
8900dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm			return -ENOSPC;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->pba_to_lba[pba] = lba;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->lba_to_pba[lba] = pba;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isnew = 1;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pba == 1) {
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Maybe it is impossible to write to PBA 1.
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Fake success, but don't do anything. */
9006f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09: avoid writing to pba 1\n");
9010dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return 0;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* read old contents */
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	address = (pba << (info->pageshift + info->blockshift));
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_read22(us, address>>1, info->blocksize,
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       info->pageshift, blockbuffer, 0);
9100dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result)
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check old contents and fill lba */
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < info->blocksize; i++) {
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bptr = blockbuffer + i*pagelen;
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cptr = bptr + info->pagesize;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nand_compute_ecc(bptr, ecc);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!nand_compare_ecc(cptr+13, ecc)) {
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n",
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  i, pba);
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nand_store_ecc(cptr+13, ecc);
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!nand_compare_ecc(cptr+8, ecc)) {
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n",
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  i, pba);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nand_store_ecc(cptr+8, ecc);
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cptr[6] = cptr[11] = MSB_of(lbap);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cptr[7] = cptr[12] = LSB_of(lbap);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* copy in new stuff and compute ECC */
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xptr = ptr;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = page; i < page+pages; i++) {
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bptr = blockbuffer + i*pagelen;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cptr = bptr + info->pagesize;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(bptr, xptr, info->pagesize);
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xptr += info->pagesize;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nand_compute_ecc(bptr, ecc);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nand_store_ecc(cptr+13, ecc);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nand_store_ecc(cptr+8, ecc);
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba);
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_write_inplace(us, address>>1, info->blocksize,
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      info->pageshift, blockbuffer, 0);
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("sddr09_write_inplace returns %d\n", result);
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned char status = 0;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int result2 = sddr09_read_status(us, &status);
9570dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		if (result2)
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("sddr09_write_inplace: cannot read status\n");
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (status != 0xc0)
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  status);
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int result2 = sddr09_test_unit_ready(us);
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_write_data(struct us_data *us,
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  unsigned long address,
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  unsigned int sectors) {
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
980a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	unsigned int lba, maxlba, page, pages;
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pagelen, blocklen;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *blockbuffer;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buffer;
9841f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	unsigned int len, offset;
9851f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	struct scatterlist *sg;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
988a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	// Figure out the initial LBA and page
989a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	lba = address >> info->blockshift;
990a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	page = (address & info->blockmask);
991a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	maxlba = info->capacity >> (info->pageshift + info->blockshift);
992a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm	if (lba >= maxlba)
993a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm		return -EIO;
994a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// blockbuffer is used for reading in the old data, overwriting
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// with the new data, and performing ECC calculations
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TODO: instead of doing kmalloc/kfree for each write,
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   add a bufferpointer to the info structure */
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	blocklen = (pagelen << info->blockshift);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	blockbuffer = kmalloc(blocklen, GFP_NOIO);
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!blockbuffer) {
10056f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09_write_data: Out of memory\n");
10060dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return -ENOMEM;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Since we don't write the user data directly to the device,
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// we have to create a bounce buffer and move the data a piece
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// at a time between the bounce buffer and the actual transfer buffer.
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer = kmalloc(len, GFP_NOIO);
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buffer == NULL) {
10166f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09_write_data: Out of memory\n");
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(blockbuffer);
10180dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return -ENOMEM;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10210dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	result = 0;
10221f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	offset = 0;
10231f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe	sg = NULL;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (sectors > 0) {
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Write as many sectors as possible in this block
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pages = min(sectors, info->blocksize - page);
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = (pages << info->pageshift);
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1032a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm		/* Not overflowing capacity? */
1033a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm		if (lba >= maxlba) {
1034a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm			US_DEBUGP("Error: Requested lba %u exceeds "
1035a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm				  "maximum %u\n", lba, maxlba);
1036a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm			result = -EIO;
1037a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm			break;
1038a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm		}
1039a6c976c6c4628ce0c9277c47e7545956d9d4f441Matthew Dharm
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Get the data from the transfer buffer
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_stor_access_xfer_buf(buffer, len, us->srb,
10421f6f31a03e3aed0854a6aa3ab763c3d3b2ff42ffJens Axboe				&sg, &offset, FROM_XFER_BUF);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = sddr09_write_lba(us, lba, page, pages,
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				buffer, blockbuffer);
10460dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		if (result)
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page = 0;
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lba++;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sectors -= pages;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buffer);
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(blockbuffer);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read_control(struct us_data *us,
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long address,
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int blocks,
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned char *content,
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int use_sg) {
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("Read control address %lu, blocks %d\n",
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address, blocks);
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_read21(us, address, blocks,
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     CONTROL_SHIFT, content, use_sg);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read Device ID Command: 12 bytes.
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: ED
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 2 bytes: Manufacturer ID and Device ID.
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On more recent cards 3 bytes: the third byte is an option code A5
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * signifying that the secret command to read an 128-bit ID is available.
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On still more recent cards 4 bytes: the fourth byte C0 means that
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a second read ID cmd is available.
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *content = us->iobuf;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result, i;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(command, 0, 12);
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0xED;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, command, 12);
10950dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result)
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			content, 64, NULL);
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 4; i++)
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		deviceID[i] = content[i];
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11040dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) {
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char status;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_read_status(us, &status);
11130dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("sddr09_get_wp: read_status fails\n");
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("sddr09_get_wp: status 0x%02X", status);
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((status & 0x80) == 0) {
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->flags |= SDDR09_WP;	/* write protected */
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP(" WP");
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & 0x40)
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP(" Ready");
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & LUNBITS)
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP(" Suspended");
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & 0x1)
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP(" Error");
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("\n");
11290dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	return 0;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset Command: 12 bytes.
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte 0: opcode: EB
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_reset(struct us_data *us) {
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *command = us->iobuf;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(command, 0, 12);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[0] = 0xEB;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	command[1] = LUNBITS;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sddr09_send_scsi_command(us, command, 12);
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct nand_flash_dev *
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nand_flash_dev *cardinfo;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char deviceID[4];
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char blurbtxt[256];
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("Reading capacity...\n");
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_read_deviceID(us, deviceID);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11610dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("Result of read_deviceID is %d\n", result);
11636f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09: could not read card info\n");
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(blurbtxt, "sddr09: Found Flash card, ID = %02X %02X %02X %02X",
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		deviceID[0], deviceID[1], deviceID[2], deviceID[3]);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Byte 0 is the manufacturer */
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(blurbtxt + strlen(blurbtxt),
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		": Manuf. %s",
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nand_flash_manufacturer(deviceID[0]));
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Byte 1 is the device type */
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cardinfo = nand_find_id(deviceID[1]);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cardinfo) {
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* MB or MiB? It is neither. A 16 MB card has
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   17301504 raw bytes, of which 16384000 are
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   usable for user data. */
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(blurbtxt + strlen(blurbtxt),
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			", %d MB", 1<<(cardinfo->chipshift - 20));
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(blurbtxt + strlen(blurbtxt),
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			", type unrecognized");
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Byte 2 is code to signal availability of 128-bit ID */
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (deviceID[2] == 0xa5) {
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(blurbtxt + strlen(blurbtxt),
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			", 128-bit ID");
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Byte 3 announces the availability of another read ID command */
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (deviceID[3] == 0xc0) {
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(blurbtxt + strlen(blurbtxt),
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			", extra cmd");
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flags & SDDR09_WP)
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(blurbtxt + strlen(blurbtxt),
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			", WP");
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12046f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel	printk(KERN_WARNING "%s\n", blurbtxt);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cardinfo;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_read_map(struct us_data *us) {
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int numblocks, alloc_len, alloc_blocks;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, result;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buffer, *buffer_end, *ptr;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int lba, lbact;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info->capacity)
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// size of a block is 1 << (blockshift + pageshift) bytes
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// divide into the total capacity to get the number of blocks
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	numblocks = info->capacity >> (info->blockshift + info->pageshift);
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// read 64 bytes for every block (actually 1 << CONTROL_SHIFT)
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// but only use a 64 KB buffer
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// buffer size used must be a multiple of (1 << CONTROL_SHIFT)
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SDDR09_READ_MAP_BUFSZ 65536
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT);
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	alloc_len = (alloc_blocks << CONTROL_SHIFT);
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer = kmalloc(alloc_len, GFP_NOIO);
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buffer == NULL) {
12356f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09_read_map: out of memory\n");
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -1;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buffer_end = buffer + alloc_len;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef SDDR09_READ_MAP_BUFSZ
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(info->lba_to_pba);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(info->pba_to_lba);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
12496f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09_read_map: out of memory\n");
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = -1;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < numblocks; i++)
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Define lba-pba translation table
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr = buffer_end;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < numblocks; i++) {
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr += (1 << CONTROL_SHIFT);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ptr >= buffer_end) {
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long address;
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address = i << (info->pageshift + info->blockshift);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			result = sddr09_read_control(
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				us, address>>1,
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				min(alloc_blocks, numblocks - i),
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				buffer, 0);
12720dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm			if (result) {
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				result = -1;
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto done;
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ptr = buffer;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i == 0 || i == 1) {
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->pba_to_lba[i] = UNUSABLE;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* special PBAs have control field 0^16 */
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < 16; j++)
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ptr[j] != 0)
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto nonz;
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->pba_to_lba[i] = UNUSABLE;
12896f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		printk(KERN_WARNING "sddr09: PBA %d has no logical mapping\n",
12906f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel		       i);
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		continue;
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nonz:
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* unwritten PBAs have control field FF^16 */
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < 16; j++)
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ptr[j] != 0xff)
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto nonff;
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		continue;
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nonff:
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* normal PBAs start with six FFs */
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (j < 6) {
13036f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			printk(KERN_WARNING
13046f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			       "sddr09: PBA %d has no logical mapping: "
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "reserved area = %02X%02X%02X%02X "
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "data status %02X block status %02X\n",
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       i, ptr[0], ptr[1], ptr[2], ptr[3],
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       ptr[4], ptr[5]);
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->pba_to_lba[i] = UNUSABLE;
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((ptr[6] >> 4) != 0x01) {
13146f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			printk(KERN_WARNING
13156f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			       "sddr09: PBA %d has invalid address field "
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%02X%02X/%02X%02X\n",
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       i, ptr[6], ptr[7], ptr[11], ptr[12]);
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->pba_to_lba[i] = UNUSABLE;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check even parity */
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (parity[ptr[6] ^ ptr[7]]) {
13246f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			printk(KERN_WARNING
13256f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			       "sddr09: Bad parity in LBA for block %d"
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       " (%02X %02X)\n", i, ptr[6], ptr[7]);
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->pba_to_lba[i] = UNUSABLE;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lba = short_pack(ptr[7], ptr[6]);
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lba = (lba & 0x07FF) >> 1;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Every 1024 physical blocks ("zone"), the LBA numbers
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * go back to zero, but are within a higher block of LBA's.
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Also, there is a maximum of 1000 LBA's per zone.
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * In other words, in PBA 1024-2047 you will find LBA 0-999
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * which are really LBA 1000-1999. This allows for 24 bad
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * or special physical blocks per zone.
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lba >= 1000) {
13446f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			printk(KERN_WARNING
13456f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			       "sddr09: Bad low LBA %d for block %d\n",
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lba, i);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto possibly_erase;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lba += 1000*(i/0x400);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (info->lba_to_pba[lba] != UNDEF) {
13536f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			printk(KERN_WARNING
13546f8aa65b52037123beab573432e371c0f70b7b9aFrank Seidel			       "sddr09: LBA %d seen for PBA %d and %d\n",
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lba, info->lba_to_pba[lba], i);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto possibly_erase;
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->pba_to_lba[i] = lba;
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->lba_to_pba[lba] = i;
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		continue;
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	possibly_erase:
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (erase_bad_lba_entries) {
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long address;
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address = (i << (info->pageshift + info->blockshift));
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sddr09_erase(us, address>>1);
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->pba_to_lba[i] = UNDEF;
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			info->pba_to_lba[i] = UNUSABLE;
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Approximate capacity. This is not entirely correct yet,
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since a zone with less than 1000 usable pages leads to
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * missing LBAs. Especially if it is the last zone, some
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * LBAs can be past capacity.
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lbact = 0;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < numblocks; i += 1024) {
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int ct = 0;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < 1024 && i+j < numblocks; j++) {
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (info->pba_to_lba[i+j] != UNUSABLE) {
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (ct >= 1000)
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					info->pba_to_lba[i+j] = SPARE;
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ct++;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lbact += ct;
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->lbact = lbact;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("Found %d LBA's\n", lbact);
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = 0;
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done:
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (result != 0) {
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(info->lba_to_pba);
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(info->pba_to_lba);
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->lba_to_pba = NULL;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->pba_to_lba = NULL;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buffer);
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssddr09_card_info_destructor(void *extra) {
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info)
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(info->lba_to_pba);
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(info->pba_to_lba);
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1420f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharmstatic int
1421f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharmsddr09_common_init(struct us_data *us) {
1422f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	int result;
1423f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm
1424f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	/* set the configuration -- STALL is an acceptable response here */
1425f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
1426f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
1427f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm				->actconfig->desc.bConfigurationValue);
1428f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		return -EINVAL;
1429f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	}
1430f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm
1431f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	result = usb_reset_configuration(us->pusb_dev);
1432f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	US_DEBUGP("Result of usb_reset_configuration is %d\n", result);
1433f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	if (result == -EPIPE) {
1434f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		US_DEBUGP("-- stall on control interface\n");
1435f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	} else if (result != 0) {
1436f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		/* it's not a stall, but another error -- time to bail */
1437f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		US_DEBUGP("-- Unknown error.  Rejecting device\n");
1438f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		return -EINVAL;
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1440f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm
1441f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
1442f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	if (!us->extra)
1443f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		return -ENOMEM;
1444f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	us->extra_destructor = sddr09_card_info_destructor;
1445f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm
1446f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	nand_init_ecc();
1447f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	return 0;
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1450f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is needed at a very early stage. If this is not listed in the
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unusual devices list but called from here then LUN 0 of the combo reader
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is not recognized. But I do not know what precisely these calls do.
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14560ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int
1457f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharmusb_stor_sddr09_dpcm_init(struct us_data *us) {
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *data = us->iobuf;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	result = sddr09_common_init(us);
1462f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	if (result)
1463f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm		return result;
1464f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
14660dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("sddr09_init: send_command fails\n");
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// get 07 02
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
14750dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("sddr09_init: 2nd send_command fails\n");
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return result;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// get 07 00
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_request_sense(us, data, 18);
14840dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result == 0 && data[2] != 0) {
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int j;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j=0; j<18; j++)
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(" %02X", data[j]);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("\n");
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// get 70 00 00 00 00 00 00 * 00 00 00 00 00 00
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// 70: current command
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// sense key 0, sense code 0, extd sense code 0
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// additional transfer length * = sizeof(data) - 7
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// sense key 06, sense code 28: unit attention,
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// not ready to ready transition
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// test unit ready
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1500f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	return 0;		/* not result */
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1504c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern * Transport for the Microtech DPCM-USB
1505c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern */
15060ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
1507c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern{
1508c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	int ret;
1509c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1510c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
1511c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1512c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	switch (srb->device->lun) {
1513c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	case 0:
1514c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1515c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		/*
1516c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		 * LUN 0 corresponds to the CompactFlash card reader.
1517c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		 */
1518c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		ret = usb_stor_CB_transport(srb, us);
1519c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		break;
1520c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1521c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	case 1:
1522c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1523c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		/*
1524c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		 * LUN 1 corresponds to the SmartMedia card reader.
1525c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		 */
1526c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1527c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		/*
1528c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		 * Set the LUN to 0 (just in case).
1529c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		 */
1530c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		srb->device->lun = 0;
1531c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		ret = sddr09_transport(srb, us);
1532c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		srb->device->lun = 1;
1533c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		break;
1534c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1535c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	default:
1536c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		US_DEBUGP("dpcm_transport: Invalid LUN %d\n",
1537c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern				srb->device->lun);
1538c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		ret = USB_STOR_TRANSPORT_ERROR;
1539c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern		break;
1540c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	}
1541c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern	return ret;
1542c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern}
1543c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1544c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern
1545c20b15fde50c32174af4b48851e5ddadba36330eAlan Stern/*
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transport for the Sandisk SDDR-09
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15480ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned char sensekey = 0, sensecode = 0;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned char havefakesense = 0;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result, i;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *ptr = us->iobuf;
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long capacity;
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int page, pages;
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sddr09_card_info *info;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned char inquiry_response[8] = {
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* note: no block descriptor support */
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned char mode_page_01[19] = {
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		0x00, 0x0F, 0x00, 0x0, 0x0, 0x0, 0x00,
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		0x01, 0x0A,
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info = (struct sddr09_card_info *)us->extra;
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) {
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* for a faked command, we have to follow with a faked sense */
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(ptr, 0, 18);
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr[0] = 0x70;
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr[2] = sensekey;
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr[7] = 11;
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr[12] = sensecode;
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_stor_set_xfer_buf(ptr, 18, srb);
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sensekey = sensecode = havefakesense = 0;
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return USB_STOR_TRANSPORT_GOOD;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	havefakesense = 1;
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Dummy up a response for INQUIRY since SDDR09 doesn't
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   respond to INQUIRY commands */
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] == INQUIRY) {
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(ptr, inquiry_response, 8);
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fill_inquiry_response(us, ptr, 36);
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return USB_STOR_TRANSPORT_GOOD;
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] == READ_CAPACITY) {
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct nand_flash_dev *cardinfo;
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sddr09_get_wp(us, info);	/* read WP bit */
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cardinfo = sddr09_get_cardinfo(us, info->flags);
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!cardinfo) {
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* probably no media */
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_error:
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sensekey = 0x02;	/* not ready */
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sensecode = 0x3a;	/* medium not present */
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return USB_STOR_TRANSPORT_FAILED;
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->capacity = (1 << cardinfo->chipshift);
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->pageshift = cardinfo->pageshift;
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->pagesize = (1 << info->pageshift);
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->blockshift = cardinfo->blockshift;
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->blocksize = (1 << info->blockshift);
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info->blockmask = info->blocksize - 1;
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// map initialization, must follow get_cardinfo()
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sddr09_read_map(us)) {
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* probably out of memory */
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto init_error;
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Report capacity
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		capacity = (info->lbact << info->blockshift) - 1;
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((__be32 *) ptr)[0] = cpu_to_be32(capacity);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Report page size
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize);
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_stor_set_xfer_buf(ptr, 8, srb);
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return USB_STOR_TRANSPORT_GOOD;
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] == MODE_SENSE_10) {
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int modepage = (srb->cmnd[2] & 0x3F);
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* They ask for the Read/Write error recovery page,
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   or for all pages. */
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* %% We should check DBD %% */
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (modepage == 0x01 || modepage == 0x3F) {
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			US_DEBUGP("SDDR09: Dummy up request for "
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  "mode page 0x%x\n", modepage);
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0;
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return USB_STOR_TRANSPORT_GOOD;
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sensekey = 0x05;	/* illegal request */
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sensecode = 0x24;	/* invalid field in CDB */
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return USB_STOR_TRANSPORT_FAILED;
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL)
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return USB_STOR_TRANSPORT_GOOD;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	havefakesense = 0;
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] == READ_10) {
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page <<= 16;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("READ_10: read page %d pagect %d\n",
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  page, pages);
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16730dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		result = sddr09_read_data(us, page, pages);
16740dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
16750dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm				USB_STOR_TRANSPORT_ERROR);
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] == WRITE_10) {
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page <<= 16;
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("WRITE_10: write page %d pagect %d\n",
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  page, pages);
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16880dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		result = sddr09_write_data(us, page, pages);
16890dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
16900dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm				USB_STOR_TRANSPORT_ERROR);
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* catch-all for all other commands, except
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * pass TEST_UNIT_READY and REQUEST_SENSE through
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->cmnd[0] != TEST_UNIT_READY &&
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    srb->cmnd[0] != REQUEST_SENSE) {
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sensekey = 0x05;	/* illegal request */
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sensecode = 0x20;	/* invalid command */
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		havefakesense = 1;
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return USB_STOR_TRANSPORT_FAILED;
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; srb->cmd_len<12; srb->cmd_len++)
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		srb->cmnd[srb->cmd_len] = 0;
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	srb->cmnd[1] = LUNBITS;
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr[0] = 0;
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<12; i++)
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]);
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	US_DEBUGP("SDDR09: Send control for command %s\n", ptr);
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	result = sddr09_send_scsi_command(us, srb->cmnd, 12);
17160dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm	if (result) {
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("sddr09_transport: sddr09_send_scsi_command "
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  "returns %d\n", result);
17190dc08a357538de3d93305fbf99348663abdbf2cdMatthew Dharm		return USB_STOR_TRANSPORT_ERROR;
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
172241c2497b188a641c542328d08a45cf3214d453bdBoaz Harrosh	if (scsi_bufflen(srb) == 0)
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return USB_STOR_TRANSPORT_GOOD;
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srb->sc_data_direction == DMA_TO_DEVICE ||
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    srb->sc_data_direction == DMA_FROM_DEVICE) {
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE)
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				? us->send_bulk_pipe : us->recv_bulk_pipe;
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		US_DEBUGP("SDDR09: %s %d bytes\n",
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  (srb->sc_data_direction == DMA_TO_DEVICE) ?
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  "sending" : "receiving",
173341c2497b188a641c542328d08a45cf3214d453bdBoaz Harrosh			  scsi_bufflen(srb));
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
173541c2497b188a641c542328d08a45cf3214d453bdBoaz Harrosh		result = usb_stor_bulk_srb(us, pipe, srb);
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (result == USB_STOR_XFER_GOOD ?
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return USB_STOR_TRANSPORT_GOOD;
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1744f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm/*
1745f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm * Initialization routine for the sddr09 subdriver
1746f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm */
17470ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int
1748f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharmusb_stor_sddr09_init(struct us_data *us) {
1749f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm	return sddr09_common_init(us);
1750f5b8cb9c91f2f7d54dc3f066db8d4e0f041de79bMatthew Dharm}
17510ff71883b2d60136430458413c135d545c69b0c4Alan Stern
17520ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic int sddr09_probe(struct usb_interface *intf,
17530ff71883b2d60136430458413c135d545c69b0c4Alan Stern			 const struct usb_device_id *id)
17540ff71883b2d60136430458413c135d545c69b0c4Alan Stern{
17550ff71883b2d60136430458413c135d545c69b0c4Alan Stern	struct us_data *us;
17560ff71883b2d60136430458413c135d545c69b0c4Alan Stern	int result;
17570ff71883b2d60136430458413c135d545c69b0c4Alan Stern
17580ff71883b2d60136430458413c135d545c69b0c4Alan Stern	result = usb_stor_probe1(&us, intf, id,
17590ff71883b2d60136430458413c135d545c69b0c4Alan Stern			(id - sddr09_usb_ids) + sddr09_unusual_dev_list);
17600ff71883b2d60136430458413c135d545c69b0c4Alan Stern	if (result)
17610ff71883b2d60136430458413c135d545c69b0c4Alan Stern		return result;
17620ff71883b2d60136430458413c135d545c69b0c4Alan Stern
17638fa7fd74ef398370383df276ca41082ba35aafd8Michal Nazarewicz	if (us->protocol == USB_PR_DPCM_USB) {
17640ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->transport_name = "Control/Bulk-EUSB/SDDR09";
17650ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->transport = dpcm_transport;
17660ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->transport_reset = usb_stor_CB_reset;
17670ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->max_lun = 1;
17680ff71883b2d60136430458413c135d545c69b0c4Alan Stern	} else {
17690ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->transport_name = "EUSB/SDDR09";
17700ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->transport = sddr09_transport;
17710ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->transport_reset = usb_stor_CB_reset;
17720ff71883b2d60136430458413c135d545c69b0c4Alan Stern		us->max_lun = 0;
17730ff71883b2d60136430458413c135d545c69b0c4Alan Stern	}
17740ff71883b2d60136430458413c135d545c69b0c4Alan Stern
17750ff71883b2d60136430458413c135d545c69b0c4Alan Stern	result = usb_stor_probe2(us);
17760ff71883b2d60136430458413c135d545c69b0c4Alan Stern	return result;
17770ff71883b2d60136430458413c135d545c69b0c4Alan Stern}
17780ff71883b2d60136430458413c135d545c69b0c4Alan Stern
17790ff71883b2d60136430458413c135d545c69b0c4Alan Sternstatic struct usb_driver sddr09_driver = {
17800ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.name =		"ums-sddr09",
17810ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.probe =	sddr09_probe,
17820ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.disconnect =	usb_stor_disconnect,
17830ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.suspend =	usb_stor_suspend,
17840ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.resume =	usb_stor_resume,
17850ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.reset_resume =	usb_stor_reset_resume,
17860ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.pre_reset =	usb_stor_pre_reset,
17870ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.post_reset =	usb_stor_post_reset,
17880ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.id_table =	sddr09_usb_ids,
17890ff71883b2d60136430458413c135d545c69b0c4Alan Stern	.soft_unbind =	1,
1790e73b2db6c9bc5bd9a3c080f286964e594351991aHuajun Li	.no_dynamic_id = 1,
17910ff71883b2d60136430458413c135d545c69b0c4Alan Stern};
17920ff71883b2d60136430458413c135d545c69b0c4Alan Stern
179365db43054065790a75291b0834657445fea2cf56Greg Kroah-Hartmanmodule_usb_driver(sddr09_driver);
1794