mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 01:22:07 +00:00
usb: gadget: mass_storage: support multi-luns with different logic block size
With Peiyu's patch "gadget: mass_storage: adapt logic block size to bound block devices" (http://www.spinics.net/lists/linux-usb/msg50791.html), now mass storage can adjust logic block size dynamically based on real devices. Then there is one issue caused by it, if two luns have different logic block size, mass storage can't work. Let's check the current software flow: 1. get_next_command(): call received_cbw(); 2. received_cbw(): update common->lun = cbw->Lun, but common->curlen is not updated; 3. do_scsi_command(): in READ_X and WRITE_X commands, common->data_size_from_cmnd is updated by common->curlun->blkbits; 4. check_command(): update common->curlun according to common->lun As you can see, the step 3 uses wrong common->curlun, then wrong common->curlun->blkbits. If the two luns have same blkbits, there isn't issue. Otherwise, both will fail. This patch moves the common->curlun update to step 1, then make sure step 3 gets right blkbits and data_size_from_cmnd. Cc: Peiyu Li <peiyu.li@csr.com> Signed-off-by: YuPing Luo <yuping.luo@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
b4fcea2a71
commit
144974e7f9
@ -1873,17 +1873,14 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
||||
common->lun, lun);
|
||||
|
||||
/* Check the LUN */
|
||||
if (common->lun < common->nluns) {
|
||||
curlun = &common->luns[common->lun];
|
||||
common->curlun = curlun;
|
||||
curlun = common->curlun;
|
||||
if (curlun) {
|
||||
if (common->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = SS_NO_SENSE;
|
||||
curlun->sense_data_info = 0;
|
||||
curlun->info_valid = 0;
|
||||
}
|
||||
} else {
|
||||
common->curlun = NULL;
|
||||
curlun = NULL;
|
||||
common->bad_lun_okay = 0;
|
||||
|
||||
/*
|
||||
@ -1929,6 +1926,17 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wrapper of check_command for data size in blocks handling */
|
||||
static int check_command_size_in_blocks(struct fsg_common *common,
|
||||
int cmnd_size, enum data_direction data_dir,
|
||||
unsigned int mask, int needs_medium, const char *name)
|
||||
{
|
||||
if (common->curlun)
|
||||
common->data_size_from_cmnd <<= common->curlun->blkbits;
|
||||
return check_command(common, cmnd_size, data_dir,
|
||||
mask, needs_medium, name);
|
||||
}
|
||||
|
||||
static int do_scsi_command(struct fsg_common *common)
|
||||
{
|
||||
struct fsg_buffhd *bh;
|
||||
@ -2011,9 +2019,9 @@ static int do_scsi_command(struct fsg_common *common)
|
||||
|
||||
case READ_6:
|
||||
i = common->cmnd[4];
|
||||
common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
|
||||
common->curlun->blkbits;
|
||||
reply = check_command(common, 6, DATA_DIR_TO_HOST,
|
||||
common->data_size_from_cmnd = (i == 0) ? 256 : i;
|
||||
reply = check_command_size_in_blocks(common, 6,
|
||||
DATA_DIR_TO_HOST,
|
||||
(7<<1) | (1<<4), 1,
|
||||
"READ(6)");
|
||||
if (reply == 0)
|
||||
@ -2022,9 +2030,9 @@ static int do_scsi_command(struct fsg_common *common)
|
||||
|
||||
case READ_10:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]) <<
|
||||
common->curlun->blkbits;
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command_size_in_blocks(common, 10,
|
||||
DATA_DIR_TO_HOST,
|
||||
(1<<1) | (0xf<<2) | (3<<7), 1,
|
||||
"READ(10)");
|
||||
if (reply == 0)
|
||||
@ -2033,9 +2041,9 @@ static int do_scsi_command(struct fsg_common *common)
|
||||
|
||||
case READ_12:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be32(&common->cmnd[6]) <<
|
||||
common->curlun->blkbits;
|
||||
reply = check_command(common, 12, DATA_DIR_TO_HOST,
|
||||
get_unaligned_be32(&common->cmnd[6]);
|
||||
reply = check_command_size_in_blocks(common, 12,
|
||||
DATA_DIR_TO_HOST,
|
||||
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
||||
"READ(12)");
|
||||
if (reply == 0)
|
||||
@ -2134,9 +2142,9 @@ static int do_scsi_command(struct fsg_common *common)
|
||||
|
||||
case WRITE_6:
|
||||
i = common->cmnd[4];
|
||||
common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
|
||||
common->curlun->blkbits;
|
||||
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
|
||||
common->data_size_from_cmnd = (i == 0) ? 256 : i;
|
||||
reply = check_command_size_in_blocks(common, 6,
|
||||
DATA_DIR_FROM_HOST,
|
||||
(7<<1) | (1<<4), 1,
|
||||
"WRITE(6)");
|
||||
if (reply == 0)
|
||||
@ -2145,9 +2153,9 @@ static int do_scsi_command(struct fsg_common *common)
|
||||
|
||||
case WRITE_10:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]) <<
|
||||
common->curlun->blkbits;
|
||||
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command_size_in_blocks(common, 10,
|
||||
DATA_DIR_FROM_HOST,
|
||||
(1<<1) | (0xf<<2) | (3<<7), 1,
|
||||
"WRITE(10)");
|
||||
if (reply == 0)
|
||||
@ -2156,9 +2164,9 @@ static int do_scsi_command(struct fsg_common *common)
|
||||
|
||||
case WRITE_12:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be32(&common->cmnd[6]) <<
|
||||
common->curlun->blkbits;
|
||||
reply = check_command(common, 12, DATA_DIR_FROM_HOST,
|
||||
get_unaligned_be32(&common->cmnd[6]);
|
||||
reply = check_command_size_in_blocks(common, 12,
|
||||
DATA_DIR_FROM_HOST,
|
||||
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
||||
"WRITE(12)");
|
||||
if (reply == 0)
|
||||
@ -2273,6 +2281,10 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
||||
if (common->data_size == 0)
|
||||
common->data_dir = DATA_DIR_NONE;
|
||||
common->lun = cbw->Lun;
|
||||
if (common->lun >= 0 && common->lun < common->nluns)
|
||||
common->curlun = &common->luns[common->lun];
|
||||
else
|
||||
common->curlun = NULL;
|
||||
common->tag = cbw->Tag;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2297,19 +2297,17 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
|
||||
DBG(fsg, "using LUN %d from CBW, "
|
||||
"not LUN %d from CDB\n",
|
||||
fsg->lun, lun);
|
||||
} else
|
||||
fsg->lun = lun; // Use LUN from the command
|
||||
}
|
||||
|
||||
/* Check the LUN */
|
||||
if (fsg->lun < fsg->nluns) {
|
||||
fsg->curlun = curlun = &fsg->luns[fsg->lun];
|
||||
curlun = fsg->curlun;
|
||||
if (curlun) {
|
||||
if (fsg->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = SS_NO_SENSE;
|
||||
curlun->sense_data_info = 0;
|
||||
curlun->info_valid = 0;
|
||||
}
|
||||
} else {
|
||||
fsg->curlun = curlun = NULL;
|
||||
fsg->bad_lun_okay = 0;
|
||||
|
||||
/* INQUIRY and REQUEST SENSE commands are explicitly allowed
|
||||
@ -2351,6 +2349,16 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wrapper of check_command for data size in blocks handling */
|
||||
static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
|
||||
enum data_direction data_dir, unsigned int mask,
|
||||
int needs_medium, const char *name)
|
||||
{
|
||||
if (fsg->curlun)
|
||||
fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
|
||||
return check_command(fsg, cmnd_size, data_dir,
|
||||
mask, needs_medium, name);
|
||||
}
|
||||
|
||||
static int do_scsi_command(struct fsg_dev *fsg)
|
||||
{
|
||||
@ -2425,26 +2433,27 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
||||
|
||||
case READ_6:
|
||||
i = fsg->cmnd[4];
|
||||
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
|
||||
fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
|
||||
if ((reply = check_command_size_in_blocks(fsg, 6,
|
||||
DATA_DIR_TO_HOST,
|
||||
(7<<1) | (1<<4), 1,
|
||||
"READ(6)")) == 0)
|
||||
reply = do_read(fsg);
|
||||
break;
|
||||
|
||||
case READ_10:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
|
||||
if ((reply = check_command_size_in_blocks(fsg, 10,
|
||||
DATA_DIR_TO_HOST,
|
||||
(1<<1) | (0xf<<2) | (3<<7), 1,
|
||||
"READ(10)")) == 0)
|
||||
reply = do_read(fsg);
|
||||
break;
|
||||
|
||||
case READ_12:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
|
||||
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
|
||||
fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
|
||||
if ((reply = check_command_size_in_blocks(fsg, 12,
|
||||
DATA_DIR_TO_HOST,
|
||||
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
||||
"READ(12)")) == 0)
|
||||
reply = do_read(fsg);
|
||||
@ -2529,26 +2538,27 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
||||
|
||||
case WRITE_6:
|
||||
i = fsg->cmnd[4];
|
||||
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
|
||||
fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
|
||||
if ((reply = check_command_size_in_blocks(fsg, 6,
|
||||
DATA_DIR_FROM_HOST,
|
||||
(7<<1) | (1<<4), 1,
|
||||
"WRITE(6)")) == 0)
|
||||
reply = do_write(fsg);
|
||||
break;
|
||||
|
||||
case WRITE_10:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
|
||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
|
||||
if ((reply = check_command_size_in_blocks(fsg, 10,
|
||||
DATA_DIR_FROM_HOST,
|
||||
(1<<1) | (0xf<<2) | (3<<7), 1,
|
||||
"WRITE(10)")) == 0)
|
||||
reply = do_write(fsg);
|
||||
break;
|
||||
|
||||
case WRITE_12:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
|
||||
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
|
||||
fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
|
||||
if ((reply = check_command_size_in_blocks(fsg, 12,
|
||||
DATA_DIR_FROM_HOST,
|
||||
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
||||
"WRITE(12)")) == 0)
|
||||
reply = do_write(fsg);
|
||||
@ -2715,7 +2725,17 @@ static int get_next_command(struct fsg_dev *fsg)
|
||||
memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
|
||||
fsg->cbbuf_cmnd_size = 0;
|
||||
spin_unlock_irq(&fsg->lock);
|
||||
|
||||
/* Use LUN from the command */
|
||||
fsg->lun = fsg->cmnd[1] >> 5;
|
||||
}
|
||||
|
||||
/* Update current lun */
|
||||
if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
|
||||
fsg->curlun = &fsg->luns[fsg->lun];
|
||||
else
|
||||
fsg->curlun = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user