class: msc device: support multi lun

- support multi lun

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
This commit is contained in:
Zhihong Chen
2024-02-06 11:25:39 +08:00
committed by sakumisu
parent 3f89d1b003
commit 920b02cb7c
7 changed files with 73 additions and 55 deletions

View File

@@ -45,6 +45,10 @@
/* Enable test mode */
// #define CONFIG_USBDEV_TEST_MODE
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
#define CONFIG_USBDEV_MSC_MAX_LUN 1
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
#endif

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, sakumisu
* Copyright (c) 2024, zhihong chen
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -40,8 +41,8 @@ USB_NOCACHE_RAM_SECTION struct usbd_msc_priv {
uint8_t max_lun;
uint32_t start_sector;
uint32_t nsectors;
uint16_t scsi_blk_size;
uint32_t scsi_blk_nbr;
uint32_t scsi_blk_size[CONFIG_USBDEV_MSC_MAX_LUN];
uint32_t scsi_blk_nbr[CONFIG_USBDEV_MSC_MAX_LUN];
USB_MEM_ALIGNX uint8_t block_buffer[CONFIG_USBDEV_MSC_MAX_BUFSIZE];
@@ -52,6 +53,15 @@ USB_NOCACHE_RAM_SECTION struct usbd_msc_priv {
#endif
} g_usbd_msc;
#ifdef CONFIG_USBDEV_MSC_THREAD
static void usbdev_msc_thread(void *argument);
#endif
static void usdb_msc_set_max_lun(void)
{
g_usbd_msc.max_lun = CONFIG_USBDEV_MSC_MAX_LUN - 1u;
}
static void usbd_msc_reset(void)
{
g_usbd_msc.stage = MSC_READ_CBW;
@@ -448,15 +458,15 @@ static bool SCSI_readFormatCapacity(uint8_t **data, uint32_t *len)
0x00,
0x00,
0x08, /* Capacity List Length */
(uint8_t)((g_usbd_msc.scsi_blk_nbr >> 24) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_nbr >> 16) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_nbr >> 8) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_nbr >> 0) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] >> 24) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] >> 16) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] >> 8) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] >> 0) & 0xff),
0x02, /* Descriptor Code: Formatted Media */
0x00,
(uint8_t)((g_usbd_msc.scsi_blk_size >> 8) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size >> 0) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN] >> 8) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN] >> 0) & 0xff),
};
memcpy(*data, (uint8_t *)format_capacity, SCSIRESP_READFORMATCAPACITIES_SIZEOF);
@@ -472,15 +482,15 @@ static bool SCSI_readCapacity10(uint8_t **data, uint32_t *len)
}
uint8_t capacity10[SCSIRESP_READCAPACITY10_SIZEOF] = {
(uint8_t)(((g_usbd_msc.scsi_blk_nbr - 1) >> 24) & 0xff),
(uint8_t)(((g_usbd_msc.scsi_blk_nbr - 1) >> 16) & 0xff),
(uint8_t)(((g_usbd_msc.scsi_blk_nbr - 1) >> 8) & 0xff),
(uint8_t)(((g_usbd_msc.scsi_blk_nbr - 1) >> 0) & 0xff),
(uint8_t)(((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] - 1) >> 24) & 0xff),
(uint8_t)(((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] - 1) >> 16) & 0xff),
(uint8_t)(((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] - 1) >> 8) & 0xff),
(uint8_t)(((g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN] - 1) >> 0) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size >> 24) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size >> 16) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size >> 8) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size >> 0) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN] >> 24) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN] >> 16) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN] >> 8) & 0xff),
(uint8_t)((g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN] >> 0) & 0xff),
};
memcpy(*data, (uint8_t *)capacity10, SCSIRESP_READCAPACITY10_SIZEOF);
@@ -501,13 +511,13 @@ static bool SCSI_read10(uint8_t **data, uint32_t *len)
g_usbd_msc.nsectors = GET_BE16(&g_usbd_msc.cbw.CB[7]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc.nsectors);
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr) {
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN]) {
SCSI_SetSenseData(SCSI_KCQIR_LBAOUTOFRANGE);
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
if (g_usbd_msc.cbw.dDataLength != (g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size)) {
if (g_usbd_msc.cbw.dDataLength != (g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN])) {
USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
return false;
}
@@ -533,13 +543,13 @@ static bool SCSI_read12(uint8_t **data, uint32_t *len)
g_usbd_msc.nsectors = GET_BE32(&g_usbd_msc.cbw.CB[6]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc.nsectors);
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr) {
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN]) {
SCSI_SetSenseData(SCSI_KCQIR_LBAOUTOFRANGE);
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
if (g_usbd_msc.cbw.dDataLength != (g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size)) {
if (g_usbd_msc.cbw.dDataLength != (g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN])) {
USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
return false;
}
@@ -566,8 +576,8 @@ static bool SCSI_write10(uint8_t **data, uint32_t *len)
g_usbd_msc.nsectors = GET_BE16(&g_usbd_msc.cbw.CB[7]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc.nsectors);
data_len = g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size;
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr) {
data_len = g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN];
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN]) {
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
@@ -595,8 +605,8 @@ static bool SCSI_write12(uint8_t **data, uint32_t *len)
g_usbd_msc.nsectors = GET_BE32(&g_usbd_msc.cbw.CB[6]); /* Number of Blocks to transfer */
USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc.nsectors);
data_len = g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size;
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr) {
data_len = g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN];
if ((g_usbd_msc.start_sector + g_usbd_msc.nsectors) > g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN]) {
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
@@ -634,15 +644,15 @@ static bool SCSI_verify10(uint8_t **data, uint32_t *len)
lba = GET_BE32(&g_usbd_msc.cbw.CB[2]);
USB_LOG_DBG("lba: 0x%x\r\n", lba);
g_usbd_msc.scsi_blk_addr = lba * g_usbd_msc.scsi_blk_size;
g_usbd_msc.scsi_blk_addr = lba * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN];
/* Number of Blocks to transfer */
blk_num = GET_BE16(&g_usbd_msc.cbw.CB[7]);
USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
g_usbd_msc.scsi_blk_len = blk_num * g_usbd_msc.scsi_blk_size;
g_usbd_msc.scsi_blk_len = blk_num * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN];
if ((lba + blk_num) > g_usbd_msc.scsi_blk_nbr) {
if ((lba + blk_num) > g_usbd_msc.scsi_blk_nbr[g_usbd_msc.cbw.bLUN]) {
USB_LOG_ERR("LBA out of range\r\n");
return false;
}
@@ -662,17 +672,17 @@ static bool SCSI_processRead(void)
USB_LOG_DBG("read lba:%d\r\n", g_usbd_msc.start_sector);
transfer_len = MIN(g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size, CONFIG_USBDEV_MSC_MAX_BUFSIZE);
transfer_len = MIN(g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN], CONFIG_USBDEV_MSC_MAX_BUFSIZE);
if (usbd_msc_sector_read(g_usbd_msc.start_sector, g_usbd_msc.block_buffer, transfer_len) != 0) {
if (usbd_msc_sector_read(g_usbd_msc.cbw.bLUN, g_usbd_msc.start_sector, g_usbd_msc.block_buffer, transfer_len) != 0) {
SCSI_SetSenseData(SCSI_KCQHE_UREINRESERVEDAREA);
return false;
}
usbd_ep_start_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, g_usbd_msc.block_buffer, transfer_len);
g_usbd_msc.start_sector += (transfer_len / g_usbd_msc.scsi_blk_size);
g_usbd_msc.nsectors -= (transfer_len / g_usbd_msc.scsi_blk_size);
g_usbd_msc.start_sector += (transfer_len / g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN]);
g_usbd_msc.nsectors -= (transfer_len / g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN]);
g_usbd_msc.csw.dDataResidue -= transfer_len;
if (g_usbd_msc.nsectors == 0) {
@@ -687,19 +697,19 @@ static bool SCSI_processWrite(uint32_t nbytes)
uint32_t data_len = 0;
USB_LOG_DBG("write lba:%d\r\n", g_usbd_msc.start_sector);
if (usbd_msc_sector_write(g_usbd_msc.start_sector, g_usbd_msc.block_buffer, nbytes) != 0) {
if (usbd_msc_sector_write(g_usbd_msc.cbw.bLUN, g_usbd_msc.start_sector, g_usbd_msc.block_buffer, nbytes) != 0) {
SCSI_SetSenseData(SCSI_KCQHE_WRITEFAULT);
return false;
}
g_usbd_msc.start_sector += (nbytes / g_usbd_msc.scsi_blk_size);
g_usbd_msc.nsectors -= (nbytes / g_usbd_msc.scsi_blk_size);
g_usbd_msc.start_sector += (nbytes / g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN]);
g_usbd_msc.nsectors -= (nbytes / g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN]);
g_usbd_msc.csw.dDataResidue -= nbytes;
if (g_usbd_msc.nsectors == 0) {
usbd_msc_send_csw(CSW_STATUS_CMD_PASSED);
} else {
data_len = MIN(g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size, CONFIG_USBDEV_MSC_MAX_BUFSIZE);
data_len = MIN(g_usbd_msc.nsectors * g_usbd_msc.scsi_blk_size[g_usbd_msc.cbw.bLUN], CONFIG_USBDEV_MSC_MAX_BUFSIZE);
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, g_usbd_msc.block_buffer, data_len);
}
@@ -721,7 +731,7 @@ static bool SCSI_CBWDecode(uint32_t nbytes)
g_usbd_msc.csw.dTag = g_usbd_msc.cbw.dTag;
g_usbd_msc.csw.dDataResidue = g_usbd_msc.cbw.dDataLength;
if ((g_usbd_msc.cbw.bLUN > 1) || (g_usbd_msc.cbw.dSignature != MSC_CBW_Signature) || (g_usbd_msc.cbw.bCBLength < 1) || (g_usbd_msc.cbw.bCBLength > 16)) {
if ((g_usbd_msc.cbw.dSignature != MSC_CBW_Signature) || (g_usbd_msc.cbw.bCBLength < 1) || (g_usbd_msc.cbw.bCBLength > 16)) {
SCSI_SetSenseData(SCSI_KCQIR_INVALIDCOMMAND);
return false;
} else {
@@ -903,11 +913,14 @@ struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uin
memset((uint8_t *)&g_usbd_msc, 0, sizeof(struct usbd_msc_priv));
usbd_msc_get_cap(0, &g_usbd_msc.scsi_blk_nbr, &g_usbd_msc.scsi_blk_size);
usdb_msc_set_max_lun();
for (uint8_t i = 0u; i <= g_usbd_msc.max_lun; i++) {
usbd_msc_get_cap(i, &g_usbd_msc.scsi_blk_nbr[i], &g_usbd_msc.scsi_blk_size[i]);
if (g_usbd_msc.scsi_blk_size > CONFIG_USBDEV_MSC_MAX_BUFSIZE) {
USB_LOG_ERR("msc block buffer overflow\r\n");
return NULL;
if (g_usbd_msc.scsi_blk_size[i] > CONFIG_USBDEV_MSC_MAX_BUFSIZE) {
USB_LOG_ERR("msc block buffer overflow\r\n");
return NULL;
}
}
return intf;

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, sakumisu
* Copyright (c) 2024, zhihong chen
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -17,9 +18,9 @@ struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf,
const uint8_t out_ep,
const uint8_t in_ep);
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length);
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length);
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint32_t *block_size);
int usbd_msc_sector_read(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
int usbd_msc_sector_write(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
void usbd_msc_set_readonly(bool readonly);
bool usbd_msc_set_popup(void);

View File

@@ -375,19 +375,19 @@ typedef struct
BLOCK_TYPE mass_block[BLOCK_COUNT];
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
*block_num = 1000; //Pretend having so many buffer,not has actually.
*block_size = BLOCK_SIZE;
}
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_read(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
if (sector < 10)
memcpy(buffer, mass_block[sector].BlockSpace, length);
return 0;
}
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_write(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
if (sector < 10)
memcpy(mass_block[sector].BlockSpace, buffer, length);

View File

@@ -358,19 +358,19 @@ typedef struct
BLOCK_TYPE mass_block[BLOCK_COUNT];
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
*block_num = 1000; //Pretend having so many buffer,not has actually.
*block_size = BLOCK_SIZE;
}
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_read(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
if (sector < 10)
memcpy(buffer, mass_block[sector].BlockSpace, length);
return 0;
}
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_write(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
if (sector < 10)
memcpy(mass_block[sector].BlockSpace, buffer, length);

View File

@@ -130,19 +130,19 @@ typedef struct
BLOCK_TYPE mass_block[BLOCK_COUNT];
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
*block_num = 1000; //Pretend having so many buffer,not has actually.
*block_size = BLOCK_SIZE;
}
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_read(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
if (sector < BLOCK_COUNT)
memcpy(buffer, mass_block[sector].BlockSpace, length);
return 0;
}
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_write(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
if (sector < BLOCK_COUNT)
memcpy(mass_block[sector].BlockSpace, buffer, length);

View File

@@ -131,19 +131,19 @@ void usbd_event_handler(uint8_t event)
}
}
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
*block_num = BLOCK_COUNT;
*block_size = BLOCK_SIZE;
}
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_read(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
rt_device_read(blk_dev, sector, buffer, length / BLOCK_SIZE);
return 0;
}
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
int usbd_msc_sector_write(uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
rt_device_write(blk_dev, sector, buffer, length / BLOCK_SIZE);
return 0;