diff options
author | Matthew Wilcox <matthew@wil.cx> | 2009-03-12 14:20:29 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-14 09:42:56 -0400 |
commit | 0da205e01bc58cfad660659e3c901223d3596c57 (patch) | |
tree | 3f199f3badd8148dd035f058580eb8870b1a0fec /drivers/scsi/sd.c | |
parent | 635374e7eb110e80d9918b8611198edd56a32975 (diff) |
[SCSI] sd: Refactor sd_read_capacity()
The sd_read_capacity() function was about 180 lines long and
included a backwards goto and a tricky state variable. Splitting out
read_capacity_10() and read_capacity_16() (about 50 lines each) reduces
sd_read_capacity to about 100 lines and gets rid of the backwards goto
and the state variable. I've tried to avoid any behaviour change with
this patch.
[jejb: upped transfer request to standard recommended 32 for RC16]
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 241 |
1 files changed, 155 insertions, 86 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e744ee40be69..dcff84abcdee 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -1273,42 +1273,61 @@ disable: | |||
1273 | sdkp->capacity = 0; | 1273 | sdkp->capacity = 0; |
1274 | } | 1274 | } |
1275 | 1275 | ||
1276 | /* | 1276 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, |
1277 | * read disk capacity | 1277 | struct scsi_sense_hdr *sshdr, int sense_valid, |
1278 | */ | 1278 | int the_result) |
1279 | static void | 1279 | { |
1280 | sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) | 1280 | sd_print_result(sdkp, the_result); |
1281 | if (driver_byte(the_result) & DRIVER_SENSE) | ||
1282 | sd_print_sense_hdr(sdkp, sshdr); | ||
1283 | else | ||
1284 | sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n"); | ||
1285 | |||
1286 | /* | ||
1287 | * Set dirty bit for removable devices if not ready - | ||
1288 | * sometimes drives will not report this properly. | ||
1289 | */ | ||
1290 | if (sdp->removable && | ||
1291 | sense_valid && sshdr->sense_key == NOT_READY) | ||
1292 | sdp->changed = 1; | ||
1293 | |||
1294 | /* | ||
1295 | * We used to set media_present to 0 here to indicate no media | ||
1296 | * in the drive, but some drives fail read capacity even with | ||
1297 | * media present, so we can't do that. | ||
1298 | */ | ||
1299 | sdkp->capacity = 0; /* unknown mapped to zero - as usual */ | ||
1300 | } | ||
1301 | |||
1302 | #define RC16_LEN 32 | ||
1303 | #if RC16_LEN > SD_BUF_SIZE | ||
1304 | #error RC16_LEN must not be more than SD_BUF_SIZE | ||
1305 | #endif | ||
1306 | |||
1307 | static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, | ||
1308 | unsigned char *buffer) | ||
1281 | { | 1309 | { |
1282 | unsigned char cmd[16]; | 1310 | unsigned char cmd[16]; |
1283 | int the_result, retries; | ||
1284 | int sector_size = 0; | ||
1285 | /* Force READ CAPACITY(16) when PROTECT=1 */ | ||
1286 | int longrc = scsi_device_protection(sdkp->device) ? 1 : 0; | ||
1287 | struct scsi_sense_hdr sshdr; | 1311 | struct scsi_sense_hdr sshdr; |
1288 | int sense_valid = 0; | 1312 | int sense_valid = 0; |
1289 | struct scsi_device *sdp = sdkp->device; | 1313 | int the_result; |
1314 | int retries = 3; | ||
1315 | unsigned long long lba; | ||
1316 | unsigned sector_size; | ||
1290 | 1317 | ||
1291 | repeat: | ||
1292 | retries = 3; | ||
1293 | do { | 1318 | do { |
1294 | if (longrc) { | 1319 | memset(cmd, 0, 16); |
1295 | memset((void *) cmd, 0, 16); | 1320 | cmd[0] = SERVICE_ACTION_IN; |
1296 | cmd[0] = SERVICE_ACTION_IN; | 1321 | cmd[1] = SAI_READ_CAPACITY_16; |
1297 | cmd[1] = SAI_READ_CAPACITY_16; | 1322 | cmd[13] = RC16_LEN; |
1298 | cmd[13] = 13; | 1323 | memset(buffer, 0, RC16_LEN); |
1299 | memset((void *) buffer, 0, 13); | 1324 | |
1300 | } else { | ||
1301 | cmd[0] = READ_CAPACITY; | ||
1302 | memset((void *) &cmd[1], 0, 9); | ||
1303 | memset((void *) buffer, 0, 8); | ||
1304 | } | ||
1305 | |||
1306 | the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, | 1325 | the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, |
1307 | buffer, longrc ? 13 : 8, &sshdr, | 1326 | buffer, RC16_LEN, &sshdr, |
1308 | SD_TIMEOUT, SD_MAX_RETRIES, NULL); | 1327 | SD_TIMEOUT, SD_MAX_RETRIES, NULL); |
1309 | 1328 | ||
1310 | if (media_not_present(sdkp, &sshdr)) | 1329 | if (media_not_present(sdkp, &sshdr)) |
1311 | return; | 1330 | return -ENODEV; |
1312 | 1331 | ||
1313 | if (the_result) | 1332 | if (the_result) |
1314 | sense_valid = scsi_sense_valid(&sshdr); | 1333 | sense_valid = scsi_sense_valid(&sshdr); |
@@ -1316,72 +1335,122 @@ repeat: | |||
1316 | 1335 | ||
1317 | } while (the_result && retries); | 1336 | } while (the_result && retries); |
1318 | 1337 | ||
1319 | if (the_result && !longrc) { | 1338 | if (the_result) { |
1339 | sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n"); | ||
1340 | read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result); | ||
1341 | return -EINVAL; | ||
1342 | } | ||
1343 | |||
1344 | sector_size = (buffer[8] << 24) | (buffer[9] << 16) | | ||
1345 | (buffer[10] << 8) | buffer[11]; | ||
1346 | lba = (((u64)buffer[0] << 56) | ((u64)buffer[1] << 48) | | ||
1347 | ((u64)buffer[2] << 40) | ((u64)buffer[3] << 32) | | ||
1348 | ((u64)buffer[4] << 24) | ((u64)buffer[5] << 16) | | ||
1349 | ((u64)buffer[6] << 8) | (u64)buffer[7]); | ||
1350 | |||
1351 | sd_read_protection_type(sdkp, buffer); | ||
1352 | |||
1353 | if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) { | ||
1354 | sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " | ||
1355 | "kernel compiled with support for large block " | ||
1356 | "devices.\n"); | ||
1357 | sdkp->capacity = 0; | ||
1358 | return -EOVERFLOW; | ||
1359 | } | ||
1360 | |||
1361 | sdkp->capacity = lba + 1; | ||
1362 | return sector_size; | ||
1363 | } | ||
1364 | |||
1365 | static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, | ||
1366 | unsigned char *buffer) | ||
1367 | { | ||
1368 | unsigned char cmd[16]; | ||
1369 | struct scsi_sense_hdr sshdr; | ||
1370 | int sense_valid = 0; | ||
1371 | int the_result; | ||
1372 | int retries = 3; | ||
1373 | sector_t lba; | ||
1374 | unsigned sector_size; | ||
1375 | |||
1376 | do { | ||
1377 | cmd[0] = READ_CAPACITY; | ||
1378 | memset(&cmd[1], 0, 9); | ||
1379 | memset(buffer, 0, 8); | ||
1380 | |||
1381 | the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, | ||
1382 | buffer, 8, &sshdr, | ||
1383 | SD_TIMEOUT, SD_MAX_RETRIES, NULL); | ||
1384 | |||
1385 | if (media_not_present(sdkp, &sshdr)) | ||
1386 | return -ENODEV; | ||
1387 | |||
1388 | if (the_result) | ||
1389 | sense_valid = scsi_sense_valid(&sshdr); | ||
1390 | retries--; | ||
1391 | |||
1392 | } while (the_result && retries); | ||
1393 | |||
1394 | if (the_result) { | ||
1320 | sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n"); | 1395 | sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n"); |
1321 | sd_print_result(sdkp, the_result); | 1396 | read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result); |
1322 | if (driver_byte(the_result) & DRIVER_SENSE) | 1397 | return -EINVAL; |
1323 | sd_print_sense_hdr(sdkp, &sshdr); | 1398 | } |
1324 | else | ||
1325 | sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n"); | ||
1326 | 1399 | ||
1327 | /* Set dirty bit for removable devices if not ready - | 1400 | sector_size = (buffer[4] << 24) | (buffer[5] << 16) | |
1328 | * sometimes drives will not report this properly. */ | 1401 | (buffer[6] << 8) | buffer[7]; |
1329 | if (sdp->removable && | 1402 | lba = (buffer[0] << 24) | (buffer[1] << 16) | |
1330 | sense_valid && sshdr.sense_key == NOT_READY) | 1403 | (buffer[2] << 8) | buffer[3]; |
1331 | sdp->changed = 1; | ||
1332 | 1404 | ||
1333 | /* Either no media are present but the drive didn't tell us, | 1405 | if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) { |
1334 | or they are present but the read capacity command fails */ | 1406 | sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " |
1335 | /* sdkp->media_present = 0; -- not always correct */ | 1407 | "kernel compiled with support for large block " |
1336 | sdkp->capacity = 0; /* unknown mapped to zero - as usual */ | 1408 | "devices.\n"); |
1409 | sdkp->capacity = 0; | ||
1410 | return -EOVERFLOW; | ||
1411 | } | ||
1337 | 1412 | ||
1338 | return; | 1413 | sdkp->capacity = lba + 1; |
1339 | } else if (the_result && longrc) { | 1414 | return sector_size; |
1340 | /* READ CAPACITY(16) has been failed */ | 1415 | } |
1341 | sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n"); | ||
1342 | sd_print_result(sdkp, the_result); | ||
1343 | sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n"); | ||
1344 | 1416 | ||
1345 | sdkp->capacity = 1 + (sector_t) 0xffffffff; | 1417 | /* |
1346 | goto got_data; | 1418 | * read disk capacity |
1347 | } | 1419 | */ |
1348 | 1420 | static void | |
1349 | if (!longrc) { | 1421 | sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) |
1350 | sector_size = (buffer[4] << 24) | | 1422 | { |
1351 | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; | 1423 | int sector_size; |
1352 | if (buffer[0] == 0xff && buffer[1] == 0xff && | 1424 | struct scsi_device *sdp = sdkp->device; |
1353 | buffer[2] == 0xff && buffer[3] == 0xff) { | 1425 | |
1354 | if(sizeof(sdkp->capacity) > 4) { | 1426 | /* Force READ CAPACITY(16) when PROTECT=1 */ |
1355 | sd_printk(KERN_NOTICE, sdkp, "Very big device. " | 1427 | if (scsi_device_protection(sdp)) { |
1356 | "Trying to use READ CAPACITY(16).\n"); | 1428 | sector_size = read_capacity_16(sdkp, sdp, buffer); |
1357 | longrc = 1; | 1429 | if (sector_size == -EOVERFLOW) |
1358 | goto repeat; | ||
1359 | } | ||
1360 | sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use " | ||
1361 | "a kernel compiled with support for large " | ||
1362 | "block devices.\n"); | ||
1363 | sdkp->capacity = 0; | ||
1364 | goto got_data; | 1430 | goto got_data; |
1365 | } | 1431 | if (sector_size < 0) |
1366 | sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) | | 1432 | return; |
1367 | (buffer[1] << 16) | | ||
1368 | (buffer[2] << 8) | | ||
1369 | buffer[3]); | ||
1370 | } else { | 1433 | } else { |
1371 | sdkp->capacity = 1 + (((u64)buffer[0] << 56) | | 1434 | sector_size = read_capacity_10(sdkp, sdp, buffer); |
1372 | ((u64)buffer[1] << 48) | | 1435 | if (sector_size == -EOVERFLOW) |
1373 | ((u64)buffer[2] << 40) | | 1436 | goto got_data; |
1374 | ((u64)buffer[3] << 32) | | 1437 | if (sector_size < 0) |
1375 | ((sector_t)buffer[4] << 24) | | 1438 | return; |
1376 | ((sector_t)buffer[5] << 16) | | 1439 | if ((sizeof(sdkp->capacity) > 4) && |
1377 | ((sector_t)buffer[6] << 8) | | 1440 | (sdkp->capacity > 0xffffffffULL)) { |
1378 | (sector_t)buffer[7]); | 1441 | int old_sector_size = sector_size; |
1379 | 1442 | sd_printk(KERN_NOTICE, sdkp, "Very big device. " | |
1380 | sector_size = (buffer[8] << 24) | | 1443 | "Trying to use READ CAPACITY(16).\n"); |
1381 | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; | 1444 | sector_size = read_capacity_16(sdkp, sdp, buffer); |
1382 | 1445 | if (sector_size < 0) { | |
1383 | sd_read_protection_type(sdkp, buffer); | 1446 | sd_printk(KERN_NOTICE, sdkp, |
1384 | } | 1447 | "Using 0xffffffff as device size\n"); |
1448 | sdkp->capacity = 1 + (sector_t) 0xffffffff; | ||
1449 | sector_size = old_sector_size; | ||
1450 | goto got_data; | ||
1451 | } | ||
1452 | } | ||
1453 | } | ||
1385 | 1454 | ||
1386 | /* Some devices are known to return the total number of blocks, | 1455 | /* Some devices are known to return the total number of blocks, |
1387 | * not the highest block number. Some devices have versions | 1456 | * not the highest block number. Some devices have versions |