[PATCH 3/3] USB mass storage device driver initial implementation

Sascha Hauer s.hauer at pengutronix.de
Fri Sep 23 02:57:46 EDT 2011


From: Rosen Kolev <rosen.kolev at amk-drives.bg>

Implemented an initial version of USB mass storage device driver,
supporting USB mass storage devices with SCSI interface and BBB
protocol.  It implements the ATA interface and registers diskovered
LUNs with the disk driver.
---
 drivers/usb/Kconfig             |    2 +
 drivers/usb/Makefile            |    1 +
 drivers/usb/storage/Kconfig     |    2 +
 drivers/usb/storage/Makefile    |    4 +
 drivers/usb/storage/transport.c |  251 ++++++++++++++++
 drivers/usb/storage/transport.h |   95 ++++++
 drivers/usb/storage/usb.c       |  619 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/storage/usb.h       |   96 ++++++
 include/scsi.h                  |  208 +++++++++++++
 9 files changed, 1278 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/storage/Kconfig
 create mode 100644 drivers/usb/storage/Makefile
 create mode 100644 drivers/usb/storage/transport.c
 create mode 100644 drivers/usb/storage/transport.h
 create mode 100644 drivers/usb/storage/usb.c
 create mode 100644 drivers/usb/storage/usb.h
 create mode 100644 include/scsi.h

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index c7b2c52..254b196 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -7,6 +7,8 @@ source drivers/usb/host/Kconfig
 
 source drivers/usb/otg/Kconfig
 
