devide: Support for flushing device cache. Avoids sending redundant
authorWill Sowerbutts <will@sowerbutts.com>
Sun, 11 Jan 2015 23:45:49 +0000 (23:45 +0000)
committerWill Sowerbutts <will@sowerbutts.com>
Sun, 11 Jan 2015 23:45:49 +0000 (23:45 +0000)
flush commands when no blocks have been written since the last flush.

Kernel/dev/devide.c
Kernel/dev/devide.h

index 5a3bd2d..f8106d0 100644 (file)
 
 #define DRIVE_COUNT 2   /* range 1 -- 4 */
 
+static uint8_t drive_flags[DRIVE_COUNT];
+#define FLAG_WRITE_CACHE 1
+#define FLAG_CACHE_DIRTY 2
+
 #ifdef IDE_REG_ALTSTATUS
 __sfr __at IDE_REG_ALTSTATUS ide_reg_altstatus;
 #endif
@@ -126,11 +130,36 @@ static bool devide_transfer_sector(uint8_t drive, uint32_t lba, void *buffer, bo
        devide_write_data(buffer, IDE_REG_DATA);
        if(!devide_wait(IDE_STATUS_READY))
            return false;
+       drive_flags[drive] |= FLAG_CACHE_DIRTY;
     }
 
     return true;
 }
 
+static int devide_flush_cache(uint8_t drive)
+{
+    /* check drive has a cache and was written to since the last flush */
+    if(drive_flags[drive] & (FLAG_WRITE_CACHE | FLAG_CACHE_DIRTY)
+                   == (FLAG_WRITE_CACHE | FLAG_CACHE_DIRTY)){
+       drive_flags[drive] &= ~FLAG_CACHE_DIRTY;
+       ide_reg_lba_3 = ((drive == 0) ? 0xE0 : 0xF0); // select drive
+
+       if(!devide_wait(IDE_STATUS_READY)){
+           udata.u_error = EIO;
+           return -1;
+       }
+
+       ide_reg_command = IDE_CMD_FLUSH_CACHE;
+
+       if(!devide_wait(IDE_STATUS_READY)){
+           udata.u_error = EIO;
+           return -1;
+       }
+    }
+
+    return 0;
+}
+
 /****************************************************************************/
 /* Code below this point used only once, at startup, so we want it to live  */
 /* in the DISCARD segment. sdcc only allows us to specify one segment for   */
@@ -152,7 +181,6 @@ static void devide_init_drive(uint8_t drive)
 {
     blkdev_t *blk;
     uint8_t *buffer, select;
-    uint32_t size;
 
     switch(drive){
        case 0: select = 0xE0; break;
@@ -160,6 +188,8 @@ static void devide_init_drive(uint8_t drive)
         default: return;
     }
 
+    drive_flags[drive] = 0;
+
     kprintf("IDE drive %d: ", drive);
 
     /* Reset depends upon the presence of alt control, which is optional */
@@ -203,19 +233,31 @@ static void devide_init_drive(uint8_t drive)
         goto failout;
     }
 
+    if( !(((uint16_t*)buffer)[82] == 0x0000 && ((uint16_t*)buffer)[83] == 0x0000) ||
+         (((uint16_t*)buffer)[82] == 0xFFFF && ((uint16_t*)buffer)[83] == 0xFFFF) ){
+       /* command set notification is supported */
+       if(buffer[164] & 0x20){
+           /* write cache is supported */
+           drive_flags[drive] |= FLAG_WRITE_CACHE;
+       }
+    }
+
+    blk = blkdev_alloc();
+    if(!blk)
+       goto failout;
+
+    blk->transfer = devide_transfer_sector;
+    blk->flush = devide_flush_cache;
+    blk->drive_number = drive;
+
     /* read out the drive's sector count */
-    size = le32_to_cpu(*((uint32_t*)&buffer[120]));
+    blk->drive_lba_count = le32_to_cpu(*((uint32_t*)&buffer[120]));
 
     /* done with our temporary memory */
     brelse((bufptr)buffer);
 
-    blk = blkdev_alloc();
-    if (blk) {
-        blk->transfer = devide_transfer_sector;
-        blk->drive_number = drive;
-        blk->drive_lba_count = size;
-        blkdev_scan(blk, SWAPSCAN);
-    }
+    /* scan partitions */
+    blkdev_scan(blk, SWAPSCAN);
 
     return;
 failout:
index 560cb93..2129bca 100644 (file)
@@ -64,6 +64,7 @@ void devide_init(void);
 /* IDE command codes */
 #define IDE_CMD_READ_SECTOR     0x20
 #define IDE_CMD_WRITE_SECTOR    0x30
+#define IDE_CMD_FLUSH_CACHE     0xE7
 #define IDE_CMD_IDENTIFY        0xEC
 #define IDE_CMD_SET_FEATURES    0xEF