Re: [PATCH linux-2.6-block:post-2.6.15 10/11] blk: add FUA support to IDE

From: Tejun Heo
Date: Thu Nov 24 2005 - 11:27:50 EST


10_blk_ide-add-fua-support.patch

Add FUA support to IDE. IDE FUA support makes use of
->protocol_changed callback to correctly adjust FUA setting
according to transfer protocol change.

Signed-off-by: Tejun Heo <htejun@xxxxxxxxx>

drivers/ide/ide-disk.c | 59 +++++++++++++++++++++++++++++++++++++++++--------
include/linux/hdreg.h | 16 +++++++++++--
include/linux/ide.h | 3 ++
3 files changed, 67 insertions(+), 11 deletions(-)

Index: work/drivers/ide/ide-disk.c
===================================================================
--- work.orig/drivers/ide/ide-disk.c 2005-11-25 00:52:03.000000000 +0900
+++ work/drivers/ide/ide-disk.c 2005-11-25 00:52:04.000000000 +0900
@@ -164,18 +164,24 @@ static ide_startstop_t __ide_do_rw_disk(
ide_hwif_t *hwif = HWIF(drive);
unsigned int dma = drive->using_dma;
u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+ int fua = blk_fua_rq(rq);
task_ioreg_t command = WIN_NOP;
ata_nsector_t nsectors;

nsectors.all = (u16) rq->nr_sectors;

if (hwif->no_lba48_dma && lba48 && dma) {
- if (block + rq->nr_sectors > 1ULL << 28)
+ if (block + rq->nr_sectors > 1ULL << 28 || fua)
dma = 0;
else
lba48 = 0;
}

+ if (unlikely(fua)) {
+ if (!lba48 || ((!dma || drive->vdma) && !drive->mult_count))
+ goto fail_fua;
+ }
+
if (!dma) {
ide_init_sg_cmd(drive, rq);
ide_map_sg(drive, rq);
@@ -253,9 +259,15 @@ static ide_startstop_t __ide_do_rw_disk(
if (dma) {
if (!hwif->dma_setup(drive)) {
if (rq_data_dir(rq)) {
- command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
- if (drive->vdma)
- command = lba48 ? WIN_WRITE_EXT: WIN_WRITE;
+ if (!fua) {
+ command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+ if (drive->vdma)
+ command = lba48 ? WIN_WRITE_EXT: WIN_WRITE;
+ } else {
+ command = ATA_CMD_WRITE_FUA_EXT;
+ if (drive->vdma)
+ command = ATA_CMD_WRITE_MULTI_FUA_EXT;
+ }
} else {
command = lba48 ? WIN_READDMA_EXT : WIN_READDMA;
if (drive->vdma)
@@ -284,7 +296,10 @@ static ide_startstop_t __ide_do_rw_disk(
} else {
if (drive->mult_count) {
hwif->data_phase = TASKFILE_MULTI_OUT;
- command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+ if (!fua)
+ command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+ else
+ command = ATA_CMD_WRITE_MULTI_FUA_EXT;
} else {
hwif->data_phase = TASKFILE_OUT;
command = lba48 ? WIN_WRITE_EXT : WIN_WRITE;
@@ -295,6 +310,13 @@ static ide_startstop_t __ide_do_rw_disk(

return pre_task_out_intr(drive, rq);
}
+
+ fail_fua:
+ printk(KERN_ERR "%s: FUA write unsupported (lba48=%u dma=%u "
+ "vdma=%u mult_count=%u)\n",
+ drive->name, lba48, dma, drive->vdma, drive->mult_count);
+ ide_end_request(drive, 0, 0);
+ return ide_stopped;
}

/*
@@ -761,7 +783,7 @@ static void update_ordered(ide_drive_t *

if (drive->wcache) {
unsigned long long capacity;
- int barrier;
+ int barrier, lba48_dma, fua;
/*
* We must avoid issuing commands a drive does not
* understand or we may crash it. We check flush cache
@@ -775,11 +797,24 @@ static void update_ordered(ide_drive_t *
(drive->addressing == 0 || capacity <= (1ULL << 28) ||
ide_id_has_flush_cache_ext(id));

- printk(KERN_INFO "%s: cache flushes %ssupported\n",
- drive->name, barrier ? "" : "not");
+ /*
+ * There is no single-sector or CHS/LBA28 FUA write
+ * command. Enable FUA only if DMA or multi-sector
+ * PIO is used for LBA48 requests.
+ */
+ lba48_dma = drive->using_dma &&
+ !drive->hwif->no_lba48_dma && !drive->vdma;
+ fua = barrier &&
+ idedisk_supports_lba48(id) && ide_id_has_fua(id) &&
+ (lba48_dma || drive->mult_count);
+
+ printk(KERN_INFO "%s: cache flushes %ssupported%s\n",
+ drive->name, barrier ? "" : "not ",
+ fua ? " w/ FUA" : "");

if (barrier) {
- ordered = QUEUE_ORDERED_DRAIN_FLUSH;
+ ordered = fua ? QUEUE_ORDERED_DRAIN_FUA
+ : QUEUE_ORDERED_DRAIN_FLUSH;
prep_fn = idedisk_prepare_flush;
issue_fn = idedisk_issue_flush;
}
@@ -1057,6 +1092,11 @@ static void ide_device_shutdown(struct d
dev->bus->suspend(dev, PMSG_SUSPEND);
}

+static void ide_disk_protocol_changed(ide_drive_t *drive)
+{
+ update_ordered(drive);
+}
+
static ide_driver_t idedisk_driver = {
.owner = THIS_MODULE,
.gen_driver = {
@@ -1074,6 +1114,7 @@ static ide_driver_t idedisk_driver = {
.error = __ide_error,
.abort = __ide_abort,
.proc = idedisk_proc,
+ .protocol_changed = ide_disk_protocol_changed,
};

static int idedisk_open(struct inode *inode, struct file *filp)
Index: work/include/linux/hdreg.h
===================================================================
--- work.orig/include/linux/hdreg.h 2005-11-25 00:51:37.000000000 +0900
+++ work/include/linux/hdreg.h 2005-11-25 00:52:04.000000000 +0900
@@ -550,7 +550,13 @@ struct hd_driveid {
* cmd set-feature supported extensions
* 15: Shall be ZERO
* 14: Shall be ONE
- * 13:6 reserved
+ * 13: IDLE IMMEDIATE w/ UNLOAD FEATURE
+ * 12:11 reserved for technical report
+ * 10: URG for WRITE STREAM
+ * 9: URG for READ STREAM
+ * 8: 64-bit World wide name
+ * 7: WRITE DMA QUEUED FUA EXT
+ * 6: WRITE DMA/MULTIPLE FUA EXT
* 5: General Purpose Logging
* 4: Streaming Feature Set
* 3: Media Card Pass Through
@@ -600,7 +606,13 @@ struct hd_driveid {
* command set-feature default
* 15: Shall be ZERO
* 14: Shall be ONE
- * 13:6 reserved
+ * 13: IDLE IMMEDIATE w/ UNLOAD FEATURE
+ * 12:11 reserved for technical report
+ * 10: URG for WRITE STREAM
+ * 9: URG for READ STREAM
+ * 8: 64-bit World wide name
+ * 7: WRITE DMA QUEUED FUA EXT
+ * 6: WRITE DMA/MULTIPLE FUA EXT
* 5: General Purpose Logging enabled
* 4: Valid CONFIGURE STREAM executed
* 3: Media Card Pass Through enabled
Index: work/include/linux/ide.h
===================================================================
--- work.orig/include/linux/ide.h 2005-11-25 00:52:03.000000000 +0900
+++ work/include/linux/ide.h 2005-11-25 00:52:04.000000000 +0900
@@ -1513,6 +1513,9 @@ extern struct bus_type ide_bus_type;
/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
#define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000)

+/* check if WRITE DMA FUA EXT command is supported (defined in ATA-8) */
+#define ide_id_has_fua(id) ((id)->cfsse & 0x0040)
+
/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
#define ide_id_has_flush_cache_ext(id) \
(((id)->cfs_enable_2 & 0x2400) == 0x2400)

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/