Important fixed to USB storage and SCSI state machine from David Hewson

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2571 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2010-04-04 16:21:13 +00:00
parent 5a39e4e761
commit 7b7d120995
2 changed files with 92 additions and 57 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
* drivers/usbdev/usbdev_storage.c
*
* Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2008-2010 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Mass storage class device. Bulk-only with SCSI subclass.
@ -78,6 +78,21 @@
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* Race condition workaround found by David Hewson. This race condition
* "seems to relate to stalling the endpoint when a short response is
* generated which causes a residue to exist when the CSW would be returned.
* I think there's two issues here. The first being if the transfer which
* had just been queued before the stall had not completed then it wouldnt
* then complete once the endpoint was stalled? The second is that the
* subsequent transfer for the CSW would be dropped on the floor (by the
* epsubmit() function) if the end point was still stalled as the control
* transfer to resume it hadn't occurred."
*/
#define CONFIG_USBSTRG_RACEWAR 1
/****************************************************************************
* Private Types
****************************************************************************/
@ -1702,13 +1717,13 @@ static int usbstrg_cmdparsestate(FAR struct usbstrg_dev_s *priv)
* case SCSI_CMD_REASSIGNBLOCKS: * 0x07 Optional */
case SCSI_CMD_READ6: /* 0x08 Mandatory */
return usbstrg_cmdread6(priv);
ret = usbstrg_cmdread6(priv);
break;
/* * 0x09 Vendor specific */
case SCSI_CMD_WRITE6: /* 0x0a Optional */
return usbstrg_cmdwrite6(priv);
ret = usbstrg_cmdwrite6(priv);
break;
/* case SCSI_CMD_SEEK6: * 0x0b Obsolete
@ -1757,13 +1772,13 @@ static int usbstrg_cmdparsestate(FAR struct usbstrg_dev_s *priv)
/* * 0x26-27 Vendor specific */
case SCSI_CMD_READ10: /* 0x28 Mandatory */
return usbstrg_cmdread10(priv);
ret = usbstrg_cmdread10(priv);
break;
/* * 0x29 Vendor specific */
case SCSI_CMD_WRITE10: /* 0x2a Optional */
return usbstrg_cmdwrite10(priv);
ret = usbstrg_cmdwrite10(priv);
break;
/* case SCSI_CMD_SEEK10: * 0x2b Obsolete
@ -1839,11 +1854,11 @@ static int usbstrg_cmdparsestate(FAR struct usbstrg_dev_s *priv)
* case SCSI_CMD_MOVEMEDIUMATTACHED: * 0xa7 Optional (MCHNGR==0) */
case SCSI_CMD_READ12: /* 0xa8 Optional */
return usbstrg_cmdread12(priv);
ret = usbstrg_cmdread12(priv);
break;
case SCSI_CMD_WRITE12: /* 0xaa Optional */
return usbstrg_cmdwrite12(priv);
ret = usbstrg_cmdwrite12(priv);
break;
/* case SCSI_CMD_READMEDIASERIALNUMBER: * 0xab Optional
@ -1871,6 +1886,10 @@ static int usbstrg_cmdparsestate(FAR struct usbstrg_dev_s *priv)
}
pthread_mutex_unlock(&priv->mutex);
/* Is a response required? (Not for read6/10/12 and write6/10/12). */
if (priv->thstate == USBSTRG_STATE_CMDPARSE)
{
/* All commands come through this path (EXCEPT read6/10/12 and write6/10/12).
* For all other commands, the following setup is expected for the response
* based on data direction:
@ -1927,7 +1946,9 @@ static int usbstrg_cmdparsestate(FAR struct usbstrg_dev_s *priv)
usbtrace(TRACE_CLASSSTATE(USBSTRG_CLASSSTATE_CMDPARSECMDFINISH), priv->cdb[0]);
priv->thstate = USBSTRG_STATE_CMDFINISH;
return OK;
ret = OK;
}
return ret;
}
/****************************************************************************
@ -2301,7 +2322,21 @@ static int usbstrg_cmdfinishstate(FAR struct usbstrg_dev_s *priv)
if (priv->residue > 0)
{
usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_CMDFINISHRESIDUE), (uint16_t)priv->residue);
#ifdef CONFIG_USBSTRG_RACEWAR
/* (See description of the workaround at the top of the file).
* First, wait for the transfer to complete, then stall the endpoint
*/
usleep (100000);
(void)EP_STALL(priv->epbulkin);
/* now wait for stall to go away .... */
usleep (100000);
#else
(void)EP_STALL(priv->epbulkin);
#endif
}
}
break;
@ -2513,6 +2548,7 @@ void *usbstrg_workerthread(void *arg)
eventset = priv->theventset;
priv->theventset = USBSTRG_EVENT_NOEVENTS;
pthread_mutex_unlock(&priv->mutex);
/* Were we awakened by some event that requires immediate action?
*

View File

@ -1717,7 +1717,6 @@ int usbstrg_unbindlun(FAR void *handle, unsigned int lunno)
if (lun->inode == NULL)
{
usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_LUNNOTBOUND), 0);
pthread_mutex_lock(&priv->mutex);
ret = -EBUSY;
}
else