Re: Problem in IDE Disks cache handling in kernel 2.4.XX

From: Alan Cox (alan@lxorguk.ukuu.org.uk)
Date: Fri Jan 10 2003 - 12:23:29 EST


On Fri, 2003-01-10 at 09:54, Francis Verscheure wrote:
> And by the way how are powered off the IDE drives ?
> Because a FLUSH CACHE or STANDY or SLEEP is MANDATORY before powering off the
> drive with cache enabled or you will enjoy lost data.

We always issue standby or sleep commands to a drive before powering off which means
the cache flush thing should never have been an issue.

Having been over the other stuff here is a fairly paranoid first cut. Marcelo
please *don't* apply this yet, I'd like an Andre review of it and some testing
first.


--- ../linux.21pre3/drivers/ide/ide-disk.c 2003-01-07 14:03:08.000000000 +0000
+++ drivers/ide/ide-disk.c 2003-01-10 17:15:02.000000000 +0000
@@ -38,9 +38,11 @@
  * Version 1.15 convert all calls to ide_raw_taskfile
  * since args will return register content.
  * Version 1.16 added suspend-resume-checkpower
+ * Version 1.17 do flush on standy, do flush on ATA < ATA6
+ * fix wcache setup.
  */
 
-#define IDEDISK_VERSION "1.16"
+#define IDEDISK_VERSION "1.17"
 
 #undef REALLY_SLOW_IO /* most systems can safely undef this */
 
@@ -67,7 +69,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-/* FIXME: soem day we shouldnt need to look in here! */
+/* FIXME: some day we shouldnt need to look in here! */
 
 #include "legacy/pdc4030.h"
 
@@ -716,6 +718,7 @@
         MOD_INC_USE_COUNT;
         if (drive->removable && drive->usage == 1) {
                 ide_task_t args;
+ int cf;
                 memset(&args, 0, sizeof(ide_task_t));
                 args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
                 args.command_type = ide_cmd_type_parser(&args);
@@ -727,12 +730,40 @@
                  */
                 if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
                         drive->doorlocking = 0;
+ drive->wcache = 0;
+ /* Cache enabled ? */
+ if (drive->id->csfo & 1)
+ drive->wcache = 1;
+ /* Cache command set available ? */
+ if (drive->id->cfs_enable_1 & (1<<5))
+ drive->wcache = 1;
+ /* ATA6 cache extended commands */
+ cf = drive->id->command_set_2 >> 24;
+ if((cf & 0xC0) == 0x40 && (cf & 0x30) != 0)
+ drive->wcache = 1;
         }
         return 0;
 }
 
 static int do_idedisk_flushcache(ide_drive_t *drive);
 
+static int ide_cacheflush_p(ide_drive_t *drive)
+{
+ if(drive->wcache)
+ {
+ printk(KERN_INFO "ide: performing cache flush.\n");
+ if (do_idedisk_flushcache(drive))
+ {
+ printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+ drive->name);
+ return -EIO;
+ }
+ return 1;
+ }
+ printk(KERN_INFO "ide: no cache flush required.\n");
+ return 0;
+}
+
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
         if (drive->removable && !drive->usage) {
@@ -744,10 +775,7 @@
                 if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
                         drive->doorlocking = 0;
         }
- if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
- if (do_idedisk_flushcache(drive))
- printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
- drive->name);
+ ide_cacheflush_p(drive);
         MOD_DEC_USE_COUNT;
 }
 
@@ -1435,7 +1463,7 @@
 {
         if (drive->suspend_reset)
                 return 1;
-
+ ide_cacheflush_p(drive);
         return call_idedisk_suspend(drive, 0);
 }
 
@@ -1679,10 +1707,7 @@
 
 static int idedisk_cleanup(ide_drive_t *drive)
 {
- if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
- if (do_idedisk_flushcache(drive))
- printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
- drive->name);
+ ide_cacheflush_p(drive);
         return ide_unregister_subdriver(drive);
 }
 

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



This archive was generated by hypermail 2b29 : Wed Jan 15 2003 - 22:00:33 EST