diff --git a/devicemodel/hw/platform/usb_pmapper.c b/devicemodel/hw/platform/usb_pmapper.c index df3c577ae..449ddcb30 100644 --- a/devicemodel/hw/platform/usb_pmapper.c +++ b/devicemodel/hw/platform/usb_pmapper.c @@ -902,6 +902,36 @@ done: return xfer->status; } +static void +clear_uas_desc(struct usb_dev *udev, uint8_t *data, uint32_t len) +{ + struct usb_devpath *path; + int32_t i; + + /* only process configuration descriptor */ + if (len < 2 || data[1] != 0x2) + return; + + i = 0; + path = &udev->info.path; + while (i < len) { + /* When UAS protocol is found in interface descriptor, set it + * to invalid value. + * + * According to USB3 spec 9.6.5, Standard Interface Descriptor, + * data[i+0] => bLength + * data[i+1] => bDescriptorType + * data[i+7] => bInterfaceProtocol + */ + if (data[i] == 9 && data[i+1] == 0x4 && data[i+7] == 0x62) { + UPRINTF(LFTL, "%d-%s: clear uas protocol\r\n", + path->bus, usb_dev_path(path)); + data[i+7] = 0; + } + i = i + data[i]; + } +} + int usb_dev_request(void *pdata, struct usb_data_xfer *xfer) { @@ -914,6 +944,7 @@ usb_dev_request(void *pdata, struct usb_data_xfer *xfer) struct usb_data_xfer_block *blk; uint8_t *data; int rc; + bool need_chk_uas = false; udev = pdata; xfer->status = USB_ERR_NORMAL_COMPLETION; @@ -960,6 +991,10 @@ usb_dev_request(void *pdata, struct usb_data_xfer *xfer) UPRINTF(LDBG, "UR_SET_INTERFACE\n"); usb_dev_set_if(udev, index, value, xfer); goto out; + case UREQ(UR_GET_DESCRIPTOR, UT_READ): + if (value == 0x0200) + need_chk_uas = true; + break; case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): if (value) { /* according to usb spec (ch9), this is impossible */ @@ -985,6 +1020,13 @@ usb_dev_request(void *pdata, struct usb_data_xfer *xfer) rc = libusb_control_transfer(udev->handle, request_type, request, value, index, data, len, 300); + /* TODO: Currently, the USB Attached SCSI (UAS) protocol is not + * supported and the following code is used as a workaround now. + * UAS will be implemented in future. + */ + if (need_chk_uas) + clear_uas_desc(udev, data, rc); + if (rc >= 0 && blk) { blk->blen = len - rc; blk->bdone += rc;