Skip to content

Commit

Permalink
[PATCH] libata: use FLUSH_EXT only when driver is larger than LBA28 l…
Browse files Browse the repository at this point in the history
…imit

Many drives support LBA48 even when its capacity is smaller than
1<<28, as LBA48 is required for many functionalities.  FLUSH_EXT is
mandatory for drives w/ LBA48 support.

Interestingly, at least one of such drives (ST960812A) has problems
dealing with FLUSH_EXT.  It eventually completes the command but takes
around 7 seconds to finish in many cases thus drastically slowing down
IO transactions.  This seems to be a firmware bug which sneaked into
production probably because no other ATA driver including linux IDE
issues FLUSH_EXT to drives which report support for LBA48 & FLUSH_EXT
but is smaller than 1<<28 blocks.

This patch adds ATA_DFLAG_FLUSH_EXT which is set iff the drive
supports LBA48 & FLUSH_EXT and is larger than LBA28 limit.  Both cache
flush paths are updated to issue FLUSH_EXT only when the flag is set.
Note that the changed behavior is more inline with the rest of libata.
libata prefers shorter commands whenever possible.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Danny Kukawka <dkukawka@novell.com>
Cc: Stefan Seyfried <seife@novell.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Dec 2, 2006
1 parent 648a88b commit 6fc49ad
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 3 deletions.
6 changes: 5 additions & 1 deletion drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1457,6 +1457,10 @@ int ata_dev_configure(struct ata_device *dev)
if (ata_id_has_lba48(id)) {
dev->flags |= ATA_DFLAG_LBA48;
lba_desc = "LBA48";

if (dev->n_sectors >= (1UL << 28) &&
ata_id_has_flush_ext(id))
dev->flags |= ATA_DFLAG_FLUSH_EXT;
}

/* config NCQ */
Expand Down Expand Up @@ -5128,7 +5132,7 @@ int ata_flush_cache(struct ata_device *dev)
if (!ata_try_flush_cache(dev))
return 0;

if (ata_id_has_flush_ext(dev->id))
if (dev->flags & ATA_DFLAG_FLUSH_EXT)
cmd = ATA_CMD_FLUSH_EXT;
else
cmd = ATA_CMD_FLUSH;
Expand Down
3 changes: 1 addition & 2 deletions drivers/ata/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1027,8 +1027,7 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scs
tf->flags |= ATA_TFLAG_DEVICE;
tf->protocol = ATA_PROT_NODATA;

if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
(ata_id_has_flush_ext(qc->dev->id)))
if (qc->dev->flags & ATA_DFLAG_FLUSH_EXT)
tf->command = ATA_CMD_FLUSH_EXT;
else
tf->command = ATA_CMD_FLUSH;
Expand Down
1 change: 1 addition & 0 deletions include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ enum {
ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */
ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */
ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,

ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
Expand Down

0 comments on commit 6fc49ad

Please sign in to comment.