diff options
author | Peiyu Li <peiyu.li@csr.com> | 2011-08-18 01:52:59 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-09-09 06:06:02 -0400 |
commit | 3f565a363cee14d2ed281823196d455bfc7c4170 (patch) | |
tree | 57e75064f7f153a3d5069b26d8b4fe9acf0a510a /drivers/usb/gadget/file_storage.c | |
parent | 019ac83252dc2b356cb0ca81c25a077ec90309e7 (diff) |
usb: gadget: storage: adapt logic block size to bound block devices
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>
Diffstat (limited to 'drivers/usb/gadget/file_storage.c')
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 50 |
1 files changed, 24 insertions, 26 deletions
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 39ece40a045f..59d97750cecd 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c | |||
@@ -69,8 +69,7 @@ | |||
69 | * each LUN would be settable independently as a disk drive or a CD-ROM | 69 | * each LUN would be settable independently as a disk drive or a CD-ROM |
70 | * drive, but currently all LUNs have to be the same type. The CD-ROM | 70 | * drive, but currently all LUNs have to be the same type. The CD-ROM |
71 | * emulation includes a single data track and no audio tracks; hence there | 71 | * emulation includes a single data track and no audio tracks; hence there |
72 | * need be only one backing file per LUN. Note also that the CD-ROM block | 72 | * need be only one backing file per LUN. |
73 | * length is set to 512 rather than the more common value 2048. | ||
74 | * | 73 | * |
75 | * Requirements are modest; only a bulk-in and a bulk-out endpoint are | 74 | * Requirements are modest; only a bulk-in and a bulk-out endpoint are |
76 | * needed (an interrupt-out endpoint is also needed for CBI). The memory | 75 | * needed (an interrupt-out endpoint is also needed for CBI). The memory |
@@ -1158,7 +1157,7 @@ static int do_read(struct fsg_dev *fsg) | |||
1158 | curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; | 1157 | curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; |
1159 | return -EINVAL; | 1158 | return -EINVAL; |
1160 | } | 1159 | } |
1161 | file_offset = ((loff_t) lba) << 9; | 1160 | file_offset = ((loff_t) lba) << curlun->blkbits; |
1162 | 1161 | ||
1163 | /* Carry out the file reads */ | 1162 | /* Carry out the file reads */ |
1164 | amount_left = fsg->data_size_from_cmnd; | 1163 | amount_left = fsg->data_size_from_cmnd; |
@@ -1196,7 +1195,7 @@ static int do_read(struct fsg_dev *fsg) | |||
1196 | if (amount == 0) { | 1195 | if (amount == 0) { |
1197 | curlun->sense_data = | 1196 | curlun->sense_data = |
1198 | SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; | 1197 | SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; |
1199 | curlun->sense_data_info = file_offset >> 9; | 1198 | curlun->sense_data_info = file_offset >> curlun->blkbits; |
1200 | curlun->info_valid = 1; | 1199 | curlun->info_valid = 1; |
1201 | bh->inreq->length = 0; | 1200 | bh->inreq->length = 0; |
1202 | bh->state = BUF_STATE_FULL; | 1201 | bh->state = BUF_STATE_FULL; |
@@ -1221,7 +1220,7 @@ static int do_read(struct fsg_dev *fsg) | |||
1221 | } else if (nread < amount) { | 1220 | } else if (nread < amount) { |
1222 | LDBG(curlun, "partial file read: %d/%u\n", | 1221 | LDBG(curlun, "partial file read: %d/%u\n", |
1223 | (int) nread, amount); | 1222 | (int) nread, amount); |
1224 | nread -= (nread & 511); // Round down to a block | 1223 | nread = round_down(nread, curlun->blksize); |
1225 | } | 1224 | } |
1226 | file_offset += nread; | 1225 | file_offset += nread; |
1227 | amount_left -= nread; | 1226 | amount_left -= nread; |
@@ -1232,7 +1231,7 @@ static int do_read(struct fsg_dev *fsg) | |||
1232 | /* If an error occurred, report it and its position */ | 1231 | /* If an error occurred, report it and its position */ |
1233 | if (nread < amount) { | 1232 | if (nread < amount) { |
1234 | curlun->sense_data = SS_UNRECOVERED_READ_ERROR; | 1233 | curlun->sense_data = SS_UNRECOVERED_READ_ERROR; |
1235 | curlun->sense_data_info = file_offset >> 9; | 1234 | curlun->sense_data_info = file_offset >> curlun->blkbits; |
1236 | curlun->info_valid = 1; | 1235 | curlun->info_valid = 1; |
1237 | break; | 1236 | break; |
1238 | } | 1237 | } |
@@ -1303,7 +1302,7 @@ static int do_write(struct fsg_dev *fsg) | |||
1303 | 1302 | ||
1304 | /* Carry out the file writes */ | 1303 | /* Carry out the file writes */ |
1305 | get_some_more = 1; | 1304 | get_some_more = 1; |
1306 | file_offset = usb_offset = ((loff_t) lba) << 9; | 1305 | file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; |
1307 | amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; | 1306 | amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; |
1308 | 1307 | ||
1309 | while (amount_left_to_write > 0) { | 1308 | while (amount_left_to_write > 0) { |
@@ -1333,11 +1332,11 @@ static int do_write(struct fsg_dev *fsg) | |||
1333 | get_some_more = 0; | 1332 | get_some_more = 0; |
1334 | curlun->sense_data = | 1333 | curlun->sense_data = |
1335 | SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; | 1334 | SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; |
1336 | curlun->sense_data_info = usb_offset >> 9; | 1335 | curlun->sense_data_info = usb_offset >> curlun->blkbits; |
1337 | curlun->info_valid = 1; | 1336 | curlun->info_valid = 1; |
1338 | continue; | 1337 | continue; |
1339 | } | 1338 | } |
1340 | amount -= (amount & 511); | 1339 | amount = round_down(amount, curlun->blksize); |
1341 | if (amount == 0) { | 1340 | if (amount == 0) { |
1342 | 1341 | ||
1343 | /* Why were we were asked to transfer a | 1342 | /* Why were we were asked to transfer a |
@@ -1376,7 +1375,7 @@ static int do_write(struct fsg_dev *fsg) | |||
1376 | /* Did something go wrong with the transfer? */ | 1375 | /* Did something go wrong with the transfer? */ |
1377 | if (bh->outreq->status != 0) { | 1376 | if (bh->outreq->status != 0) { |
1378 | curlun->sense_data = SS_COMMUNICATION_FAILURE; | 1377 | curlun->sense_data = SS_COMMUNICATION_FAILURE; |
1379 | curlun->sense_data_info = file_offset >> 9; | 1378 | curlun->sense_data_info = file_offset >> curlun->blkbits; |
1380 | curlun->info_valid = 1; | 1379 | curlun->info_valid = 1; |
1381 | break; | 1380 | break; |
1382 | } | 1381 | } |
@@ -1408,8 +1407,7 @@ static int do_write(struct fsg_dev *fsg) | |||
1408 | } else if (nwritten < amount) { | 1407 | } else if (nwritten < amount) { |
1409 | LDBG(curlun, "partial file write: %d/%u\n", | 1408 | LDBG(curlun, "partial file write: %d/%u\n", |
1410 | (int) nwritten, amount); | 1409 | (int) nwritten, amount); |
1411 | nwritten -= (nwritten & 511); | 1410 | nwritten = round_down(nwritten, curlun->blksize); |
1412 | // Round down to a block | ||
1413 | } | 1411 | } |
1414 | file_offset += nwritten; | 1412 | file_offset += nwritten; |
1415 | amount_left_to_write -= nwritten; | 1413 | amount_left_to_write -= nwritten; |
@@ -1418,7 +1416,7 @@ static int do_write(struct fsg_dev *fsg) | |||
1418 | /* If an error occurred, report it and its position */ | 1416 | /* If an error occurred, report it and its position */ |
1419 | if (nwritten < amount) { | 1417 | if (nwritten < amount) { |
1420 | curlun->sense_data = SS_WRITE_ERROR; | 1418 | curlun->sense_data = SS_WRITE_ERROR; |
1421 | curlun->sense_data_info = file_offset >> 9; | 1419 | curlun->sense_data_info = file_offset >> curlun->blkbits; |
1422 | curlun->info_valid = 1; | 1420 | curlun->info_valid = 1; |
1423 | break; | 1421 | break; |
1424 | } | 1422 | } |
@@ -1500,8 +1498,8 @@ static int do_verify(struct fsg_dev *fsg) | |||
1500 | return -EIO; // No default reply | 1498 | return -EIO; // No default reply |
1501 | 1499 | ||
1502 | /* Prepare to carry out the file verify */ | 1500 | /* Prepare to carry out the file verify */ |
1503 | amount_left = verification_length << 9; | 1501 | amount_left = verification_length << curlun->blkbits; |
1504 | file_offset = ((loff_t) lba) << 9; | 1502 | file_offset = ((loff_t) lba) << curlun->blkbits; |
1505 | 1503 | ||
1506 | /* Write out all the dirty buffers before invalidating them */ | 1504 | /* Write out all the dirty buffers before invalidating them */ |
1507 | fsg_lun_fsync_sub(curlun); | 1505 | fsg_lun_fsync_sub(curlun); |
@@ -1527,7 +1525,7 @@ static int do_verify(struct fsg_dev *fsg) | |||
1527 | if (amount == 0) { | 1525 | if (amount == 0) { |
1528 | curlun->sense_data = | 1526 | curlun->sense_data = |
1529 | SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; | 1527 | SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; |
1530 | curlun->sense_data_info = file_offset >> 9; | 1528 | curlun->sense_data_info = file_offset >> curlun->blkbits; |
1531 | curlun->info_valid = 1; | 1529 | curlun->info_valid = 1; |
1532 | break; | 1530 | break; |
1533 | } | 1531 | } |
@@ -1550,11 +1548,11 @@ static int do_verify(struct fsg_dev *fsg) | |||
1550 | } else if (nread < amount) { | 1548 | } else if (nread < amount) { |
1551 | LDBG(curlun, "partial file verify: %d/%u\n", | 1549 | LDBG(curlun, "partial file verify: %d/%u\n", |
1552 | (int) nread, amount); | 1550 | (int) nread, amount); |
1553 | nread -= (nread & 511); // Round down to a sector | 1551 | nread = round_down(nread, curlun->blksize); |
1554 | } | 1552 | } |
1555 | if (nread == 0) { | 1553 | if (nread == 0) { |
1556 | curlun->sense_data = SS_UNRECOVERED_READ_ERROR; | 1554 | curlun->sense_data = SS_UNRECOVERED_READ_ERROR; |
1557 | curlun->sense_data_info = file_offset >> 9; | 1555 | curlun->sense_data_info = file_offset >> curlun->blkbits; |
1558 | curlun->info_valid = 1; | 1556 | curlun->info_valid = 1; |
1559 | break; | 1557 | break; |
1560 | } | 1558 | } |
@@ -1668,7 +1666,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) | |||
1668 | 1666 | ||
1669 | put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); | 1667 | put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); |
1670 | /* Max logical block */ | 1668 | /* Max logical block */ |
1671 | put_unaligned_be32(512, &buf[4]); /* Block length */ | 1669 | put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ |
1672 | return 8; | 1670 | return 8; |
1673 | } | 1671 | } |
1674 | 1672 | ||
@@ -1890,7 +1888,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg, | |||
1890 | 1888 | ||
1891 | put_unaligned_be32(curlun->num_sectors, &buf[0]); | 1889 | put_unaligned_be32(curlun->num_sectors, &buf[0]); |
1892 | /* Number of blocks */ | 1890 | /* Number of blocks */ |
1893 | put_unaligned_be32(512, &buf[4]); /* Block length */ | 1891 | put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ |
1894 | buf[4] = 0x02; /* Current capacity */ | 1892 | buf[4] = 0x02; /* Current capacity */ |
1895 | return 12; | 1893 | return 12; |
1896 | } | 1894 | } |
@@ -2415,7 +2413,7 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2415 | 2413 | ||
2416 | case READ_6: | 2414 | case READ_6: |
2417 | i = fsg->cmnd[4]; | 2415 | i = fsg->cmnd[4]; |
2418 | fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; | 2416 | fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; |
2419 | if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, | 2417 | if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, |
2420 | (7<<1) | (1<<4), 1, | 2418 | (7<<1) | (1<<4), 1, |
2421 | "READ(6)")) == 0) | 2419 | "READ(6)")) == 0) |
@@ -2424,7 +2422,7 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2424 | 2422 | ||
2425 | case READ_10: | 2423 | case READ_10: |
2426 | fsg->data_size_from_cmnd = | 2424 | fsg->data_size_from_cmnd = |
2427 | get_unaligned_be16(&fsg->cmnd[7]) << 9; | 2425 | get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; |
2428 | if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, | 2426 | if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, |
2429 | (1<<1) | (0xf<<2) | (3<<7), 1, | 2427 | (1<<1) | (0xf<<2) | (3<<7), 1, |
2430 | "READ(10)")) == 0) | 2428 | "READ(10)")) == 0) |
@@ -2433,7 +2431,7 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2433 | 2431 | ||
2434 | case READ_12: | 2432 | case READ_12: |
2435 | fsg->data_size_from_cmnd = | 2433 | fsg->data_size_from_cmnd = |
2436 | get_unaligned_be32(&fsg->cmnd[6]) << 9; | 2434 | get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; |
2437 | if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, | 2435 | if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, |
2438 | (1<<1) | (0xf<<2) | (0xf<<6), 1, | 2436 | (1<<1) | (0xf<<2) | (0xf<<6), 1, |
2439 | "READ(12)")) == 0) | 2437 | "READ(12)")) == 0) |
@@ -2519,7 +2517,7 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2519 | 2517 | ||
2520 | case WRITE_6: | 2518 | case WRITE_6: |
2521 | i = fsg->cmnd[4]; | 2519 | i = fsg->cmnd[4]; |
2522 | fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; | 2520 | fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; |
2523 | if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, | 2521 | if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, |
2524 | (7<<1) | (1<<4), 1, | 2522 | (7<<1) | (1<<4), 1, |
2525 | "WRITE(6)")) == 0) | 2523 | "WRITE(6)")) == 0) |
@@ -2528,7 +2526,7 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2528 | 2526 | ||
2529 | case WRITE_10: | 2527 | case WRITE_10: |
2530 | fsg->data_size_from_cmnd = | 2528 | fsg->data_size_from_cmnd = |
2531 | get_unaligned_be16(&fsg->cmnd[7]) << 9; | 2529 | get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; |
2532 | if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, | 2530 | if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, |
2533 | (1<<1) | (0xf<<2) | (3<<7), 1, | 2531 | (1<<1) | (0xf<<2) | (3<<7), 1, |
2534 | "WRITE(10)")) == 0) | 2532 | "WRITE(10)")) == 0) |
@@ -2537,7 +2535,7 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2537 | 2535 | ||
2538 | case WRITE_12: | 2536 | case WRITE_12: |
2539 | fsg->data_size_from_cmnd = | 2537 | fsg->data_size_from_cmnd = |
2540 | get_unaligned_be32(&fsg->cmnd[6]) << 9; | 2538 | get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; |
2541 | if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, | 2539 | if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, |
2542 | (1<<1) | (0xf<<2) | (0xf<<6), 1, | 2540 | (1<<1) | (0xf<<2) | (0xf<<6), 1, |
2543 | "WRITE(12)")) == 0) | 2541 | "WRITE(12)")) == 0) |