changeset 2535:6ffeb2616b4b

* cdl/ide_disk.cdl: Rename of the devices to be /dev/idediskX/Y so that all disk drivers have unique device names. * cdl/ide_disk.cdl: * src/ide_diskc: Add a configurable startup delay to allow slow disks to initialize. Add support for 8-bit data path. Remove the identity check which are retired in the ATA standard. Optimize the read/write functions.
author asl
date Sun, 24 Aug 2008 12:55:41 +0000
parents 41a4df71f380
children 8e41333db259
files packages/devs/disk/ide/current/ChangeLog packages/devs/disk/ide/current/cdl/ide_disk.cdl packages/devs/disk/ide/current/src/ide_disk.c
diffstat 3 files changed, 185 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/disk/ide/current/ChangeLog
+++ b/packages/devs/disk/ide/current/ChangeLog
@@ -1,3 +1,16 @@
+2008-08-19  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* cdl/ide_disk.cdl: Rename of the devices to be /dev/idediskX/Y
+	so that all disk drivers have unique device names.
+
+2008-08-18 Frank Pagliughi <fpagliughi@mindspring.com>
+
+	* cdl/ide_disk.cdl:
+	* src/ide_diskc: Add a configurable startup delay to allow slow
+	disks to initialize. Add support for 8-bit data path. Remove the
+	identity check which are retired in the ATA standard. Optimize the
+	read/write functions.
+
 2006-11-17  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* src/ide_disk.c (ide_read_sector, ide_write_sector): Length
