Author: mav
Date: Thu Sep  2 11:18:43 2010
New Revision: 212145
URL: http://svn.freebsd.org/changeset/base/212145

Log:
  SATA1.x SiliconImage controllers on power-on reset TFD Status register into
  value 0xff. On hot-plug this value confuses ata_generic_reset() device
  presence detection logic. As soon as we already know drive presence from
  SATA hard reset, hint ata_generic_reset() to wait for device signature
  until success or full timeout.

Modified:
  head/sys/dev/ata/ata-all.h
  head/sys/dev/ata/ata-lowlevel.c
  head/sys/dev/ata/chipsets/ata-siliconimage.c

Modified: head/sys/dev/ata/ata-all.h
==============================================================================
--- head/sys/dev/ata/ata-all.h  Thu Sep  2 09:45:06 2010        (r212144)
+++ head/sys/dev/ata/ata-all.h  Thu Sep  2 11:18:43 2010        (r212145)
@@ -565,6 +565,7 @@ struct ata_channel {
 #define         ATA_NO_ATAPI_DMA       0x40
 #define         ATA_SATA               0x80
 #define         ATA_DMA_BEFORE_CMD     0x100
+#define         ATA_KNOWN_PRESENCE     0x200
 
     int                                pm_level;       /* power management 
level */
     int                         devices;        /* what is present */

Modified: head/sys/dev/ata/ata-lowlevel.c
==============================================================================
--- head/sys/dev/ata/ata-lowlevel.c     Thu Sep  2 09:45:06 2010        
(r212144)
+++ head/sys/dev/ata/ata-lowlevel.c     Thu Sep  2 11:18:43 2010        
(r212145)
@@ -474,7 +474,8 @@ ata_generic_reset(device_t dev)
     ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER));
     DELAY(10);
     ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
-    if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
+    if (((ostat0 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) &&
+           ostat0 != 0xa5) {
        stat0 = ATA_S_BUSY;
        mask |= 0x01;
     }
@@ -484,7 +485,8 @@ ata_generic_reset(device_t dev)
        ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_SLAVE));
        DELAY(10);      
        ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
-       if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
+       if (((ostat1 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) &&
+               ostat1 != 0xa5) {
            stat1 = ATA_S_BUSY;
            mask |= 0x02;
        }
@@ -570,22 +572,16 @@ ata_generic_reset(device_t dev)
            }
        }
 
-       if (mask == 0x00)       /* nothing to wait for */
-           break;
-       if (mask == 0x01)       /* wait for master only */
-           if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10))
-               break;
-       if (mask == 0x02)       /* wait for slave only */
-           if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 10))
-               break;
-       if (mask == 0x03) {     /* wait for both master & slave */
-           if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
-               break;
-           if ((stat0 == 0xff) && (timeout > 20))
-               mask &= ~0x01;
-           if ((stat1 == 0xff) && (timeout > 20))
-               mask &= ~0x02;
+       if ((ch->flags & ATA_KNOWN_PRESENCE) == 0 &&
+           timeout > ((mask == 0x03) ? 20 : 10)) {
+               if ((mask & 0x01) && stat0 == 0xff)
+                       mask &= ~0x01;
+               if ((mask & 0x02) && stat1 == 0xff)
+                       mask &= ~0x02;
        }
+       if (((mask & 0x01) == 0 || !(stat0 & ATA_S_BUSY)) &&
+           ((mask & 0x02) == 0 || !(stat1 & ATA_S_BUSY)))
+               break;
        ata_udelay(100000);
     }
 

Modified: head/sys/dev/ata/chipsets/ata-siliconimage.c
==============================================================================
--- head/sys/dev/ata/chipsets/ata-siliconimage.c        Thu Sep  2 09:45:06 
2010        (r212144)
+++ head/sys/dev/ata/chipsets/ata-siliconimage.c        Thu Sep  2 11:18:43 
2010        (r212145)
@@ -316,6 +316,7 @@ ata_sii_ch_attach(device_t dev)
        ch->r_io[ATA_SCONTROL].offset = 0x100 + (unit01 << 7) + (unit10 << 8);
        ch->flags |= ATA_NO_SLAVE;
        ch->flags |= ATA_SATA;
+       ch->flags |= ATA_KNOWN_PRESENCE;
 
        /* enable PHY state change interrupt */
        ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16));
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to