Newer
Older
* Most of this source has been derived from the Linux USB
* project:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
* (c) 1999 Michael Gee (michael@linuxspecific.com)
* (c) 2000 Yggdrasil Computing, Inc.
*
*
* Adapted for U-Boot:
* (C) Copyright 2001 Denis Peter, MPL AG Switzerland
* Driver model conversion:
* (C) Copyright 2015 Google, Inc
* For BBB support (C) Copyright 2003
* Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
* BBB support based on /sys/dev/usb/umass.c from
* SPDX-License-Identifier: GPL-2.0+
*/
/* Note:
* Currently only the CBI transport protocoll has been implemented, and it
* is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
* transport protocoll may work as well.
*/
/*
* New Note:
* Support for USB Mass Storage Devices (BBB) has been added. It has
* only been tested with USB memory sticks.
*/
#include <errno.h>
#include <inttypes.h>
#include <memalign.h>
#include <asm/byteorder.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <part.h>
#undef BBB_COMDAT_TRACE
#undef BBB_XPORT_TRACE
#include <scsi.h>
/* direction table -- this indicates the direction of the data
* transfer for each command code -- a 1 indicates input
*/
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, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN)));
static int usb_max_devs; /* number of highest available usb device */
#ifndef CONFIG_BLK
static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV];
typedef int (*trans_cmnd)(ccb *cb, struct us_data *data);
typedef int (*trans_reset)(struct us_data *data);
struct usb_device *pusb_dev; /* this usb_device */
unsigned int flags; /* from filter initially */
# define USB_READY (1 << 0)
unsigned char ifnum; /* interface number */
unsigned char ep_in; /* in endpoint */
unsigned char ep_out; /* out ....... */
unsigned char ep_int; /* interrupt . */
unsigned char subclass; /* as in overview */
unsigned char protocol; /* .............. */
unsigned char attention_done; /* force attn on first cmd */
unsigned short ip_data; /* interrupt data */
int action; /* what to do */
int ip_wanted; /* needed */
int *irq_handle; /* for USB int requests */
unsigned int irqpipe; /* pipe for release_irq */
unsigned char irqmaxp; /* max packed for irq Pipe */
unsigned char irqinterval; /* Intervall for IRQ Pipe */
ccb *srb; /* current srb */
trans_reset transport_reset; /* reset routine */
trans_cmnd transport; /* transport routine */
* The U-Boot EHCI driver can handle any transfer length as long as there is
* enough free heap space left, but the SCSI READ(10) and WRITE(10) commands are
* limited to 65535 blocks.
#ifndef CONFIG_BLK
#define USB_STOR_TRANSPORT_GOOD 0
#define USB_STOR_TRANSPORT_FAILED -1
#define USB_STOR_TRANSPORT_ERROR -2
int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
struct us_data *ss);
#ifdef CONFIG_BLK
static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
lbaint_t blkcnt, void *buffer);
static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
lbaint_t blkcnt, const void *buffer);
#else
static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
lbaint_t blkcnt, void *buffer);
static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
lbaint_t blkcnt, const void *buffer);
/*******************************************************************************
* show info on storage devices; 'usb start/init' must be invoked earlier
* as we only retrieve structures populated during devices initialization
*/
int count = 0;
#ifdef CONFIG_BLK
struct udevice *dev;
for (blk_first_device(IF_TYPE_USB, &dev);
dev;
blk_next_device(&dev)) {
struct blk_desc *desc = dev_get_uclass_platdata(dev);
printf(" Device %d: ", desc->devnum);
dev_print(desc);
count++;
}
#else
for (i = 0; i < usb_max_devs; i++) {
dev_print(&usb_dev_desc[i]);
}
if (!count) {
printf("No storage devices, perhaps not 'usb start'ed..?\n");
return 1;
}
static unsigned int usb_get_max_lun(struct us_data *us)
{
int len;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1);
len = usb_control_msg(us->pusb_dev,
usb_rcvctrlpipe(us->pusb_dev, 0),
US_BBB_GET_MAX_LUN,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
0, us->ifnum,
USB_CNTL_TIMEOUT * 5);
debug("Get Max LUN -> len = %i, result = %i\n", len, (int) *result);
static int usb_stor_probe_device(struct usb_device *udev)
int lun, max_lun;
#ifdef CONFIG_BLK
struct us_data *data;
int ret;
#else
int start;
if (udev == NULL)
return -ENOENT; /* no more devices available */
#endif
debug("\n\nProbing for storage\n");
#ifdef CONFIG_BLK
/*
* We store the us_data in the mass storage device's platdata. It
* is shared by all LUNs (block devices) attached to this mass storage
* device.
*/
data = dev_get_platdata(udev->dev);
if (!usb_storage_probe(udev, 0, data))
return 0;
max_lun = usb_get_max_lun(data);
for (lun = 0; lun <= max_lun; lun++) {
struct blk_desc *blkdev;
struct udevice *dev;
snprintf(str, sizeof(str), "lun%d", lun);
ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
IF_TYPE_USB, usb_max_devs, 512, 0,
&dev);
if (ret) {
debug("Cannot bind driver\n");
return ret;
}
blkdev = dev_get_uclass_platdata(dev);
blkdev->target = 0xff;
blkdev->lun = lun;
ret = usb_stor_get_info(udev, data, blkdev);
if (ret == 1)
ret = blk_prepare_device(dev);
if (!ret) {
usb_max_devs++;
debug("%s: Found device %p\n", __func__, udev);
} else {
debug("usb_stor_get_info: Invalid device\n");
ret = device_unbind(dev);
if (ret)
return ret;
}
}
#else
/* We don't have space to even probe if we hit the maximum */
if (usb_max_devs == USB_MAX_STOR_DEV) {
printf("max USB Storage Device reached: %d stopping\n",
usb_max_devs);
return -ENOSPC;
}
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
if (!usb_storage_probe(udev, 0, &usb_stor[usb_max_devs]))
return 0;
/*
* OK, it's a storage device. Iterate over its LUNs and populate
* usb_dev_desc'
*/
start = usb_max_devs;
max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
for (lun = 0; lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
lun++) {
struct blk_desc *blkdev;
blkdev = &usb_dev_desc[usb_max_devs];
memset(blkdev, '\0', sizeof(struct blk_desc));
blkdev->if_type = IF_TYPE_USB;
blkdev->devnum = usb_max_devs;
blkdev->part_type = PART_TYPE_UNKNOWN;
blkdev->target = 0xff;
blkdev->type = DEV_TYPE_UNKNOWN;
blkdev->block_read = usb_stor_read;
blkdev->block_write = usb_stor_write;
blkdev->lun = lun;
blkdev->priv = udev;
if (usb_stor_get_info(udev, &usb_stor[start],
&usb_dev_desc[usb_max_devs]) == 1) {
debug("partype: %d\n", blkdev->part_type);
part_init(blkdev);
debug("partype: %d\n", blkdev->part_type);
usb_max_devs++;
debug("%s: Found device %p\n", __func__, udev);
return 0;
}
void usb_stor_reset(void)
{
usb_max_devs = 0;
}
/*******************************************************************************
* scan the usb and reports device info
* to the user if mode = 1
* returns current device or -1 if no
*/
int usb_stor_scan(int mode)
{
unsigned char i;
printf(" scanning usb for storage devices... ");
usb_disable_asynch(1); /* asynch transfer not allowed */
usb_stor_reset();
struct usb_device *dev;
dev = usb_get_dev_index(i); /* get device */
debug("i=%d\n", i);
if (usb_stor_probe_device(dev))
printf("%d Storage Device(s) found\n", usb_max_devs);
static int usb_stor_irq(struct usb_device *dev)
{
struct us_data *us;
printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
for (i = 0; i < 12; i++)
printf("%02X ", pccb->cmd[i]);
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
printf("\n");
}
static void display_int_status(unsigned long tmp)
{
printf("Status: %s %s %s %s %s %s %s\n",
(tmp & USB_ST_ACTIVE) ? "Active" : "",
(tmp & USB_ST_STALLED) ? "Stalled" : "",
(tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
(tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
(tmp & USB_ST_NAK_REC) ? "NAKed" : "",
(tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
(tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
}
#endif
/***********************************************************************
* Data transfer routines
***********************************************************************/
static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
{
int max_size;
int this_xfer;
int result;
int partial;
int maxtry;
int stat;
/* determine the maximum packet size for these transfers */
max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
/* while we have data left to transfer */
while (length) {
/* calculate how long this will be -- maximum or a remainder */
this_xfer = length > max_size ? max_size : length;
length -= this_xfer;
/* setup the retry counter */
maxtry = 10;
/* set up the transfer loop */
do {
/* transfer the data */
debug("Bulk xfer 0x%lx(%d) try #%d\n",
(ulong)map_to_sysmem(buf), this_xfer,
11 - maxtry);
this_xfer, &partial,
USB_CNTL_TIMEOUT * 5);
debug("bulk_msg returned %d xferred %d/%d\n",
result, partial, this_xfer);
if (us->pusb_dev->status != 0) {
/* if we stall, we need to clear it before
* we go on
*/
display_int_status(us->pusb_dev->status);
#endif
if (us->pusb_dev->status & USB_ST_STALLED) {
debug("stalled ->clearing endpoint" \
"halt for pipe 0x%x\n", pipe);
stat = us->pusb_dev->status;
usb_clear_halt(us->pusb_dev, pipe);
us->pusb_dev->status = stat;
if (this_xfer == partial) {
debug("bulk transferred" \
"with error %lX," \
" but data ok\n",
us->pusb_dev->status);
return 0;
}
else
return result;
}
if (us->pusb_dev->status & USB_ST_NAK_REC) {
debug("Device NAKed bulk_msg\n");
debug("bulk transferred with error");
debug(" %ld, but data ok\n",
us->pusb_dev->status);
return 0;
}
/* if our try counter reaches 0, bail out */
debug(" %ld, data %d\n",
us->pusb_dev->status, partial);
if (!maxtry--)
return result;
}
/* update to show what data was transferred */
this_xfer -= partial;
buf += partial;
/* continue until this transfer is done */
}
/* if we get here, we're done and successful */
return 0;
}
static int usb_stor_BBB_reset(struct us_data *us)
{
int result;
unsigned int pipe;
/*
* Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
*
* For Reset Recovery the host shall issue in the following order:
* a) a Bulk-Only Mass Storage Reset
* b) a Clear Feature HALT to the Bulk-In endpoint
* c) a Clear Feature HALT to the Bulk-Out endpoint
*
* This is done in 3 steps.
*
* If the reset doesn't succeed, the device should be port reset.
*
* This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
*/
debug("BBB_reset\n");
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
US_BBB_RESET,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
debug("RESET:stall\n");
/* long wait for reset */
debug("BBB_reset result %d: status %lX reset\n",
result, us->pusb_dev->status);
pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
result = usb_clear_halt(us->pusb_dev, pipe);
/* long wait for reset */
debug("BBB_reset result %d: status %lX clearing IN endpoint\n",
result, us->pusb_dev->status);
/* long wait for reset */
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
result = usb_clear_halt(us->pusb_dev, pipe);
debug("BBB_reset result %d: status %lX clearing OUT endpoint\n",
result, us->pusb_dev->status);
debug("BBB_reset done\n");
/* FIXME: this reset function doesn't really reset the port, and it
* should. Actually it should probably do what it's doing here, and
* reset the port physically
*/
static int usb_stor_CB_reset(struct us_data *us)
{
unsigned char cmd[12];
int result;
debug("CB_reset\n");
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
US_CBI_ADSC,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, cmd, sizeof(cmd),
USB_CNTL_TIMEOUT * 5);
debug("CB_reset result %d: status %lX clearing endpoint halt\n",
result, us->pusb_dev->status);
usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
debug("CB_reset done\n");
/*
* Set up the command for a BBB device. Note that the actual SCSI
* command is copied into cbw.CBWCDB.
*/
static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us)
{
int result;
int actlen;
int dir_in;
unsigned int pipe;
ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
dir_in = US_DIRECTION(srb->cmd[0]);
#ifdef BBB_COMDAT_TRACE
printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p\n",
dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
srb->pdata);
for (result = 0; result < srb->cmdlen; result++)
printf("cmd[%d] %#x ", result, srb->cmd[result]);
printf("\n");
}
#endif
/* sanity checks */
if (!(srb->cmdlen <= CBWCDBLENGTH)) {
debug("usb_stor_BBB_comdat:cmdlen too large\n");
return -1;
}
/* always OUT to the ep */
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE);
cbw->dCBWTag = cpu_to_le32(CBWTag++);
cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen);
cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
cbw->bCBWLUN = srb->lun;
cbw->bCDBLength = srb->cmdlen;
/* copy the command data into the CBW command data buffer */
/* DST SRC LEN!!! */
memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE,
debug("usb_stor_BBB_comdat:usb_bulk_msg error\n");
return result;
}
/* FIXME: we also need a CBI_command which sets up the completion
* interrupt, and waits for it
*/
static int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
retry = 5;
dir_in = US_DIRECTION(srb->cmd[0]);
if (dir_in)
pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
else
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
while (retry--) {
debug("CBI gets a command: Try %d\n", 5 - retry);
#ifdef DEBUG
usb_show_srb(srb);
#endif
/* let's send the command via the control pipe */
result = usb_control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev , 0),
US_CBI_ADSC,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
srb->cmd, srb->cmdlen,
USB_CNTL_TIMEOUT * 5);
debug("CB_transport: control msg returned %d, status %lX\n",
result, us->pusb_dev->status);
/* check the return code for the command */
if (result < 0) {
if (us->pusb_dev->status & USB_ST_STALLED) {
status = us->pusb_dev->status;
debug(" stall during command found," \
" clear pipe\n");
usb_clear_halt(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev, 0));
us->pusb_dev->status = status;
debug(" error during command %02X" \
" Stat = %lX\n", srb->cmd[0],
us->pusb_dev->status);
return result;
}
/* transfer the data payload for this command, if one exists*/
debug("CB_transport: control msg returned %d," \
" direction is %s to go 0x%lx\n", result,
dir_in ? "IN" : "OUT", srb->datalen);
result = us_one_transfer(us, pipe, (char *)srb->pdata,
srb->datalen);
debug("CBI attempted to transfer data," \
" result is %d status %lX, len %d\n",
result, us->pusb_dev->status,
us->pusb_dev->act_len);
if (!(us->pusb_dev->status & USB_ST_NAK_REC))
break;
} /* if (srb->datalen) */
else
break;
}
/* return result */
return result;
}
static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
(void *) &us->ip_data, us->irqmaxp, us->irqinterval);
timeout = 1000;
while (timeout--) {
if (us->ip_wanted == 0)
printf(" Did not get interrupt on CBI\n");
us->ip_wanted = 0;
return USB_STOR_TRANSPORT_ERROR;
}
debug("Got interrupt data 0x%x, transferred %d status 0x%lX\n",
us->ip_data, us->pusb_dev->irq_act_len,
us->pusb_dev->irq_status);
/* UFI gives us ASC and ASCQ, like a request sense */
if (us->subclass == US_SC_UFI) {
if (srb->cmd[0] == SCSI_REQ_SENSE ||
srb->cmd[0] == SCSI_INQUIRY)
return USB_STOR_TRANSPORT_GOOD; /* Good */
else if (us->ip_data)
return USB_STOR_TRANSPORT_FAILED;
}
/* otherwise, we interpret the data normally */
switch (us->ip_data) {
case 0x0001:
return USB_STOR_TRANSPORT_GOOD;
case 0x0002:
return USB_STOR_TRANSPORT_FAILED;
default:
return USB_STOR_TRANSPORT_ERROR;
} /* switch */
return USB_STOR_TRANSPORT_ERROR;
}
#define USB_TRANSPORT_UNKNOWN_RETRY 5
#define USB_TRANSPORT_NOT_READY_RETRY 10
/* clear a stall on an endpoint - special for BBB devices */
static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
{
int result;
/* ENDPOINT_HALT = 0, so set value to 0 */
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
return result;
}
static int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
{
int result, retry;
int dir_in;
int actlen, data_actlen;
unsigned int pipe, pipein, pipeout;
ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
#ifdef BBB_XPORT_TRACE
unsigned char *ptr;
int index;
#endif
dir_in = US_DIRECTION(srb->cmd[0]);
/* COMMAND phase */
debug("COMMAND phase\n");
result = usb_stor_BBB_comdat(srb, us);
if (result < 0) {
debug("failed to send CBW status %ld\n",
us->pusb_dev->status);
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
}
if (!(us->flags & USB_READY))
mdelay(5);
pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
/* DATA phase + error handling */
data_actlen = 0;
/* no data, go immediately to the STATUS phase */
if (srb->datalen == 0)
goto st;
debug("DATA phase\n");
if (dir_in)
pipe = pipein;
else
pipe = pipeout;
result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
&data_actlen, USB_CNTL_TIMEOUT * 5);
/* special handling of STALL in DATA phase */
if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
debug("DATA:stall\n");
/* clear the STALL on the endpoint */
result = usb_stor_BBB_clear_endpt_stall(us,
dir_in ? us->ep_in : us->ep_out);
if (result >= 0)
/* continue on to STATUS phase */
goto st;
}
if (result < 0) {
debug("usb_bulk_msg error status %ld\n",
us->pusb_dev->status);
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
}
#ifdef BBB_XPORT_TRACE
for (index = 0; index < data_actlen; index++)
printf("pdata[%d] %#x ", index, srb->pdata[index]);
printf("\n");
#endif
/* STATUS phase + error handling */
debug("STATUS phase\n");
result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE,
&actlen, USB_CNTL_TIMEOUT*5);
/* special handling of STALL in STATUS phase */
if ((result < 0) && (retry < 1) &&
(us->pusb_dev->status & USB_ST_STALLED)) {
debug("STATUS:stall\n");
/* clear the STALL on the endpoint */
result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
if (result >= 0 && (retry++ < 1))
/* do a retry */
goto again;
}
if (result < 0) {
debug("usb_bulk_msg error status %ld\n",
us->pusb_dev->status);
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
}
#ifdef BBB_XPORT_TRACE
for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
printf("ptr[%d] %#x ", index, ptr[index]);
printf("\n");
#endif
/* misuse pipe to get the residue */
pipe = le32_to_cpu(csw->dCSWDataResidue);
if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
pipe = srb->datalen - data_actlen;
if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) {
debug("!CSWSIGNATURE\n");
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) {
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if (csw->bCSWStatus > CSWSTATUS_PHASE) {
debug(">PHASE\n");
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if (csw->bCSWStatus == CSWSTATUS_PHASE) {
debug("=PHASE\n");
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
} else if (data_actlen > srb->datalen) {
debug("transferred %dB instead of %ldB\n",
data_actlen, srb->datalen);
return USB_STOR_TRANSPORT_FAILED;
} else if (csw->bCSWStatus == CSWSTATUS_FAILED) {
debug("FAILED\n");
return USB_STOR_TRANSPORT_FAILED;
}
return result;
}
static int usb_stor_CB_transport(ccb *srb, struct us_data *us)
psrb = &reqsrb;
status = USB_STOR_TRANSPORT_GOOD;
retry = 0;
notready = 0;
debug("command / Data returned %d, status %lX\n",
result, us->pusb_dev->status);
if (us->protocol == US_PR_CBI) {
status = usb_stor_CBI_get_status(srb, us);
debug(" USB CBI Command Error\n");
srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
if (!us->ip_data) {
/* if the status is good, report it */
if (status == USB_STOR_TRANSPORT_GOOD) {
debug(" USB CBI Command Good\n");
return status;
}
}
}
/* do we have to issue an auto request? */
/* HERE we have to check the result */
if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
debug("ERROR %lX\n", us->pusb_dev->status);
us->transport_reset(us);
return USB_STOR_TRANSPORT_ERROR;
}
if ((us->protocol == US_PR_CBI) &&
((srb->cmd[0] == SCSI_REQ_SENSE) ||
(srb->cmd[0] == SCSI_INQUIRY))) {
/* do not issue an autorequest after request sense */
debug("No auto request and good\n");
return USB_STOR_TRANSPORT_GOOD;
}
/* issue an request_sense */
memset(&psrb->cmd[0], 0, 12);
psrb->cmd[0] = SCSI_REQ_SENSE;
psrb->cmd[1] = srb->lun << 5;
psrb->cmd[4] = 18;
psrb->datalen = 18;
psrb->pdata = &srb->sense_buf[0];
debug("auto request returned %d\n", result);
if (us->protocol == US_PR_CBI)
status = usb_stor_CBI_get_status(psrb, us);
if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
debug(" AUTO REQUEST ERROR %ld\n",
us->pusb_dev->status);
debug("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
srb->sense_buf[0], srb->sense_buf[2],
srb->sense_buf[12], srb->sense_buf[13]);
if ((srb->sense_buf[2] == 0) &&
(srb->sense_buf[12] == 0) &&
(srb->sense_buf[13] == 0)) {
/* ok, no sense */
switch (srb->sense_buf[2]) {
case 0x01:
/* Recovered Error */
return USB_STOR_TRANSPORT_GOOD;
case 0x02:
/* Not Ready */
if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
" 0x%02X (NOT READY)\n", srb->cmd[0],
srb->sense_buf[0], srb->sense_buf[2],
srb->sense_buf[12], srb->sense_buf[13]);
return USB_STOR_TRANSPORT_FAILED;
} else {
goto do_retry;
}
break;
default:
if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
" 0x%02X\n", srb->cmd[0], srb->sense_buf[0],
srb->sense_buf[2], srb->sense_buf[12],
srb->sense_buf[13]);
return USB_STOR_TRANSPORT_FAILED;
goto do_retry;
break;
static int usb_inquiry(ccb *srb, struct us_data *ss)
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_INQUIRY;
srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 36;
srb->datalen = 36;
srb->cmdlen = 12;
i = ss->transport(srb, ss);
debug("inquiry returns %d\n", i);
printf("error in inquiry\n");
return -1;
}
return 0;
}
static int usb_request_sense(ccb *srb, struct us_data *ss)
ptr = (char *)srb->pdata;
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_REQ_SENSE;
srb->cmd[1] = srb->lun << 5;
srb->pdata = &srb->sense_buf[0];
srb->cmdlen = 12;
ss->transport(srb, ss);
debug("Request Sense returned %02X %02X %02X\n",
srb->sense_buf[2], srb->sense_buf[12],
srb->sense_buf[13]);
static int usb_test_unit_ready(ccb *srb, struct us_data *ss)