patch; svn186316; SATA port multiplier disk detect bugs

James R. Van Artsdalen james-freebsd-current at jrv.org
Fri Dec 19 10:22:19 UTC 2008


This only affects Silicon Image host controllers.  It was only tested
with a Sil3132.

I have found two bugs in the port multiplier code and a place where an
added delay is both necessary and sufficient to make my setup work, even
though I can't explain why.

The first change in ata_siiprb_issue_cmd() increases the timeout count
from 10,000 to 31,000 counts.  When a soft reset is issued to a port
multiplier disk port this loop may have to wait for the hard disk to
spin up.  I consistently saw 15,000 counts as needed by experiment;
assuming counts are milliseconds then 31,000 is what ATA calls for. 
Note that currently empty disk ports behind a port multiplier are
detected by letting this loop time out; i.e., an empty port multiplier
enclosure can lengthen boot time by 2.5 minutes.  Some other strategy
for disk detection might be needed later (the PHY probably is a good
approach).

The second change in ata_siiprb_issue_cmd() fixes a typo: failure was
being returned if a command took more than 1,000 counts even if it
completed within the allotted 10,000 counts.

The last change in ata_siiprb_softreset() is a delay that mysteriously
turns out to be necessary.  I don't know why, how much or how little is
needed.  Hardware is like that sometimes.

With this my setup, with a Sil3132 host controller, always detects the
drives in my Sil3726-based port-multiplier enclosures.

There are other severe problems in usage, especially on my 12GB RAM
system, but at least this may let people get past disk detection and on
to those other issues.

/usr/src-current# svn di
Index: sys/dev/ata/chipsets/ata-siliconimage.c
===================================================================
--- sys/dev/ata/chipsets/ata-siliconimage.c     (revision 186316)
+++ sys/dev/ata/chipsets/ata-siliconimage.c     (working copy)
@@ -679,7 +679,7 @@
     ATA_OUTL(ctlr->r_res2, 0x1c04 + offset, prb_bus >> 32);
 
     /* poll for command finished */
-    for (timeout = 0; timeout < 10000; timeout++) {
+    for (timeout = 0; timeout < 31000; timeout++) {
         DELAY(1000);
         if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000)
             break;
@@ -687,7 +687,7 @@
     // SOS XXX ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x00010000);
     ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x08ff08ff);
 
-    if (timeout >= 1000)
+    if (timeout >= 31000)
        return EIO;
 
     if (bootverbose)
@@ -761,6 +761,18 @@
     prb->control = htole16(0x0080);
     prb->fis[1] = port & 0x0f;
 
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+    ata_udelay(150000);
+
     /* issue soft reset */
     if (ata_siiprb_issue_cmd(dev))
        return -1;
/usr/src-current#


More information about the freebsd-current mailing list