--- a/packages/devs/disk/ide/current/cdl/ide_disk.cdl
+++ b/packages/devs/disk/ide/current/cdl/ide_disk.cdl
@@ -55,7 +55,7 @@ cdl_package CYGPKG_DEVS_DISK_IDE {
     compile     -library=libextras.a   ide_disk.c
     
     cdl_component CYGVAR_DEVS_DISK_IDE_DISK0 {
-    	display         "Provide disk 0 device"
+        display         "Provide disk 0 device"
         flavor          bool
         default_value   1
         description     "IDE chanel 0:0 disk driver"
@@ -63,12 +63,12 @@ cdl_package CYGPKG_DEVS_DISK_IDE {
         cdl_option CYGDAT_IO_DISK_IDE_DISK0_NAME {
             display       "Device name for disk 0 device"
             flavor        data
-            default_value {"\"/dev/hda/\""}
+            default_value {"\"/dev/idedisk0/\""}
         }
     }
     
     cdl_component CYGVAR_DEVS_DISK_IDE_DISK1 {
-     display         "Provide disk 1 device"
+        display         "Provide disk 1 device"
         flavor          bool
         default_value   0
         description     "IDE chanel 0:1 disk driver"
@@ -76,12 +76,12 @@ cdl_package CYGPKG_DEVS_DISK_IDE {
         cdl_option CYGDAT_IO_DISK_IDE_DISK1_NAME {
             display       "Device name for disk 1 device"
             flavor        data
-            default_value {"\"/dev/hdb/\""}
+            default_value {"\"/dev/idedisk1/\""}
         }
     }
     
     cdl_component CYGVAR_DEVS_DISK_IDE_DISK2 {
-     display         "Provide disk 2 device"
+        display         "Provide disk 2 device"
         flavor          bool
         default_value   0
         description     "IDE chanel 1:0 disk driver"
@@ -89,12 +89,12 @@ cdl_package CYGPKG_DEVS_DISK_IDE {
         cdl_option CYGDAT_IO_DISK_IDE_DISK2_NAME {
             display       "Device name for disk 2 device"
             flavor        data
-            default_value {"\"/dev/hdc/\""}
+            default_value {"\"/dev/idedisk2/\""}
         }
     }
     
     cdl_component CYGVAR_DEVS_DISK_IDE_DISK3 {
-     display         "Provide disk 3 device"
+        display         "Provide disk 3 device"
         flavor          bool
         default_value   0
         description     "IDE chanel 1:1 disk driver"
@@ -102,7 +102,7 @@ cdl_package CYGPKG_DEVS_DISK_IDE {
         cdl_option CYGDAT_IO_DISK_IDE_DISK3_NAME {
             display       "Device name for disk 3 device"
             flavor        data
-            default_value {"\"/dev/hdd/\""}
+            default_value {"\"/dev/idedisk3/\""}
         }
     }
 
@@ -112,7 +112,35 @@ cdl_package CYGPKG_DEVS_DISK_IDE {
         default_value 512
         description "
         This option controls the disk sector size (default=512)"
-     }
+    }
+
+    cdl_option CYGDAT_DEVS_DISK_IDE_STARTUP_DELAY {
+        display       "Startup delay (in ms)"
+        flavor        data
+        default_value 0
+        description "
+		The amount of time (in ms) to wait for the IDE drives to 
+		initialize on startup. For hard drives, this can usually
+		be set to zero, but for Compact Flash and other solid
+		state media this could be up to 500ms. If drives are not
+		detected at power-up, try increasing this value.
+		"
+    }
+
+    cdl_option CYGDAT_DEVS_DISK_IDE_8_BIT_DATA_PATH {
+        display       "8-bit data path"
+        flavor        bool
+        default_value false
+        description "
+            This allows the host to communicate with the IDE drives using an 
+            8-bit data, rather than 16-bits. It does so by requesting a \"Set
+            Feature\" on the drive for the 8-bit path. Note that this may
+            be ignored by most modern disk drives, but is supported by Compact
+            Flash drives. This is only used by proprietary boards, and should
+	    be disabled for standard IDE controllers.
+        "
+    }
+
 
     cdl_option CYGSEM_DEVS_DISK_IDE_VMWARE {
         display       "Work with VMware virtual disks"
@@ -121,7 +149,6 @@ cdl_package CYGPKG_DEVS_DISK_IDE {
         description "
         This option controls the disk driver behaviour at ide-init"
      }
-
 }
 
 # EOF ide_disk.cdl
--- a/packages/devs/disk/ide/current/src/ide_disk.c
+++ b/packages/devs/disk/ide/current/src/ide_disk.c
@@ -48,6 +48,7 @@
 //==========================================================================
 
 #include <pkgconf/devs_disk_ide.h>
+#include <pkgconf/io_disk.h>
 
 #include <cyg/infra/cyg_type.h>
 #include <cyg/infra/cyg_ass.h>
@@ -64,7 +65,9 @@
 
 // ----------------------------------------------------------------------------
 
-//#define DEBUG 1
+#ifdef CYGDBG_IO_DISK_DEBUG
+# define DEBUG 1
+#endif
 
 #ifdef DEBUG
 # define D(fmt,args...) diag_printf(fmt, ## args)
@@ -94,6 +97,8 @@ IDE_DISK_INSTANCE(2, 1, 0, true, CYGDAT_
 IDE_DISK_INSTANCE(3, 1, 1, true, CYGDAT_IO_DISK_IDE_DISK3_NAME);
 #endif
 
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
 // ----------------------------------------------------------------------------
 
 static void
@@ -101,8 +106,7 @@ id_strcpy(char *dest, cyg_uint16 *src, c
 {
     int i;
 
-    for (i = 0; i < size; i+=2)
-    {
+    for (i=0; i<size; i+=2) {
         *dest++ = (char)(*src >> 8);
         *dest++ = (char)(*src & 0x00FF);
         src++;
@@ -121,7 +125,9 @@ static inline void
     } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
 }
 
+// ----------------------------------------------------------------------------
 // Wait while the device is busy with the last command
+
 static inline int
 __wait_busy(int ctlr)
 {
@@ -137,6 +143,8 @@ static inline int
     return 0;   
 }
 
+// ----------------------------------------------------------------------------
+
 static inline int
 __wait_for_drq(int ctlr)
 {
@@ -156,18 +164,20 @@ static inline int
     return 0;
 }
 
+// ----------------------------------------------------------------------------
 // Return true if any devices attached to controller
+
 static int
 ide_presence_detect(int ctlr)
 {
     cyg_uint8 sel, val;
     int i;
 
-    for (i = 0; i < 2; i++) {
+    for (i = 0; i < HAL_IDE_NUM_CONTROLLERS; i++) {
         sel = (i << 4) | 0xA0;
-        CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+        CYGACC_CALL_IF_DELAY_US(50000U);
         HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel);
-        CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+        CYGACC_CALL_IF_DELAY_US(50000U);
         HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val);
         if (val == sel) {
 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
@@ -180,6 +190,8 @@ ide_presence_detect(int ctlr)
     return 0;
 }
 
+// ----------------------------------------------------------------------------
+
 static int
 ide_reset(int ctlr)
 {
@@ -193,14 +205,14 @@ ide_reset(int ctlr)
 //
 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
     HAL_IDE_WRITE_CONTROL(ctlr, 6);    // polled mode, reset asserted
-    CYGACC_CALL_IF_DELAY_US(5000);
+    CYGACC_CALL_IF_DELAY_US(5000U);
     HAL_IDE_WRITE_CONTROL(ctlr, 2);   // polled mode, reset cleared
-    CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+    CYGACC_CALL_IF_DELAY_US(50000U);
 #endif
 
     // wait 30 seconds max for not busy and drive ready
-    for (delay = 0; delay < 300; ++delay) {
-        CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
+    for (delay=0; delay<300; ++delay) {
+        CYGACC_CALL_IF_DELAY_US(100000U);
         HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
             if (!(status & IDE_STAT_BSY)) {
                 if (status & IDE_STAT_DRDY) {
@@ -211,43 +223,76 @@ ide_reset(int ctlr)
     return 0;
 }
 
+// ----------------------------------------------------------------------------
+
 static int
 ide_ident(int ctlr, int dev, cyg_uint16 *buf)
 {
     int i;
 
-    if (!__wait_busy(ctlr)) {
+    if (!__wait_busy(ctlr))
          return 0;
-    }
-    
+
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xEC);
-    CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+    CYGACC_CALL_IF_DELAY_US(50000U);
 
-    if (!__wait_for_drq(ctlr)) {
+    if (!__wait_for_drq(ctlr))
          return 0;
+
+    for (i=0; i<(CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE/sizeof(cyg_uint16)); 
+         i++, buf++) {
+      HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
     }
-    
-    for (i = 0; i < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
-         i++, buf++)
-        HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
-
     return 1;
 }
 
+// ----------------------------------------------------------------------------
+// Requests the disk to use an 8-bit data path. This is probably ignored by
+// most modern drives, but is supported by compact flash devices.
+
+#ifdef CYGDAT_DEVS_DISK_IDE_8_BIT_DATA_PATH
+static int
+ide_8bit_mode(int ctlr, int dev, cyg_bool on)
+{
+    cyg_uint8 stat;
+
+    if (!__wait_busy(ctlr))
+         return 0;
+    
+    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
+    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_FEATURES, 0x01);
+    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND,  0xEF);
+
+    if (!__wait_busy(ctlr))
+        return 0;
+
+    HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, stat);
+    return (stat & 1) ? 0 : 1;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// Reads a group of contiguous sectors from the drive.
+// It can read up to 256 sectors.
+
 static int
 ide_read_sector(int ctlr, int dev, cyg_uint32 start, 
                 cyg_uint8 *buf, cyg_uint32 len)
 {
-    int j, c;
-    cyg_uint16 p;
-    cyg_uint8 * b=buf;
+    int i, nword;
+    cyg_uint8 lenb;
+    cyg_uint16 w;
+
+    if (len==0 || !__wait_busy(ctlr))
+       return 0;
 
-    if(!__wait_busy(ctlr)) {
-         return 0;
-    }
-    
-    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1);    // count =1
+    len = MIN(len, 256);
+    lenb = (len == 256) ? 0 : ((cyg_uint8) len);
+
+    nword = len * CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16);
+
+    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, lenb);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >>  8) & 0xff);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (start >> 16) & 0xff);
@@ -257,52 +302,68 @@ ide_read_sector(int ctlr, int dev, cyg_u
 
     if (!__wait_for_drq(ctlr))
         return 0;
-    // 
-    // It would be fine if all buffers were word aligned,
-    // but who knows
-    //
-    for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
-         j++) {
-        HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, p);
-        if (c++<(len*512)) *b++=p&0xff;
-        if (c++<(len*512)) *b++=(p>>8)&0xff;
+
+    if ((int) buf & 1) {
+        // Unaligned buffer, so split each word manually
+        for (i=0; i<nword; i++) {
+            HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, w);
+            *buf++ = w & 0xff;
+            *buf++ = (w>>8) & 0xff;
+        }
     }
-    return 1;
+    else {
+        cyg_uint16* wbuf = (cyg_uint16*) buf;
+        for (i=0; i<nword; i++, wbuf++)
+            HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *wbuf);
+    }
+    return (int) len;
 }
 
+// ----------------------------------------------------------------------------
+// Writes a group of contiguous sectors to the drive.
+// It can write up to 256 sectors.
+
 static int
 ide_write_sector(int ctlr, int dev, cyg_uint32 start, 
-                cyg_uint8 *buf, cyg_uint32 len)
+                 cyg_uint8 *buf, cyg_uint32 len)
 {
-    int j, c;
-    cyg_uint16 p;
-    cyg_uint8 * b=buf;
+    int i, nword;
+    cyg_uint8 lenb;
+    cyg_uint16 w;
 
-    if(!__wait_busy(ctlr)) {
-         return 0;
-    }
-    
-    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1);    // count =1
+    if (len==0 || !__wait_busy(ctlr))
+       return 0;
+
+    len = MIN(len, 256);
+    lenb = (len == 256) ? 0 : ((cyg_uint8) len);
+
+    nword = len * CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16);
+
+    HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, lenb);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >>  8) & 0xff);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (start >> 16) & 0xff);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
-          ((start >> 24) & 0xf) | (dev << 4) | 0x40);
+                            ((start >> 24) & 0xf) | (dev << 4) | 0x40);
     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x30);
 
     if (!__wait_for_drq(ctlr))
         return 0;