+source drivers/usb/storage/Kconfig
+
 endif
 
 source drivers/usb/gadget/Kconfig
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index e6f683b..be4b371 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_USB)		+= core/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
+obj-$(CONFIG_USB_STORAGE)	+= storage/
 obj-y += host/
 obj-y += otg/
 
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
new file mode 100644
index 0000000..f6c8c06
--- /dev/null
+++ b/drivers/usb/storage/Kconfig
@@ -0,0 +1,2 @@
+config USB_STORAGE
+	tristate "USB Mass Storage support"
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
new file mode 100644
index 0000000..adf0843
--- /dev/null
+++ b/drivers/usb/storage/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_USB_STORAGE)	+= usb-storage.o
+
+usb-storage-objs :=	usb.o transport.o
+
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
new file mode 100644
index 0000000..e7a5972
--- /dev/null
+++ b/drivers/usb/storage/transport.c
@@ -0,0 +1,251 @@
+/*
+ * Most of this source has been derived from the Linux and
+ * U-Boot USB Mass Storage driver implementations.
+ *
+ * Adapted for barebox:
+ * Copyright (c) 2011, AMK Drives & Controls Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <clock.h>
+#include <scsi.h>
+#include <errno.h>
+
+#undef USB_STOR_DEBUG
+
+#include "usb.h"
+#include "transport.h"
+
+
+/* The timeout argument of usb_bulk_msg() is actually ignored
+   and the timeout is hardcoded in the host driver */
+#define USB_BULK_TO		5000
+
+static __u32 cbw_tag = 0;
+
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code (bit-encoded) -- 1 indicates input
+ * note that this doesn't work for shared command codes
+ */
+static const unsigned char us_direction[256/8] = {
+	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x01, 0x00, 0x40, 0x09, 0x01, 0x80, 0x01,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+
+/*
+ * Bulk only transport
+ */
+
+/* Clear a stall on an endpoint - special for bulk-only devices */
+int usb_stor_Bulk_clear_endpt_stall(struct us_data *us, unsigned int pipe)
+{
+	return usb_clear_halt(us->pusb_dev, pipe);
+}
+
+/* Determine what the maximum LUN supported is */
+int usb_stor_Bulk_max_lun(struct us_data *us)
+{
+	int len;
+	unsigned char iobuf[1];
+
+	/* issue the command */
+	iobuf[0] = 0;
+	len = usb_control_msg(us->pusb_dev,
+	                      usb_rcvctrlpipe(us->pusb_dev, 0),
+	                      US_BULK_GET_MAX_LUN,
+	                      USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+	                      0, us->ifnum, iobuf, 1, USB_CNTL_TIMEOUT);
+
+	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
+	          len, (int)iobuf[0]);
+
+	/* if we have a successful request, return the result */
+	if (len > 0)
+		return (int)iobuf[0];
+
+	/*
+	 * Some devices don't like GetMaxLUN.  They may STALL the control
+	 * pipe, they may return a zero-length result, they may do nothing at
+	 * all and timeout, or they may fail in even more bizarrely creative
+	 * ways.  In these cases the best approach is to use the default
+	 * value: only one LUN.
+	 */
+	return 0;
+}
+
+int usb_stor_Bulk_transport(ccb *srb, struct us_data *us)
+{
+	struct bulk_cb_wrap cbw;
+	struct bulk_cs_wrap csw;
+	int actlen, data_actlen;
+	int result;
+	unsigned int residue;
+	unsigned int pipein = usb_rcvbulkpipe(us->pusb_dev, us->recv_bulk_ep);
+	unsigned int pipeout = usb_sndbulkpipe(us->pusb_dev, us->send_bulk_ep);
+	int dir_in = US_DIRECTION(srb->cmd[0]);
+
+	srb->trans_bytes = 0;
+
+	/* set up the command wrapper */
+	cbw.Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	cbw.DataTransferLength = cpu_to_le32(srb->datalen);
+	cbw.Flags = (dir_in ? US_BULK_FLAG_IN : US_BULK_FLAG_OUT);
+	cbw.Tag = ++cbw_tag;
+	cbw.Lun = srb->lun;
+	cbw.Length = srb->cmdlen;
+
+	/* copy the command payload */
+	memcpy(cbw.CDB, srb->cmd, cbw.Length);
+
+	/* send it to out endpoint */
+	US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
+	                le32_to_cpu(cbw.Signature), cbw.Tag,
+	                le32_to_cpu(cbw.DataTransferLength), cbw.Flags,
+	                (cbw.Lun >> 4), (cbw.Lun & 0x0F),
+	                cbw.Length);
+	result = usb_bulk_msg(us->pusb_dev, pipeout, &cbw, US_BULK_CB_WRAP_LEN,
+			      &actlen, USB_BULK_TO);
+	US_DEBUGP("Bulk command transfer result=%d\n", result);
+	if (result < 0) {
+		usb_stor_Bulk_reset(us);
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* DATA STAGE */
+	/* send/receive data payload, if there is any */
+
+	wait_ms(1);
+
+	data_actlen = 0;
+	if (srb->datalen) {
+		unsigned int pipe = dir_in ? pipein : pipeout;
+		result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata,
+		                      srb->datalen, &data_actlen, USB_BULK_TO);
+		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+		/* special handling of STALL in DATA phase */
+		if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+			US_DEBUGP("DATA: stall\n");
+			/* clear the STALL on the endpoint */
+			result = usb_stor_Bulk_clear_endpt_stall(us, pipe);
+		}
+		if (result < 0) {
+			US_DEBUGP("Device status: %lx\n", us->pusb_dev->status);
+			usb_stor_Bulk_reset(us);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+	}
+
+	/* STATUS phase + error handling */
+	US_DEBUGP("Attempting to get CSW...\n");
+	result = usb_bulk_msg(us->pusb_dev, pipein, &csw, US_BULK_CS_WRAP_LEN,
+	                      &actlen, USB_BULK_TO);
+
+	/* did the endpoint stall? */
+	if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+		US_DEBUGP("STATUS: stall\n");
+		/* clear the STALL on the endpoint */
+		result = usb_stor_Bulk_clear_endpt_stall(us, pipein);
+		if (result >= 0) {
+			US_DEBUGP("Attempting to get CSW...\n");
+			result = usb_bulk_msg(us->pusb_dev, pipein,
+			                      &csw, US_BULK_CS_WRAP_LEN,
+			                      &actlen, USB_BULK_TO);
+		}
+	}
+
+	if (result < 0) {
+		US_DEBUGP("Device status: %lx\n", us->pusb_dev->status);
+		usb_stor_Bulk_reset(us);
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* check bulk status */
+	residue = le32_to_cpu(csw.Residue);
+	US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
+	          le32_to_cpu(csw.Signature), csw.Tag, residue, csw.Status);
+	if (csw.Signature != cpu_to_le32(US_BULK_CS_SIGN)) {
+		US_DEBUGP("Bad CSW signature\n");
+		usb_stor_Bulk_reset(us);
+		return USB_STOR_TRANSPORT_FAILED;
+	} else if (csw.Tag != cbw_tag) {
+		US_DEBUGP("Mismatching tag\n");
+		usb_stor_Bulk_reset(us);
+		return USB_STOR_TRANSPORT_FAILED;
+	} else if (csw.Status >= US_BULK_STAT_PHASE) {
+		US_DEBUGP("Status >= phase\n");
+		usb_stor_Bulk_reset(us);
+		return USB_STOR_TRANSPORT_ERROR;
+	} else if (residue > srb->datalen) {
+		US_DEBUGP("residue (%uB) > req data (%luB)\n",
+		          residue, srb->datalen);
+		return USB_STOR_TRANSPORT_FAILED;
+	} else if (csw.Status == US_BULK_STAT_FAIL) {
+		US_DEBUGP("FAILED\n");
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+	srb->trans_bytes = min(srb->datalen - residue, (ulong)data_actlen);
+
+	return 0;
+}
+
+
+/* This issues a Bulk-only Reset to the device in question, including
+ * clearing the subsequent endpoint halts that may occur.
+ */
+int usb_stor_Bulk_reset(struct us_data *us)
+{
+	int result;
+	int result2;
+	unsigned int pipe;
+
+	US_DEBUGP("%s called\n", __func__);
+
+	/* issue the command */
+	result = usb_control_msg(us->pusb_dev,
+	                         usb_sndctrlpipe(us->pusb_dev, 0),
+	                         US_BULK_RESET_REQUEST,
+	                         USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+	                         0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT);
+	if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+		US_DEBUGP("Soft reset stalled: %d\n", result);
+		return result;
+	}
+	wait_ms(150);
+
+	/* clear the bulk endpoints halt */
+	US_DEBUGP("Soft reset: clearing %s endpoint halt\n", "bulk-in");
+	pipe = usb_rcvbulkpipe(us->pusb_dev, us->recv_bulk_ep);
+	result = usb_clear_halt(us->pusb_dev, pipe);
+	wait_ms(150);
+	US_DEBUGP("Soft reset: clearing %s endpoint halt\n", "bulk-out");
+	pipe = usb_sndbulkpipe(us->pusb_dev, us->send_bulk_ep);
+	result2 = usb_clear_halt(us->pusb_dev, pipe);
+	wait_ms(150);
+
+	if (result >= 0)
+		result = result2;
+	US_DEBUGP("Soft reset %s\n", ((result < 0) ? "failed" : "done"));
+
+	return result;
+}
+
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
new file mode 100644
index 0000000..1c5c141
--- /dev/null
+++ b/drivers/usb/storage/transport.h
@@ -0,0 +1,95 @@
+/*
+ * Most of this source has been derived from the Linux and
+ * U-Boot USB Mass Storage driver implementations.
+ *
+ * Adapted for barebox:
+ * Copyright (c) 2011, AMK Drives & Controls Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include <scsi.h>
+
+/*
+ * Bulk only data structures
+ */
+
+/* command block wrapper */
+struct bulk_cb_wrap {
+	__le32	Signature;		/* contains 'USBC' */
+	__u32	Tag;			/* unique per command id */
+	__le32	DataTransferLength;	/* size of data */
+	__u8	Flags;			/* direction in bit 7 */
+	__u8	Lun;			/* LUN normally 0 */
+	__u8	Length;			/* of of the CDB */
+	__u8	CDB[16];		/* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN	31
+#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
+#define US_BULK_FLAG_IN		(1<<7)
+#define US_BULK_FLAG_OUT	(0<<7)
+
+/* command status wrapper */
+struct bulk_cs_wrap {
+	__le32	Signature;		/* should = 'USBS' */
+	__u32	Tag;			/* same as original command */
+	__le32	Residue;		/* amount not transferred */
+	__u8	Status;			/* see below */
+	__u8	Filler[18];
+};
+
+#define US_BULK_CS_WRAP_LEN	13
+#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
+#define US_BULK_STAT_OK		0
+#define US_BULK_STAT_FAIL	1
+#define US_BULK_STAT_PHASE	2
+
+/* bulk-only class specific requests */
+#define US_BULK_RESET_REQUEST	0xff
+#define US_BULK_GET_MAX_LUN	0xfe
+
+/*
+ * usb_stor_bulk_transfer_xxx() return codes, in order of severity
+ */
+
+#define USB_STOR_XFER_GOOD	0	/* good transfer                 */
+#define USB_STOR_XFER_SHORT	1	/* transferred less than expected */
+#define USB_STOR_XFER_STALLED	2	/* endpoint stalled              */
+#define USB_STOR_XFER_LONG	3	/* device tried to send too much */
+#define USB_STOR_XFER_ERROR	4	/* transfer died in the middle   */
+
+/*
+ * Transport return codes
+ */
+
+#define USB_STOR_TRANSPORT_GOOD	   0   /* Transport good, command good	   */
+#define USB_STOR_TRANSPORT_FAILED  1   /* Transport good, command failed   */
+#define USB_STOR_TRANSPORT_NO_SENSE 2  /* Command failed, no auto-sense    */
+#define USB_STOR_TRANSPORT_ERROR   3   /* Transport bad (i.e. device dead) */
+
+
+struct us_data;
+
+extern int usb_stor_Bulk_transport(ccb *, struct us_data *);
+extern int usb_stor_Bulk_max_lun(struct us_data *);
+extern int usb_stor_Bulk_reset(struct us_data *);
+
+#endif
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
new file mode 100644
index 0000000..d033b29
--- /dev/null
+++ b/drivers/usb/storage/usb.c
@@ -0,0 +1,619 @@
+/*
+ * Most of this source has been derived from the Linux and
+ * U-Boot USB Mass Storage driver implementations.
+ *
+ * Adapted for barebox:
+ * Copyright (c) 2011, AMK Drives & Controls Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <errno.h>
+#include <scsi.h>
+#include <usb/usb.h>
+#include <usb/usb_defs.h>
+
+#undef USB_STOR_DEBUG
+
+#include "usb.h"
+#include "transport.h"
+
+
+static LIST_HEAD(us_blkdev_list);
+
+
+/***********************************************************************
+ * USB Storage routines
+ ***********************************************************************/
+
+static int usb_stor_inquiry(ccb *srb, struct us_data *us)
+{
+	int retries, result;
+
+	srb->datalen = min(128UL, srb->datalen);
+	if (srb->datalen < 5) {
+		US_DEBUGP("SCSI_INQUIRY: invalid data buffer size\n");
+		return -EINVAL;
+	}
+
+	retries = 3;
+	do {
+		US_DEBUGP("SCSI_INQUIRY\n");
+		memset(&srb->cmd[0], 0, 6);
+		srb->cmdlen = 6;
+		srb->cmd[0] = SCSI_INQUIRY;
+		srb->cmd[3] = (u8)(srb->datalen >> 8);
+		srb->cmd[4] = (u8)(srb->datalen >> 0);
+		result = us->transport(srb, us);
+		US_DEBUGP("SCSI_INQUIRY returns %d\n", result);
+	} while ((result != USB_STOR_TRANSPORT_GOOD) && retries--);
+
+	return (result != USB_STOR_TRANSPORT_GOOD) ? -EIO : 0;
+}
+
+static int usb_stor_request_sense(ccb *srb, struct us_data *us)
+{
+	unsigned char *pdata = srb->pdata;
+	unsigned long datalen = srb->datalen;
+
+	US_DEBUGP("SCSI_REQ_SENSE\n");
+	srb->pdata = &srb->sense_buf[0];
+	srb->datalen = 18;
+	memset(&srb->cmd[0], 0, 6);
+	srb->cmdlen = 6;
+	srb->cmd[0] = SCSI_REQ_SENSE;
+	srb->cmd[4] = (u8)(srb->datalen >> 0);
+	us->transport(srb, us);
+	US_DEBUGP("Request Sense returned %02X %02X %02X\n",
+	          srb->sense_buf[2], srb->sense_buf[12], srb->sense_buf[13]);
+	srb->pdata = pdata;
+	srb->datalen = datalen;
+
+	return 0;
+}
+
+static int usb_stor_test_unit_ready(ccb *srb, struct us_data *us)
+{
+	int retries, result;
+
+	retries = 10;
+	do {
+		US_DEBUGP("SCSI_TST_U_RDY\n");
+		memset(&srb->cmd[0], 0, 6);
+		srb->cmdlen = 6;
+		srb->cmd[0] = SCSI_TST_U_RDY;
+		srb->datalen = 0;
+		result = us->transport(srb, us);
+		US_DEBUGP("SCSI_TST_U_RDY returns %d\n", result);
+		if (result == USB_STOR_TRANSPORT_GOOD)
+			return 0;
+		usb_stor_request_sense(srb, us);
+		wait_ms(100);
+	} while (retries--);
+
+	return -1;
+}
+
+static int usb_stor_read_capacity(ccb *srb, struct us_data *us)
+{
+	int retries, result;
+
+	if (srb->datalen < 8) {
+		US_DEBUGP("SCSI_RD_CAPAC: invalid data buffer size\n");
+		return -EINVAL;
+	}
+
+	retries = 3;
+	do {
+		US_DEBUGP("SCSI_RD_CAPAC\n");
+		memset(&srb->cmd[0], 0, 10);
+		srb->cmdlen = 10;
+		srb->cmd[0] = SCSI_RD_CAPAC;
+		srb->datalen = 8;
+		result = us->transport(srb, us);
+		US_DEBUGP("SCSI_RD_CAPAC returns %d\n", result);
+	} while ((result != USB_STOR_TRANSPORT_GOOD) && retries--);
+
+	return (result != USB_STOR_TRANSPORT_GOOD) ? -EIO : 0;
+}
+
+static int usb_stor_read_10(ccb *srb, struct us_data *us,
+                            unsigned long start, unsigned short blocks)
+{
+	int retries, result;
+
+	retries = 2;
+	do {
+		US_DEBUGP("SCSI_READ10: start %lx blocks %x\n", start, blocks);
+		memset(&srb->cmd[0], 0, 10);
+		srb->cmdlen = 10;
+		srb->cmd[0] = SCSI_READ10;
+		srb->cmd[2] = (u8)(start >> 24);
+		srb->cmd[3] = (u8)(start >> 16);
+		srb->cmd[4] = (u8)(start >> 8);
+		srb->cmd[5] = (u8)(start >> 0);
+		srb->cmd[7] = (u8)(blocks >> 8);
+		srb->cmd[8] = (u8)(blocks >> 0);
+		result = us->transport(srb, us);
+		US_DEBUGP("SCSI_READ10 returns %d\n", result);
+		if (result == USB_STOR_TRANSPORT_GOOD)
+			return 0;
+		usb_stor_request_sense(srb, us);
+	} while (retries--);
+
+	return -EIO;
+}
+
+static int usb_stor_write_10(ccb *srb, struct us_data *us,
+                             unsigned long start, unsigned short blocks)
+{
+	int retries, result;
+
+	retries = 2;
+	do {
+		US_DEBUGP("SCSI_WRITE10: start %lx blocks %x\n", start, blocks);
+		memset(&srb->cmd[0], 0, 10);
+		srb->cmdlen = 10;
+		srb->cmd[0] = SCSI_WRITE10;
+		srb->cmd[2] = (u8)(start >> 24);
+		srb->cmd[3] = (u8)(start >> 16);
+		srb->cmd[4] = (u8)(start >> 8);
+		srb->cmd[5] = (u8)(start >> 0);
+		srb->cmd[7] = (u8)(blocks >> 8);
+		srb->cmd[8] = (u8)(blocks >> 0);
+		result = us->transport(srb, us);
+		US_DEBUGP("SCSI_WRITE10 returns %d\n", result);
+		if (result == USB_STOR_TRANSPORT_GOOD)
+			return 0;
+		usb_stor_request_sense(srb, us);
+	} while (retries--);
+
+	return us->transport(srb, us);
+}
+
+
+/***********************************************************************
+ * Disk driver interface
+ ***********************************************************************/
+
+#define US_MAX_IO_BLK 32U
+
+enum { io_rd, io_wr };
+
+/* Read / write a chunk of sectors on media */
+static int usb_stor_blk_io(int io_op, struct device_d *disk_dev,
+                           uint64_t sector_start, unsigned sector_count,
+                           void *buffer)
+{
+	struct ata_interface *pata_if = disk_dev->platform_data;
+	struct us_blk_dev *pblk_dev = (struct us_blk_dev *)pata_if->priv;
+	struct us_data *us = pblk_dev->us;
+	ccb us_ccb;
+	ushort const sector_size = 512;
+	unsigned sectors_done;
+
+	if (sector_count == 0)
+		return 0;
+
+	/* check for unsupported block size */
+	if (pblk_dev->blksz != sector_size) {
+		US_DEBUGP("%s: unsupported block size %lu\n",
+		          __func__, pblk_dev->blksz);
+		return -EINVAL;
+	}
+
+	/* check for invalid sector_start */
+	if (sector_start >= pblk_dev->blknum || sector_start > (ulong)-1) {
+		US_DEBUGP("%s: start sector %llu too large\n",
+		          __func__, sector_start);
+		return -EINVAL;
+	}
+
+	us_ccb.lun = pblk_dev->lun;
+	usb_disable_asynch(1);
+
+	/* ensure unit ready */
+	US_DEBUGP("Testing for unit ready\n");
+	if (usb_stor_test_unit_ready(&us_ccb, us)) {
+		US_DEBUGP("Device NOT ready\n");
+		usb_disable_asynch(0);
+		return -EIO;
+	}
+
+	/* possibly limit the amount of I/O data */
+	if (sector_count > INT_MAX) {
+		sector_count = INT_MAX;
+		US_DEBUGP("Restricting I/O to %u blocks\n", sector_count);
+	}
+	if (sector_start + sector_count > pblk_dev->blknum) {
+		sector_count = pblk_dev->blknum - sector_start;
+		US_DEBUGP("Restricting I/O to %u blocks\n", sector_count);
+	}
+
+	/* read / write the requested data */
+	US_DEBUGP("%s %u block(s), starting from %llu\n",
+	          ((io_op == io_rd) ? "Read" : "Write"),
+	          sector_count, sector_start);
+	sectors_done = 0;
+	while (sector_count > 0) {
+		int result;
+		ushort n = (ushort)min(sector_count, US_MAX_IO_BLK);
+		us_ccb.pdata = buffer + sectors_done * sector_size;
+		us_ccb.datalen = n * (ulong)sector_size;
+		if (io_op == io_rd)
+			result = usb_stor_read_10(&us_ccb, us,
+			                          (ulong)sector_start, n);
+		else
+			result = usb_stor_write_10(&us_ccb, us,
+			                           (ulong)sector_start, n);
+		if (result != 0) {
+			US_DEBUGP("I/O error at sector %llu\n", sector_start);
+			break;
+		}
+		sector_start += n;
+		sector_count -= n;
+		sectors_done += n;
+	}
+
+	usb_disable_asynch(0);
+
+	US_DEBUGP("Successful I/O of %u blocks\n", sectors_done);
+
+	return (sector_count != 0) ? -EIO : 0;
+}
+
+/* Write a chunk of sectors to media */
+static int usb_stor_blk_write(struct device_d *disk_dev, uint64_t sector_start,
+                              unsigned sector_count, const void *buffer)
+{
+	return usb_stor_blk_io(io_wr, disk_dev, sector_start, sector_count,
+	                       (void *)buffer);
+}
+
+/* Read a chunk of sectors from media */
+static int usb_stor_blk_read(struct device_d *disk_dev, uint64_t sector_start,
+                             unsigned sector_count, void *buffer)
+{
+	return usb_stor_blk_io(io_rd, disk_dev, sector_start, sector_count,
+	                       buffer);
+}
+
+
+/***********************************************************************
+ * Block device routines
+ ***********************************************************************/
+
+static unsigned char us_io_buf[512];
+
+/* Prepare a disk device */
+static int usb_stor_init_blkdev(struct us_blk_dev *pblk_dev)
+{
+	struct us_data *us = pblk_dev->us;
+	ccb us_ccb;
+	unsigned long *pcap;
+	int result = 0;
+
+	us_ccb.pdata = us_io_buf;
+	us_ccb.lun = pblk_dev->lun;
+
+	pblk_dev->blknum = 0;
+	usb_disable_asynch(1);
+
+	/* get device info */
+	US_DEBUGP("Reading device info\n");
+	us_ccb.datalen = 36;
+	if (usb_stor_inquiry(&us_ccb, us)) {
+		US_DEBUGP("Cannot read device info\n");
+		result = -ENODEV;
+		goto Exit;
+	}
+	US_DEBUGP("Peripheral type: %x, removable: %x\n",
+	          us_io_buf[0], (us_io_buf[1] >> 7));
+	US_DEBUGP("ISO ver: %x, resp format: %x\n", us_io_buf[2], us_io_buf[3]);
+	US_DEBUGP("Vendor/product/rev: %28s\n", &us_io_buf[8]);
+	// TODO:  process and store device info
+
+	/* ensure unit ready */
+	US_DEBUGP("Testing for unit ready\n");
+	us_ccb.datalen = 0;
+	if (usb_stor_test_unit_ready(&us_ccb, us)) {
+		US_DEBUGP("Device NOT ready\n");
+		result = -ENODEV;
+		goto Exit;
+	}
+
+	/* read capacity */
+	US_DEBUGP("Reading capacity\n");
+	memset(us_ccb.pdata, 0, 8);
+	us_ccb.datalen = sizeof(us_io_buf);
+	if (usb_stor_read_capacity(&us_ccb, us) != 0) {
+		US_DEBUGP("Cannot read device capacity\n");
+		result = -EIO;
+		goto Exit;
+	}
+	pcap = (unsigned long *)us_ccb.pdata;
+	US_DEBUGP("Read Capacity returns: 0x%lx, 0x%lx\n", pcap[0], pcap[1]);
+	pblk_dev->blknum = be32_to_cpu(pcap[0]);
+	pblk_dev->blksz = be32_to_cpu(pcap[1]);
+	pblk_dev->blknum++;
+	US_DEBUGP("Capacity = 0x%llx, blocksz = 0x%lx\n",
+	          pblk_dev->blknum, pblk_dev->blksz);
+
+Exit:
+	usb_disable_asynch(0);
+	return result;
+}
+
+/* Create and register a disk device for the specified LUN */
+static int usb_stor_add_blkdev(struct us_data *us, unsigned char lun)
+{
+	struct us_blk_dev *pblk_dev;
+	struct device_d *pdev;
+	struct ata_interface *pata_if;
+	int result;
+
+	/* allocate blk dev data */
+	pblk_dev = (struct us_blk_dev *)malloc(sizeof(struct us_blk_dev));
+	if (!pblk_dev)
+		return -ENOMEM;
+	memset(pblk_dev, 0, sizeof(struct us_blk_dev));
+
+	/* initialize blk dev data */
+	pblk_dev->us = us;
+	pblk_dev->lun = lun;
+	pata_if = &pblk_dev->ata_if;
+	pata_if->read = &usb_stor_blk_read;
+	pata_if->write = &usb_stor_blk_write;
+	pata_if->priv = pblk_dev;
+	pdev = &pblk_dev->dev;
+	strcpy(pdev->name, "disk");
+	pdev->platform_data = pata_if;
+
+	/* read some info and get the unit ready */
+	result = usb_stor_init_blkdev(pblk_dev);
+	if (result < 0)
+		goto BadDevice;
+
+	/* register disk device */
+	result = register_device(pdev);
+	if (result < 0)
+		goto BadDevice;
+	list_add_tail(&pblk_dev->list, &us_blkdev_list);
+	US_DEBUGP("USB disk device successfully added\n");
+
+	return 0;
+
+BadDevice:
+	US_DEBUGP("%s failed with %d\n", __func__, result);
+	free(pblk_dev);
+	return result;
+}
+
+/***********************************************************************
+ * USB Mass Storage device probe and initialization
+ ***********************************************************************/
+
+/* Get the transport settings */
+static void get_transport(struct us_data *us)
+{
+	switch (us->protocol) {
+	case US_PR_BULK:
+		us->transport_name = "Bulk";
+		us->transport = &usb_stor_Bulk_transport;
+		us->transport_reset = &usb_stor_Bulk_reset;
+		break;
+	}
+
+	US_DEBUGP("Transport: %s\n", us->transport_name);
+}
+
+/* Get the endpoint settings */
+static int get_pipes(struct us_data *us, struct usb_interface_descriptor *intf)
+{
+	unsigned int i;
+	struct usb_endpoint_descriptor *ep;
+	struct usb_endpoint_descriptor *ep_in = NULL;
+	struct usb_endpoint_descriptor *ep_out = NULL;
+	struct usb_endpoint_descriptor *ep_int = NULL;
+
+	/*
+	 * Find the first endpoint of each type we need.
+	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
+	 * An optional interrupt-in is OK (necessary for CBI protocol).
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < intf->bNumEndpoints; i++) {
+		ep = &intf->ep_desc[i];
+
+		if (USB_EP_IS_XFER_BULK(ep)) {
+			if (USB_EP_IS_DIR_IN(ep)) {
+				if ( !ep_in )
+					ep_in = ep;
+			}
+			else {
+				if ( !ep_out )
+					ep_out = ep;
+			}
+		}
+		else if (USB_EP_IS_INT_IN(ep)) {
+			if (!ep_int)
+				ep_int = ep;
+		}
+	}
+	if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) {
+		US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
+		return -EIO;
+	}
+
+	/* Store the pipe values */
+	us->send_bulk_ep = USB_EP_NUM(ep_out);
+	us->recv_bulk_ep = USB_EP_NUM(ep_in);
+	if (ep_int) {
+		us->recv_intr_ep = USB_EP_NUM(ep_int);
+		us->ep_bInterval = ep_int->bInterval;
+	}
+	return 0;
+}
+
+/* Scan device's LUNs, registering a disk device for each LUN */
+static int usb_stor_scan(struct usb_device *usbdev, struct us_data *us)
+{
+	unsigned char lun;
+	int num_devs = 0;
+
+	/* obtain the max LUN */
+	us->max_lun = 0;
+	if (us->protocol == US_PR_BULK)
+		us->max_lun = usb_stor_Bulk_max_lun(us);
+
+	/* register a disk device for each active LUN */
+	for (lun=0; lun<=us->max_lun; lun++) {
+		if (usb_stor_add_blkdev(us, lun) == 0)
+			num_devs++;
+	}
+
+	US_DEBUGP("Found %d block devices on %s\n", num_devs, usbdev->dev.name);
+
+	return  num_devs ? 0 : -ENODEV;
+}
+
+/* Probe routine for standard devices */
+static int usb_stor_probe(struct usb_device *usbdev,
+			 const struct usb_device_id *id)
+{
+	struct us_data *us;
+	int result;
+	int ifno;
+	struct usb_interface_descriptor *intf;
+
+	US_DEBUGP("Supported USB Mass Storage device detected\n");
+
+	/* scan usbdev interfaces again to find one that we can handle */
+	for (ifno=0; ifno<usbdev->config.no_of_if; ifno++) {
+		intf = &usbdev->config.if_desc[ifno];
+
+		if (intf->bInterfaceClass    == USB_CLASS_MASS_STORAGE &&
+		    intf->bInterfaceSubClass == US_SC_SCSI &&
+		    intf->bInterfaceProtocol == US_PR_BULK)
+			break;
+	}
+	if (ifno >= usbdev->config.no_of_if)
+		return -ENXIO;
+
+	/* select the right interface */
+	result = usb_set_interface(usbdev, intf->bInterfaceNumber, 0);
+	if (result)
+		return result;
+
+	US_DEBUGP("Selected interface %d\n", (int)intf->bInterfaceNumber);
+
+	/* allocate us_data structure */
+	us = (struct us_data *)malloc(sizeof(struct us_data));
+	if (!us)
+		return -ENOMEM;
+	memset(us, 0, sizeof(struct us_data));
+
+	/* initialize the us_data structure */
+	us->pusb_dev = usbdev;
+	us->flags = 0;
+	us->ifnum = intf->bInterfaceNumber;
+	us->subclass = intf->bInterfaceSubClass;
+	us->protocol = intf->bInterfaceProtocol;
+
+	/* get standard transport and protocol settings */
+	get_transport(us);
+
+	/* find the endpoints needed by the transport */
+	result = get_pipes(us, intf);
+	if (result)
+		goto BadDevice;
+
+	/* register a disk device for each LUN */
+	usb_stor_scan(usbdev, us);
+
+	/* associate the us_data structure with the usb_device */
+	usbdev->drv_data = us;
+
+	return 0;
+
+BadDevice:
+	US_DEBUGP("%s failed with %d\n", __func__, result);
+	free(us);
+	return result;
+}
+
+/* Handle a USB mass-storage disconnect */
+static void usb_stor_disconnect(struct usb_device *usbdev)
+{
+#if 0
+	struct us_data *us = (struct us_data *)usbdev->drv_data;
+	struct us_blk_dev *bdev, *bdev_tmp;
+
+	US_DEBUGP("Disconnecting USB Mass Storage device %s\n",
+	          usbdev->dev.name);
+
+	/* release all block devices of this mass storage device */
+	list_for_each_entry_safe(bdev, bdev_tmp, &us_blkdev_list, list) {
+		if (bdev->us == us) {
+			US_DEBUGP("Releasing %s\n", bdev->dev.name);
+			list_del(&bdev->list);
+			unregister_device(&bdev->dev);
+			free(bdev);
+		}
+	}
+
+	/* release device's private data */
+	usbdev->drv_data = 0;
+	free(us);
+#else
+	dev_err(&usbdev->dev, "Disk/partition removal not yet implemented "
+	                      "in the ATA disk driver.");
+#endif
+}
+
+#define USUAL_DEV(use_proto, use_trans, drv_info) \
+{	USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, use_proto, use_trans), \
+	.driver_info = (drv_info) }
+
+/* Table with supported devices, most specific first. */
+static struct usb_device_id usb_storage_usb_ids[] = {
+	USUAL_DEV(US_SC_SCSI, US_PR_BULK, 0),	// SCSI intf, BBB proto
+	{ }
+};
+
+
+/***********************************************************************
+ * USB Storage driver initialization and registration
+ ***********************************************************************/
+
+static struct usb_driver usb_storage_driver = {
+	.driver.name =	"usb-storage",
+	.id_table =	usb_storage_usb_ids,
+	.probe =	usb_stor_probe,
+	.disconnect =	usb_stor_disconnect,
+};
+
+static int __init usb_stor_init(void)
+{
+	usb_storage_driver.name = usb_storage_driver.driver.name;
+	return usb_driver_register(&usb_storage_driver);
+}
+device_initcall(usb_stor_init);
+
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
new file mode 100644
index 0000000..17a1e12
--- /dev/null
+++ b/drivers/usb/storage/usb.h
@@ -0,0 +1,96 @@
+/*
+ * Most of this source has been derived from the Linux and
+ * U-Boot USB Mass Storage driver implementations.
+ *
+ * Adapted for barebox:
+ * Copyright (c) 2011, AMK Drives & Controls Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef _STORAGE_USB_H_
+#define _STORAGE_USB_H_
+
+#include <usb/usb.h>
+#include <ata.h>
+#include <scsi.h>
+#include <linux/list.h>
+
+
+#ifdef  USB_STOR_DEBUG
+#define US_DEBUGP(fmt, args...)    printf(fmt , ##args)
+#else
+#define US_DEBUGP(fmt, args...)
+#endif
+
+
+/* some defines, similar to ch9.h */
+#define USB_EP_NUM(epd) \
+	((epd)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+#define USB_EP_IS_DIR_IN(epd) \
+	(((epd)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+#define USB_EP_IS_XFER_BULK(epd) \
+	(((epd)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == \
+	 USB_ENDPOINT_XFER_BULK)
+#define USB_EP_IS_XFER_INT(epd) \
+	(((epd)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == \
+	 USB_ENDPOINT_XFER_INT)
+#define USB_EP_IS_INT_IN(epd) \
+	(USB_EP_IS_XFER_INT(epd) && USB_EP_IS_DIR_IN(epd))
+
+
+struct us_data;
+
+typedef int (*trans_cmnd)(ccb *cb, struct us_data *data);
+typedef int (*trans_reset)(struct us_data *data);
+
+/* one us_data object allocated per usb storage device */
+struct us_data {
+	struct usb_device	*pusb_dev;	/* this usb_device */
+	unsigned int		flags;		/* from filter */
+	unsigned char		send_bulk_ep;	/* used endpoints */
+	unsigned char		recv_bulk_ep;
+	unsigned char		recv_intr_ep;
+	unsigned char		ifnum;		/* interface number */
+
+	unsigned char		subclass;
+	unsigned char		protocol;
+
+	unsigned char		max_lun;
+	unsigned char		ep_bInterval;
+
+	char			*transport_name;
+
+	trans_cmnd		transport;	/* transport function */
+	trans_reset		transport_reset;/* transport device reset */
+
+	/* SCSI interfaces */
+	ccb			*srb;		/* current srb */
+};
+
+/* one us_blk_dev object allocated per LUN */
+struct us_blk_dev {
+	struct us_data		*us;		/* LUN's enclosing dev */
+	struct device_d		dev;		/* intf to generic driver */
+	struct ata_interface	ata_if;		/* intf to "disk" driver */
+	uint64_t		blknum;		/* capacity */
+	unsigned long		blksz;		/* block size */
+	unsigned char 		lun;		/* the LUN of this blk dev */
+	struct list_head	list;		/* siblings */
+};
+
+#endif
diff --git a/include/scsi.h b/include/scsi.h
new file mode 100644
index 0000000..931d03d
--- /dev/null
+++ b/include/scsi.h
@@ -0,0 +1,208 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+ #ifndef _SCSI_H
+ #define _SCSI_H
+
+typedef struct SCSI_cmd_block {
+	unsigned char		cmd[16];		/* command */
+	unsigned char		sense_buf[64];		/* for request sense */
+	unsigned char		status;			/* SCSI Status */
+	unsigned char		target;			/* Target ID */
+	unsigned char		lun;			/* Target LUN */
+	unsigned char		cmdlen;			/* command len */
+	unsigned long		datalen;		/* Total data length */
+	unsigned char	*	pdata;			/* pointer to data */
+	unsigned char		msgout[12];		/* Messge out buffer (NOT USED) */
+	unsigned char		msgin[12];		/* Message in buffer */
+	unsigned char		sensecmdlen;		/* Sense command len */
+	unsigned long		sensedatalen;		/* Sense data len */
+	unsigned char		sensecmd[6];		/* Sense command */
+	unsigned long		contr_stat;		/* Controller Status */
+	unsigned long		trans_bytes;		/* tranfered bytes */
+
+	unsigned int		priv;
+} ccb;
+
+/*-----------------------------------------------------------
+**
+**	SCSI  constants.
+**
+**-----------------------------------------------------------
+*/
+
+/*
+**	Messages
+*/
+
+#define	M_COMPLETE	(0x00)
+#define	M_EXTENDED	(0x01)
+#define	M_SAVE_DP	(0x02)
+#define	M_RESTORE_DP	(0x03)
+#define	M_DISCONNECT	(0x04)
+#define	M_ID_ERROR	(0x05)
+#define	M_ABORT		(0x06)
+#define	M_REJECT	(0x07)
+#define	M_NOOP		(0x08)
+#define	M_PARITY	(0x09)
+#define	M_LCOMPLETE	(0x0a)
+#define	M_FCOMPLETE	(0x0b)
+#define	M_RESET		(0x0c)
+#define	M_ABORT_TAG	(0x0d)
+#define	M_CLEAR_QUEUE	(0x0e)
+#define	M_INIT_REC	(0x0f)
+#define	M_REL_REC	(0x10)
+#define	M_TERMINATE	(0x11)
+#define	M_SIMPLE_TAG	(0x20)
+#define	M_HEAD_TAG	(0x21)
+#define	M_ORDERED_TAG	(0x22)
+#define	M_IGN_RESIDUE	(0x23)
+#define	M_IDENTIFY	(0x80)
+
+#define	M_X_MODIFY_DP	(0x00)
+#define	M_X_SYNC_REQ	(0x01)
+#define	M_X_WIDE_REQ	(0x03)
+#define	M_X_PPR_REQ	(0x04)
+
+
+/*
+**	Status
+*/
+
+#define	S_GOOD		(0x00)
+#define	S_CHECK_COND	(0x02)
+#define	S_COND_MET	(0x04)
+#define	S_BUSY		(0x08)
+#define	S_INT		(0x10)
+#define	S_INT_COND_MET	(0x14)
+#define	S_CONFLICT	(0x18)
+#define	S_TERMINATED	(0x20)
+#define	S_QUEUE_FULL	(0x28)
+#define	S_ILLEGAL	(0xff)
+#define	S_SENSE		(0x80)
+
+/*
+ * Sense_keys
+ */
+
+#define SENSE_NO_SENSE		0x0
+#define SENSE_RECOVERED_ERROR	0x1
+#define SENSE_NOT_READY		0x2
+#define SENSE_MEDIUM_ERROR	0x3
+#define SENSE_HARDWARE_ERROR	0x4
+#define SENSE_ILLEGAL_REQUEST	0x5
+#define SENSE_UNIT_ATTENTION	0x6
+#define SENSE_DATA_PROTECT	0x7
+#define SENSE_BLANK_CHECK	0x8
+#define SENSE_VENDOR_SPECIFIC	0x9
+#define SENSE_COPY_ABORTED	0xA
+#define SENSE_ABORTED_COMMAND	0xB
+#define SENSE_VOLUME_OVERFLOW	0xD
+#define SENSE_MISCOMPARE	0xE
+
+
+#define SCSI_CHANGE_DEF	0x40		/* Change Definition (Optional) */
+#define SCSI_COMPARE	0x39		/* Compare (O) */
+#define SCSI_COPY	0x18		/* Copy (O) */
+#define SCSI_COP_VERIFY	0x3A		/* Copy and Verify (O) */
+#define SCSI_INQUIRY	0x12		/* Inquiry (MANDATORY) */
+#define SCSI_LOG_SELECT	0x4C		/* Log Select (O) */
+#define SCSI_LOG_SENSE	0x4D		/* Log Sense (O) */
+#define SCSI_MODE_SEL6	0x15		/* Mode Select 6-byte (Device Specific) */
+#define SCSI_MODE_SEL10	0x55		/* Mode Select 10-byte (Device Specific) */
+#define SCSI_MODE_SEN6	0x1A		/* Mode Sense 6-byte (Device Specific) */
+#define SCSI_MODE_SEN10	0x5A		/* Mode Sense 10-byte (Device Specific) */
+#define SCSI_READ_BUFF	0x3C		/* Read Buffer (O) */
+#define SCSI_REQ_SENSE	0x03		/* Request Sense (MANDATORY) */
+#define SCSI_SEND_DIAG	0x1D		/* Send Diagnostic (O) */
+#define SCSI_TST_U_RDY	0x00		/* Test Unit Ready (MANDATORY) */
+#define SCSI_WRITE_BUFF	0x3B		/* Write Buffer (O) */
+/***************************************************************************
+ *			  %%% Commands Unique to Direct Access Devices %%%
+ ***************************************************************************/
+#define SCSI_COMPARE	0x39		/* Compare (O) */
+#define SCSI_FORMAT	0x04		/* Format Unit (MANDATORY) */
+#define SCSI_LCK_UN_CAC	0x36		/* Lock Unlock Cache (O) */
+#define SCSI_PREFETCH	0x34		/* Prefetch (O) */
+#define SCSI_MED_REMOVL	0x1E		/* Prevent/Allow medium Removal (O) */
+#define SCSI_READ6	0x08		/* Read 6-byte (MANDATORY) */
+#define SCSI_READ10	0x28		/* Read 10-byte (MANDATORY) */
+#define SCSI_RD_CAPAC	0x25		/* Read Capacity (MANDATORY) */
+#define SCSI_RD_DEFECT	0x37		/* Read Defect Data (O) */
+#define SCSI_READ_LONG	0x3E		/* Read Long (O) */
+#define SCSI_REASS_BLK	0x07		/* Reassign Blocks (O) */
+#define SCSI_RCV_DIAG	0x1C		/* Receive Diagnostic Results (O) */
+#define SCSI_RELEASE	0x17		/* Release Unit (MANDATORY) */
+#define SCSI_REZERO	0x01		/* Rezero Unit (O) */
+#define SCSI_SRCH_DAT_E	0x31		/* Search Data Equal (O) */
+#define SCSI_SRCH_DAT_H	0x30		/* Search Data High (O) */
+#define SCSI_SRCH_DAT_L	0x32		/* Search Data Low (O) */
+#define SCSI_SEEK6	0x0B		/* Seek 6-Byte (O) */
+#define SCSI_SEEK10	0x2B		/* Seek 10-Byte (O) */
+#define SCSI_SEND_DIAG	0x1D		/* Send Diagnostics (MANDATORY) */
+#define SCSI_SET_LIMIT	0x33		/* Set Limits (O) */
+#define SCSI_START_STP	0x1B		/* Start/Stop Unit (O) */
+#define SCSI_SYNC_CACHE	0x35		/* Synchronize Cache (O) */
+#define SCSI_VERIFY	0x2F		/* Verify (O) */
+#define SCSI_WRITE6	0x0A		/* Write 6-Byte (MANDATORY) */
+#define SCSI_WRITE10	0x2A		/* Write 10-Byte (MANDATORY) */
+#define SCSI_WRT_VERIFY	0x2E		/* Write and Verify (O) */
+#define SCSI_WRITE_LONG	0x3F		/* Write Long (O) */
+#define SCSI_WRITE_SAME	0x41		/* Write Same (O) */
+
+
+/****************************************************************************
+ * decleration of functions which have to reside in the LowLevel Part Driver
+ */
+
+void scsi_print_error(ccb *pccb);
+int scsi_exec(ccb *pccb);
+void scsi_bus_reset(void);
+void scsi_low_level_init(int busdevfunc);
+
+
+/***************************************************************************
+ * functions residing inside cmd_scsi.c
+ */
+void scsi_init(void);
+
+
+#define SCSI_IDENTIFY				0xC0  /* not used */
+
+/* Hardware errors  */
+#define SCSI_SEL_TIME_OUT		 0x00000101  /* Selection time out */
+#define SCSI_HNS_TIME_OUT		 0x00000102  /* Handshake */
+#define SCSI_MA_TIME_OUT		 0x00000103  /* Phase error */
+#define SCSI_UNEXP_DIS			 0x00000104  /* unexpected disconnect */
+
+#define SCSI_INT_STATE			 0x00010000  /* unknown Interrupt number is stored in 16 LSB */
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#endif /* _SCSI_H */
-- 
1.7.2.3




More information about the barebox mailing list