Skip to content

Commit

Permalink
usb: gadget: storage: adapt logic block size to bound block devices
Browse files Browse the repository at this point in the history
Now the mass storage driver has fixed logic block size of 512 bytes.

The mass storage gadget read/write bound devices only through VFS, so the
bottom level devices actually are just RAW devices to the driver and connected
PC. As a RAW, hosts can always format, read and write it right in 512 bytes
logic block and don't care about the actual logic block size of devices bound
to the gadget.

But if we want to share the bound block device partition between target board
and PC, in case the logic block size of the bound block device is 4KB, we
execute the following steps:

1. connect a board with mass storage gadget to PC(the board has set one
	partition of on-board block device as file name of the mass storage)
2. PC format the mass storage to VFAT by default logic block size and
	read/write it
3. disconnect boards from PC
4. target board mount the partition as VFAT

Step 4 will fail since kernel on target thinks the logic block size of the
bound partition as 4KB.
A typical error is "FAT: logical sector size too small for device (logical
sector size = 512)"

If we execute opposite steps:
1. format the partition to VFAT on target board and read/write this partition
2. connect the board to Windows PC as usb mass storage gadget, windows will
	think the disk is not formatted

So the conclusion is that only as a gadget, the mass storage driver has no any
problem.  But being shared VFAT or other filesystem on PC and target board, it
will fail.

This patch adapts logic block size to bound block devices and fix the issue.

Cc: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Peiyu Li <peiyu.li@csr.com>
Signed-off-by: Xianglong Du <xianglong.du@csr.com>
Signed-off-by: Huayi Li <huayi.li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
  • Loading branch information
Peiyu Li authored and Felipe Balbi committed Sep 9, 2011
1 parent 019ac83 commit 3f565a3
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 57 deletions.
63 changes: 37 additions & 26 deletions drivers/usb/gadget/f_mass_storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@
* is not loaded (an empty string as "filename" in the fsg_config
* structure causes error). The CD-ROM emulation includes a single
* data track and no audio tracks; hence there need be only one
* backing file per LUN. Note also that the CD-ROM block length is
* set to 512 rather than the more common value 2048.
* backing file per LUN.
*
*
* MSF includes support for module parameters. If gadget using it
Expand Down Expand Up @@ -771,7 +770,7 @@ static int do_read(struct fsg_common *common)
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
file_offset = ((loff_t) lba) << 9;
file_offset = ((loff_t) lba) << curlun->blkbits;

/* Carry out the file reads */
amount_left = common->data_size_from_cmnd;
Expand Down Expand Up @@ -812,7 +811,8 @@ static int do_read(struct fsg_common *common)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = file_offset >> 9;
curlun->sense_data_info =
file_offset >> curlun->blkbits;
curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
Expand All @@ -835,7 +835,7 @@ static int do_read(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int)nread, amount);
nread -= (nread & 511); /* Round down to a block */
nread = round_down(nread, curlun->blksize);
}
file_offset += nread;
amount_left -= nread;
Expand All @@ -846,7 +846,8 @@ static int do_read(struct fsg_common *common)
/* If an error occurred, report it and its position */
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
curlun->sense_data_info = file_offset >> 9;
curlun->sense_data_info =
file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
Expand Down Expand Up @@ -921,7 +922,7 @@ static int do_write(struct fsg_common *common)

/* Carry out the file writes */
get_some_more = 1;
file_offset = usb_offset = ((loff_t) lba) << 9;
file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd;

Expand Down Expand Up @@ -954,11 +955,12 @@ static int do_write(struct fsg_common *common)
get_some_more = 0;
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = usb_offset >> 9;
curlun->sense_data_info =
usb_offset >> curlun->blkbits;
curlun->info_valid = 1;
continue;
}
amount -= amount & 511;
amount = round_down(amount, curlun->blksize);
if (amount == 0) {

/*
Expand Down Expand Up @@ -1002,7 +1004,8 @@ static int do_write(struct fsg_common *common)
/* Did something go wrong with the transfer? */
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
curlun->sense_data_info = file_offset >> 9;
curlun->sense_data_info =
file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
Expand Down Expand Up @@ -1033,8 +1036,7 @@ static int do_write(struct fsg_common *common)
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int)nwritten, amount);
nwritten -= (nwritten & 511);
/* Round down to a block */
nwritten = round_down(nwritten, curlun->blksize);
}
file_offset += nwritten;
amount_left_to_write -= nwritten;
Expand All @@ -1043,7 +1045,8 @@ static int do_write(struct fsg_common *common)
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
curlun->sense_data_info = file_offset >> 9;
curlun->sense_data_info =
file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
Expand Down Expand Up @@ -1129,8 +1132,8 @@ static int do_verify(struct fsg_common *common)
return -EIO; /* No default reply */

/* Prepare to carry out the file verify */
amount_left = verification_length << 9;
file_offset = ((loff_t) lba) << 9;
amount_left = verification_length << curlun->blkbits;
file_offset = ((loff_t) lba) << curlun->blkbits;

/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub(curlun);
Expand All @@ -1157,7 +1160,8 @@ static int do_verify(struct fsg_common *common)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = file_offset >> 9;
curlun->sense_data_info =
file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
Expand All @@ -1179,11 +1183,12 @@ static int do_verify(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int)nread, amount);
nread -= nread & 511; /* Round down to a sector */
nread = round_down(nread, curlun->blksize);
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
curlun->sense_data_info = file_offset >> 9;
curlun->sense_data_info =
file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
Expand Down Expand Up @@ -1289,7 +1294,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)

put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
put_unaligned_be32(512, &buf[4]); /* Block length */
put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
return 8;
}

Expand Down Expand Up @@ -1527,7 +1532,7 @@ static int do_read_format_capacities(struct fsg_common *common,

put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
put_unaligned_be32(512, &buf[4]); /* Block length */
put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
Expand Down Expand Up @@ -2022,7 +2027,8 @@ 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) << 9;
common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)");
Expand All @@ -2032,7 +2038,8 @@ static int do_scsi_command(struct fsg_common *common)

case READ_10:
common->data_size_from_cmnd =
get_unaligned_be16(&common->cmnd[7]) << 9;
get_unaligned_be16(&common->cmnd[7]) <<
common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)");
Expand All @@ -2042,7 +2049,8 @@ static int do_scsi_command(struct fsg_common *common)

case READ_12:
common->data_size_from_cmnd =
get_unaligned_be32(&common->cmnd[6]) << 9;
get_unaligned_be32(&common->cmnd[6]) <<
common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)");
Expand Down Expand Up @@ -2142,7 +2150,8 @@ 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) << 9;
common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)");
Expand All @@ -2152,7 +2161,8 @@ static int do_scsi_command(struct fsg_common *common)

case WRITE_10:
common->data_size_from_cmnd =
get_unaligned_be16(&common->cmnd[7]) << 9;
get_unaligned_be16(&common->cmnd[7]) <<
common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)");
Expand All @@ -2162,7 +2172,8 @@ static int do_scsi_command(struct fsg_common *common)

case WRITE_12:
common->data_size_from_cmnd =
get_unaligned_be32(&common->cmnd[6]) << 9;
get_unaligned_be32(&common->cmnd[6]) <<
common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)");
Expand Down
Loading

0 comments on commit 3f565a3

Please sign in to comment.