diff options
author | Albert Lee <albertcc@tw.ibm.com> | 2005-10-12 15:12:26 +0800 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-18 17:18:16 -0400 |
commit | c6a33e2464edd87f8c12cc2d11369a5b44c65b77 (patch) | |
tree | f15eb374fa98fb1f76bf3a7cffd9cb8ef7173091 | |
parent | 59a10b172fccaea793352c00fd9065f0a5b4ef70 (diff) | |
download | linux-c6a33e2464edd87f8c12cc2d11369a5b44c65b77.tar.gz linux-c6a33e2464edd87f8c12cc2d11369a5b44c65b77.tar.bz2 linux-c6a33e2464edd87f8c12cc2d11369a5b44c65b77.zip |
[PATCH] libata CHS: LBA28/LBA48 optimization (revise #6)
- add lba_28_ok() and lba_48_ok() to ata.h.
- check ending block number instead of staring block number.
- use lba_28_ok() for CHS range check
- LBA28/LBA48 optimization
Suggested by Mark Lord and Alan Cox.
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
=====
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | drivers/scsi/libata-scsi.c | 48 | ||||
-rw-r--r-- | include/linux/ata.h | 12 |
2 files changed, 33 insertions, 27 deletions
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 90bf22204668..efbe6fe65442 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -636,9 +636,13 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) if (dev->flags & ATA_DFLAG_LBA) { tf->flags |= ATA_TFLAG_LBA; - if (dev->flags & ATA_DFLAG_LBA48) { - if (n_block > (64 * 1024)) - goto invalid_fld; + if (lba_28_ok(block, n_block)) { + /* use LBA28 */ + tf->command = ATA_CMD_VERIFY; + tf->device |= (block >> 24) & 0xf; + } else if (lba_48_ok(block, n_block)) { + if (!(dev->flags & ATA_DFLAG_LBA48)) + goto out_of_range; /* use LBA48 */ tf->flags |= ATA_TFLAG_LBA48; @@ -649,15 +653,9 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->hob_lbah = (block >> 40) & 0xff; tf->hob_lbam = (block >> 32) & 0xff; tf->hob_lbal = (block >> 24) & 0xff; - } else { - if (n_block > 256) - goto invalid_fld; - - /* use LBA28 */ - tf->command = ATA_CMD_VERIFY; - - tf->device |= (block >> 24) & 0xf; - } + } else + /* request too large even for LBA48 */ + goto out_of_range; tf->nsect = n_block & 0xff; @@ -670,8 +668,8 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) /* CHS */ u32 sect, head, cyl, track; - if (n_block > 256) - goto invalid_fld; + if (!lba_28_ok(block, n_block)) + goto out_of_range; /* Convert LBA to CHS */ track = (u32)block / dev->sectors; @@ -784,9 +782,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) if (dev->flags & ATA_DFLAG_LBA) { tf->flags |= ATA_TFLAG_LBA; - if (dev->flags & ATA_DFLAG_LBA48) { - /* The request -may- be too large for LBA48. */ - if ((block >> 48) || (n_block > 65536)) + if (lba_28_ok(block, n_block)) { + /* use LBA28 */ + tf->device |= (block >> 24) & 0xf; + } else if (lba_48_ok(block, n_block)) { + if (!(dev->flags & ATA_DFLAG_LBA48)) goto out_of_range; /* use LBA48 */ @@ -797,15 +797,9 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->hob_lbah = (block >> 40) & 0xff; tf->hob_lbam = (block >> 32) & 0xff; tf->hob_lbal = (block >> 24) & 0xff; - } else { - /* use LBA28 */ - - /* The request -may- be too large for LBA28. */ - if ((block >> 28) || (n_block > 256)) - goto out_of_range; - - tf->device |= (block >> 24) & 0xf; - } + } else + /* request too large even for LBA48 */ + goto out_of_range; ata_rwcmd_protocol(qc); @@ -822,7 +816,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) u32 sect, head, cyl, track; /* The request -may- be too large for CHS addressing. */ - if ((block >> 28) || (n_block > 256)) + if (!lba_28_ok(block, n_block)) goto out_of_range; ata_rwcmd_protocol(qc); diff --git a/include/linux/ata.h b/include/linux/ata.h index 630908c9378b..b7e7e1cb2633 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -291,4 +291,16 @@ static inline int ata_ok(u8 status) == ATA_DRDY); } +static inline int lba_28_ok(u64 block, u32 n_block) +{ + /* check the ending block number */ + return ((block + n_block - 1) < ((u64)1 << 28)) && (n_block <= 256); +} + +static inline int lba_48_ok(u64 block, u32 n_block) +{ + /* check the ending block number */ + return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536); +} + #endif /* __LINUX_ATA_H__ */ |