usbmsc: Add USBMSC_NOT_STALL_BULKEP for RP2040 workaround

The new configuration CONFIG_USBMSC_NOT_STALL_BULKEP avoids to go into
stall state when :
- Receiving SCSI_CMD_INQUIRY with flags or pagecode != 0
- Receiving SCSI_CMD_MODESENSE6 and return the result data shorter than
  the requested data size.
Instead of stall, it just ignores the error condition.

Originally the usb driver goes into the stall under the conditions
mentioned above to inform to the USB host that the requested SCSI feature
is not supported, or the result data is shorter than the requested data
size.
But, at this moment, RP2040 USB device driver cannot handle entering and
leaving stall state of the bulk endpoints well.  Once stalls, the host -
device communication stops and cannot be resumed.

I have investigated to solve the issue and found that the existing
RP2040 USB device driver implementation, TinyUSB
(https://github.com/hathach/tinyusb) mass-storage class driver doesn't
enter the stall state like the treatment of this patch.

So, I introduce this new configuration as the RP2040 workaround.
In the future, when the RP2040 USB device driver is fixed and can handle
the bulk endpoint stall correctly, this patch should be reverted.
This commit is contained in:
Yuichi Nakamura 2021-06-13 23:58:22 +09:00 committed by Alan Carvalho de Assis
parent e00546335d
commit 8d722709cd
2 changed files with 23 additions and 0 deletions

View File

@ -852,6 +852,14 @@ config USBMSC_SCSI_STACKSIZE
Stack size used with the SCSI kernel thread. The default value
is not tuned.
config USBMSC_NOT_STALL_BULKEP
bool "Not stall USBMSC bulk endpoints for workaround"
default n
---help---
Not stall USBMSC bulk endpoints in some conditions.
Because RP2040 usbdev driver cannot handle stalling/resuming bulk
endpoints well, this workaround is required.
endif
menuconfig RNDIS

View File

@ -663,12 +663,14 @@ static inline int usbmsc_cmdinquiry(FAR struct usbmsc_dev_s *priv,
response->qualtype = SCSIRESP_INQUIRYPQ_NOTCAPABLE |
SCSIRESP_INQUIRYPD_UNKNOWN;
}
#ifndef CONFIG_USBMSC_NOT_STALL_BULKEP
else if ((inquiry->flags != 0) || (inquiry->pagecode != 0))
{
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INQUIRYFLAGS), 0);
priv->lun->sd = SCSI_KCQIR_INVALIDFIELDINCBA;
ret = -EINVAL;
}
#endif
else
{
memset(response, 0, SCSIRESP_INQUIRY_SIZEOF);
@ -822,7 +824,9 @@ static int inline usbmsc_cmdmodesense6(FAR struct usbmsc_dev_s *priv,
(FAR struct scsicmd_modesense6_s *)priv->cdb;
FAR struct scsiresp_modeparameterhdr6_s *mph =
(FAR struct scsiresp_modeparameterhdr6_s *)buf;
#ifndef CONFIG_USBMSC_NOT_STALL_BULKEP
int mdlen;
#endif
int ret;
priv->u.alloclen = modesense->alloclen;
@ -830,6 +834,11 @@ static int inline usbmsc_cmdmodesense6(FAR struct usbmsc_dev_s *priv,
USBMSC_FLAGS_DIRDEVICE2HOST);
if (ret == OK)
{
#ifdef CONFIG_USBMSC_NOT_STALL_BULKEP
priv->residue = priv->cbwlen = priv->nreqbytes =
SCSIRESP_MODEPARAMETERHDR6_SIZEOF;
#endif
if ((modesense->flags & ~SCSICMD_MODESENSE6_DBD) != 0 ||
modesense->subpgcode != 0)
{
@ -851,6 +860,7 @@ static int inline usbmsc_cmdmodesense6(FAR struct usbmsc_dev_s *priv,
(priv->lun->readonly ? SCSIRESP_MODEPARMHDR_DAPARM_WP : 0x00);
mph->bdlen = 0; /* Block descriptor length */
#ifndef CONFIG_USBMSC_NOT_STALL_BULKEP
/* There are no block descriptors, only the following mode page: */
ret = usbmsc_modepage(priv,
@ -867,6 +877,7 @@ static int inline usbmsc_cmdmodesense6(FAR struct usbmsc_dev_s *priv,
priv->nreqbytes =
mdlen + SCSIRESP_MODEPARAMETERHDR6_SIZEOF;
}
#endif
}
}
@ -2584,6 +2595,7 @@ static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv)
if (priv->residue > 0)
{
#ifndef CONFIG_USBMSC_NOT_STALL_BULKEP
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CMDFINISHRESIDUE),
(uint16_t)priv->residue);
@ -2601,6 +2613,9 @@ static int usbmsc_cmdfinishstate(FAR struct usbmsc_dev_s *priv)
nxsig_usleep (100000);
#else
EP_STALL(priv->epbulkin);
#endif
#else
priv->residue = 0;
#endif
}
}