Skip to content

Commit af1c81f

Browse files
committed
tests: usbh: msc: MSC improvements
- Small extension to MSC test case - Fixed error paths and code style in driver - Fixed a deallocation bug, tested with MAX3421E - If a transfer is cancelled it shouldn't be deallocated by the upper driver, the host driver may still need to use it. It must be freed by the callback. - Other host drivers use `-EPIPE` to signal a stall, aligned Renesas driver. - Verified the MSC test with the MAX3421E. Signed-off-by: Mattia Maldini <mattia.m@embedd.it> Signed-off-by: Valentyn Gololobov <val@embedd.it>
1 parent beb7d4b commit af1c81f

5 files changed

Lines changed: 126 additions & 76 deletions

File tree

drivers/usb/uhc/uhc_renesas_ra.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,11 @@ static int uhc_renesas_ra_event_xfer_complete(const struct device *dev, usbh_eve
291291

292292
switch (hal_evt->complete.result) {
293293
case USB_XFER_RESULT_STALLED:
294-
uhc_xfer_return(dev, priv->last_xfer, -ENOTSUP);
294+
uhc_xfer_return(dev, priv->last_xfer, -EPIPE);
295295
ret = -EAGAIN;
296-
break;
297296
case USB_XFER_RESULT_TIMEOUT:
298297
case USB_XFER_RESULT_FAILED:
299-
uhc_xfer_return(dev, priv->last_xfer, -EPIPE);
298+
uhc_xfer_return(dev, priv->last_xfer, -EIO);
300299
ret = -EAGAIN;
301300
break;
302301
case USB_XFER_RESULT_SUCCESS: {

subsys/usb/host/class/usbh_msc.c

Lines changed: 76 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ struct scsi_cbw {
6969
/* Size of the attached command block data */
7070
size_t command_block_length;
7171
/* Command block data */
72-
uint8_t const *command_block;
72+
const uint8_t *command_block;
7373
/* Data phase transfer length */
7474
size_t data_transfer_length;
7575
};
@@ -168,13 +168,20 @@ static int clear_feature_endpoint_halt(struct driver_data *driver_data, uint8_t
168168
*/
169169
static int sync_cb(struct usb_device *const udev, struct uhc_transfer *const xfer)
170170
{
171-
ARG_UNUSED(udev);
172171
struct driver_data *driver_data = xfer->priv;
173172

174173
if (xfer->err != 0) {
175174
LOG_DBG("Request finished %p, err %d, sem %i", xfer, xfer->err,
176175
k_sem_count_get(&driver_data->sync));
177176
}
177+
/* If the transfer was cancelled we deallocate it here */
178+
else if (xfer->err == -ECONNRESET) {
179+
LOG_INF("Transfer %p cancelled", (void *)xfer);
180+
usbh_xfer_free(udev, xfer);
181+
182+
return 0;
183+
}
184+
178185
k_sem_give(&driver_data->sync);
179186

180187
return 0;
@@ -188,17 +195,17 @@ static int sync_cb(struct usb_device *const udev, struct uhc_transfer *const xfe
188195
*/
189196
static int wait_for_sync(struct driver_data *driver_data, struct uhc_transfer *xfer)
190197
{
191-
if (k_sem_take(&driver_data->sync, K_MSEC(SCSI_REQ_TIMEOUT)) != 0) {
192-
int result = 0;
198+
int result = 0;
193199

200+
if (k_sem_take(&driver_data->sync, K_MSEC(100u)) != 0) {
194201
LOG_ERR("Timeout");
195202

196203
result = usbh_xfer_dequeue(driver_data->udev, xfer);
197204
/* While the semaphore take timed out, the transfer was actually already
198205
* done and the callback on its way. */
199206
if (result == -EALREADY) {
200207
/* Take the semaphore again to be sure that the callback is done */
201-
if (k_sem_take(&driver_data->sync, K_MSEC(SCSI_REQ_TIMEOUT)) != 0) {
208+
if (k_sem_take(&driver_data->sync, K_MSEC(100u)) != 0) {
202209
/* Should not happen */
203210
LOG_ERR("Double timeout");
204211
}
@@ -207,11 +214,22 @@ static int wait_for_sync(struct driver_data *driver_data, struct uhc_transfer *x
207214
else if (result != 0) {
208215
LOG_ERR("Failed to cancel transfer");
209216
}
217+
/* Dequeue succeeded, do nothing */
218+
else {
219+
}
220+
221+
/* The USB host driver may still need to work with the transfer, so we leave it to
222+
* the callback to deallocate it.
223+
*/
210224

211225
return -ETIMEDOUT;
226+
} else {
227+
/* The transfer was successful, store the result and free it */
228+
result = xfer->err;
229+
usbh_xfer_free(driver_data->udev, xfer);
212230
}
213231

214-
return xfer->err;
232+
return result;
215233
}
216234

217235
/*
@@ -276,10 +294,11 @@ static int scsi_transfer_data(struct driver_data *driver_data, size_t data_lengt
276294
result = usbh_xfer_enqueue(driver_data->udev, xfer);
277295
if (result != 0) {
278296
LOG_ERR("Unable to enqueue the transfer: %i", result);
297+
usbh_xfer_free(driver_data->udev, xfer);
279298
goto error_cleanup;
280299
}
281300

282-
/* Wait for completion */
301+
/* Wait for completion, deallocation handled automatically */
283302
result = wait_for_sync(driver_data, xfer);
284303
if (result != 0) {
285304
goto error_cleanup;
@@ -296,7 +315,6 @@ static int scsi_transfer_data(struct driver_data *driver_data, size_t data_lengt
296315
error_cleanup:
297316
/* Done with the buffer and transfer */
298317
usbh_xfer_buf_free(driver_data->udev, xfer->buf);
299-
usbh_xfer_free(driver_data->udev, xfer);
300318
return result;
301319
}
302320

@@ -311,7 +329,7 @@ static int scsi_read_status(struct driver_data *driver_data, struct scsi_csw *cs
311329

312330
result = scsi_transfer_data(driver_data, sizeof(buffer), buffer, SCSI_DIRECTION_DATA_IN);
313331
/* Stall, clear in endpoint and retry once */
314-
if (result == -ENOTSUP) {
332+
if (result == -EPIPE) {
315333
LOG_DBG("CSW stalled, clearing endpoint and retrying...");
316334
result = clear_feature_endpoint_halt(driver_data,
317335
driver_data->in_bulk_ep->bEndpointAddress);
@@ -406,14 +424,15 @@ static int scsi_command(struct driver_data *driver_data, struct scsi_cbw cbw)
406424
result = usbh_xfer_enqueue(driver_data->udev, xfer);
407425
if (result != 0) {
408426
LOG_ERR("Unable to enqueue the transfer: %i", result);
427+
usbh_xfer_free(driver_data->udev, xfer);
409428
goto error_cleanup;
410429
}
411430

431+
/* Wait for completion, deallocation handled automatically */
412432
result = wait_for_sync(driver_data, xfer);
413433

414434
error_cleanup:
415435
usbh_xfer_buf_free(driver_data->udev, xfer->buf);
416-
usbh_xfer_free(driver_data->udev, xfer);
417436
return result;
418437
}
419438

@@ -461,7 +480,7 @@ static int scsi_transaction(struct driver_data *driver_data, struct scsi_cbw cbw
461480
cbw.direction);
462481
/* The device stalled the transaction; it's a valid response, we should just
463482
* clear the endpoint and continue with the status to check what happened */
464-
if (result == -ENOTSUP) {
483+
if (result == -EPIPE) {
465484
/* Pick the target endpoint */
466485
uint8_t endpoint_address =
467486
get_endpoint_for_direction(driver_data, cbw.direction);
@@ -486,6 +505,7 @@ static int scsi_transaction(struct driver_data *driver_data, struct scsi_cbw cbw
486505

487506
/* Wrong tag */
488507
if (csw.tag != driver_data->tag) {
508+
result = -EIO;
489509
LOG_ERR("Mismatching CBW and CSW tags: 0x%04X vs 0x%04X", driver_data->tag,
490510
csw.tag);
491511
continue;
@@ -548,6 +568,8 @@ static int scsi_request_sense(struct driver_data *driver_data, struct scsi_sense
548568
.command_block = command_block,
549569
.data_transfer_length = sizeof(buffer),
550570
};
571+
/* We need data up to the 14th byte */
572+
const size_t required_sense_data = 14u;
551573

552574
result = scsi_transaction(driver_data, cbw, buffer, true);
553575

@@ -556,17 +578,17 @@ static int scsi_request_sense(struct driver_data *driver_data, struct scsi_sense
556578
return result;
557579
}
558580
/* Not enough data */
559-
else if (result < 14) {
581+
else if (result < required_sense_data) {
560582
LOG_ERR("Not enough sense data: %i", result);
561583
return -EIO;
562584
}
563585

564586
/* See SPC document, section 4.4 */
565-
sense_data->valid = (buffer[0] & 0x80) > 0;
566-
sense_data->response_code = buffer[0] & 0x7F;
567-
sense_data->sense_key = buffer[2] & 0xF;
568-
sense_data->additional_sense_code = buffer[12];
569-
sense_data->additional_sense_code_qualifier = buffer[13];
587+
sense_data->valid = (buffer[0u] & 0x80u) > 0u;
588+
sense_data->response_code = buffer[0u] & 0x7Fu;
589+
sense_data->sense_key = buffer[2u] & 0xFu;
590+
sense_data->additional_sense_code = buffer[12u];
591+
sense_data->additional_sense_code_qualifier = buffer[13u];
570592

571593
return 0;
572594
}
@@ -729,6 +751,8 @@ static int mode_sense_6(struct driver_data *driver_data, uint8_t lun_index)
729751
SCSI_MODE_SENSE_DATA_LENGTH & 0xFFu, /* Data length */
730752
0u,
731753
};
754+
/* We need data up to the 4th byte */
755+
const size_t required_sense_data = 4u;
732756

733757
struct scsi_cbw cbw = {
734758
.lun = lun_index,
@@ -750,7 +774,7 @@ static int mode_sense_6(struct driver_data *driver_data, uint8_t lun_index)
750774
return result;
751775
}
752776
/* Not enough data */
753-
else if (result < 4) {
777+
else if (result < required_sense_data) {
754778
LOG_ERR("Not enough mode data: %i", result);
755779
return -EIO;
756780
}
@@ -866,7 +890,7 @@ static int synchronize_cache(struct driver_data *driver_data, uint8_t lun_index)
866890
}
867891
}
868892

869-
return 0;
893+
return result;
870894
}
871895
#endif /* CONFIG_USBH_MSC_IGNORE_SYNC */
872896

@@ -931,7 +955,7 @@ static int read_blocks(struct driver_data *driver_data, uint8_t lun_index, uint3
931955
* Write a number of blocks to a logical unit.
932956
*/
933957
static int write_blocks(struct driver_data *driver_data, uint8_t lun_index, uint32_t lba,
934-
uint16_t block_count, uint8_t const *buffer)
958+
uint16_t block_count, const uint8_t *buffer)
935959
{
936960
int result = 0;
937961
uint32_t transfer_length =
@@ -1002,7 +1026,7 @@ static int get_max_lun(struct driver_data *driver_data)
10021026
result = usbh_req_setup(driver_data->udev, bmRequestType, GET_MAX_LUN, 0,
10031027
driver_data->target_iface, 1, buf);
10041028
/* A stalled GET_MAX_LUN request shall be interpreted as a unique unit */
1005-
if (result == -ENOTSUP) {
1029+
if (result == -EPIPE) {
10061030
driver_data->max_logical_unit = 0;
10071031
result = 0;
10081032
}
@@ -1121,19 +1145,23 @@ static int scan_interface_endpoints(struct driver_data *driver_data, uint8_t ifa
11211145
if (desc->bDescriptorType == USB_DESC_ENDPOINT) {
11221146
ep_desc = (const void *)desc;
11231147

1124-
/* Input bulk endpoint */
1125-
if (USB_EP_DIR_IS_IN(ep_desc->bEndpointAddress) &&
1126-
driver_data->in_bulk_ep == NULL) {
1127-
LOG_DBG("Input bulk endpoint: 0x%02X",
1128-
ep_desc->bEndpointAddress);
1129-
driver_data->in_bulk_ep = ep_desc;
1130-
}
1131-
/* Output bulk endpoint */
1132-
else if (USB_EP_DIR_IS_OUT(ep_desc->bEndpointAddress) &&
1133-
driver_data->out_bulk_ep == NULL) {
1134-
LOG_DBG("Output bulk endpoint: 0x%02X",
1135-
ep_desc->bEndpointAddress);
1136-
driver_data->out_bulk_ep = ep_desc;
1148+
/* Only pick bulk endpoints */
1149+
if ((ep_desc->bmAttributes & USB_EP_TRANSFER_TYPE_MASK) ==
1150+
USB_EP_TYPE_BULK) {
1151+
/* Input bulk endpoint */
1152+
if (USB_EP_DIR_IS_IN(ep_desc->bEndpointAddress) &&
1153+
driver_data->in_bulk_ep == NULL) {
1154+
LOG_DBG("Input bulk endpoint: 0x%02X",
1155+
ep_desc->bEndpointAddress);
1156+
driver_data->in_bulk_ep = ep_desc;
1157+
}
1158+
/* Output bulk endpoint */
1159+
else if (USB_EP_DIR_IS_OUT(ep_desc->bEndpointAddress) &&
1160+
driver_data->out_bulk_ep == NULL) {
1161+
LOG_DBG("Output bulk endpoint: 0x%02X",
1162+
ep_desc->bEndpointAddress);
1163+
driver_data->out_bulk_ep = ep_desc;
1164+
}
11371165
}
11381166

11391167
ep_count++;
@@ -1268,6 +1296,12 @@ static int disk_access_read(struct disk_info *disk, uint8_t *data_buf, uint32_t
12681296
struct driver_data *driver_data = lun_data->driver_data;
12691297
int result = 0;
12701298

1299+
if (num_sector > 0xFFFF) {
1300+
LOG_ERR("Cannot read more than 65535 sectors, and %" PRIu32 " were requested",
1301+
num_sector);
1302+
return -EINVAL;
1303+
}
1304+
12711305
k_mutex_lock(&driver_data->lock, K_FOREVER);
12721306
if (start_sector + num_sector > lun_data->last_logical_block_address + 1) {
12731307
k_mutex_unlock(&driver_data->lock);
@@ -1292,6 +1326,12 @@ static int disk_access_write(struct disk_info *disk, const uint8_t *data_buf, ui
12921326
struct driver_data *driver_data = lun_data->driver_data;
12931327
int result = 0;
12941328

1329+
if (num_sector > 0xFFFF) {
1330+
LOG_ERR("Cannot write more than 65535 sectors, and %" PRIu32 " were requested",
1331+
num_sector);
1332+
return -EINVAL;
1333+
}
1334+
12951335
k_mutex_lock(&driver_data->lock, K_FOREVER);
12961336
if (start_sector + num_sector > lun_data->last_logical_block_address + 1) {
12971337
k_mutex_unlock(&driver_data->lock);
@@ -1422,7 +1462,7 @@ static int usbh_msc_probe(struct usbh_class_data *const c_data, struct usb_devic
14221462
{
14231463
const struct device *dev = c_data->priv;
14241464
struct driver_data *driver_data = (void *)dev->data;
1425-
struct driver_config const *driver_config = (void *)dev->config;
1465+
const struct driver_config *driver_config = (void *)dev->config;
14261466
int result;
14271467

14281468
LOG_INF("MSC device connected");
@@ -1449,7 +1489,7 @@ static int usbh_msc_probe(struct usbh_class_data *const c_data, struct usb_devic
14491489
}
14501490

14511491
/* Fetch bulk endpoints */
1452-
result = scan_interface_endpoints(driver_data, iface);
1492+
result = scan_interface_endpoints(driver_data, driver_data->target_iface);
14531493
if (result != 0) {
14541494
LOG_ERR("Failed to scan endpoints: %d", result);
14551495
goto error_cleanup;

tests/subsys/usb/msc/prj.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,5 @@ CONFIG_FS_FATFS_CUSTOM_MOUNT_POINTS="RAM0,RAM1,USB0_0,USB0_1"
3838
CONFIG_USBH_MSC_LOG_LEVEL_DBG=y
3939
CONFIG_USBH_LOG_LEVEL_INF=y
4040
CONFIG_UHC_DRIVER_LOG_LEVEL_INF=y
41+
42+
CONFIG_DEBUG_OPTIMIZATIONS=y

0 commit comments

Comments
 (0)