-    // 
-    // It would be fine if all buffers were word aligned,
-    // but who knows
-    //
-    for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
-         j++) {
-        p = (c++<(len*512)) ? *b++ : 0;
-        p |= (c++<(len*512)) ? (*b++<<8) : 0; 
-        HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, p);
+
+    if ((int) buf & 1) {
+        // Unaligned buffer, so assemble each word manually
+        for (i=0; i<nword; ++i) {
+            w  = *buf++;
+            w |= (cyg_uint16) (*buf++) << 8;
+            HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, w);
+        }
     }
-    return 1;
+    else {
+        cyg_uint16* wbuf = (cyg_uint16*) buf;
+        for (i=0; i<nword; ++i)
+            HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, *wbuf++);
+    }
+    return (int) len;
 }
 
 // ----------------------------------------------------------------------------
@@ -328,6 +389,11 @@ ide_disk_init(struct cyg_devtab_entry *t
         D("No IDE controller for channel %d:%d\n", info->port, info->chan);
         return false;
     }
+
+#if CYGDAT_DEVS_DISK_IDE_STARTUP_DELAY
+    CYGACC_CALL_IF_DELAY_US(CYGDAT_DEVS_DISK_IDE_STARTUP_DELAY*1000U);
+#endif
+
     if (!ide_present[info->port]) {
         ide_present[info->port]=ide_presence_detect(info->port);
         if (!ide_present[info->port]) {
@@ -342,6 +408,13 @@ ide_disk_init(struct cyg_devtab_entry *t
             return false;
         }
     }
+
+#ifdef CYGDAT_DEVS_DISK_IDE_8_BIT_DATA_PATH
+    if (!ide_8bit_mode(info->port, info->chan, true)) {
+        D("IDE disk %d:%d failed to enter 8-bit mode\n",
+          info->port, info->chan);
+    }
+#endif
     
     D("IDE %d:%d identify drive\n", info->port, info->chan);
     
@@ -350,9 +423,9 @@ ide_disk_init(struct cyg_devtab_entry *t
         return false;
     }
 
-    id_strcpy(ident.serial, ide_idData->serial,       20);
+    id_strcpy(ident.serial, ide_idData->serial, 20);
     id_strcpy(ident.firmware_rev, ide_idData->firmware_rev, 8);
-    id_strcpy(ident.model_num, ide_idData->model_num,    40);
+    id_strcpy(ident.model_num, ide_idData->model_num, 40);
     
     ident.cylinders_num  = ide_idData->num_cylinders;
     ident.heads_num = ide_idData->num_heads;
@@ -360,6 +433,8 @@ ide_disk_init(struct cyg_devtab_entry *t
     ident.lba_sectors_num = ide_idData->lba_total_sectors[1] << 16 | 
                             ide_idData->lba_total_sectors[0];
     ident.phys_block_size = 1;
+
+    // TODO: Should this be CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE?
     ident.max_transfer = 512;
     
     D("\tSerial : %s\n", ident.serial);
@@ -367,13 +442,7 @@ ide_disk_init(struct cyg_devtab_entry *t
     D("\tModel : %s\n", ident.model_num);
     D("\tC/H/S : %d/%d/%d\n", ident.cylinders_num, 
                               ident.heads_num, ident.sectors_num);
-    D("\tKind : %x\n", (ide_idData->general_conf>>8)&0x1f);
 
-    if (((ide_idData->general_conf>>8)&0x1f)!=2) {
-        diag_printf("IDE device %d:%d is not a hard disk!\n",
-                    info->port, info->chan);
-        return false;
-    }
     if (!(chan->callbacks->disk_init)(tab))
         return false;