[PATCH] sata_sil24: reimplement hardreset
authorTejun Heo <htejun@gmail.com>
Tue, 11 Apr 2006 13:32:19 +0000 (22:32 +0900)
committerJeff Garzik <jeff@garzik.org>
Tue, 11 Apr 2006 17:31:36 +0000 (13:31 -0400)
Reimplement hardreset according to the datasheet.  The old hardreset
didn't reset controller status and the controller might not be ready
after reset.  Also, as SStatus is a bit flakey after hardreset,
sata_std_hardrset() didn't use to wait long enough before proceeding.

Note that as we're not depending on SStatus, DET==1 condition cannot
be used to wait for link, so use shorter timeout for no device case.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/scsi/sata_sil24.c

index be4817e6502bfd9573d95d06887adc40d67092dc..4180c81f639cf779b2fdcdb0f382145789f81bdc 100644 (file)
@@ -521,10 +521,47 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
 
 static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
 {
-       unsigned int dummy_class;
+       void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+       const char *reason;
+       int tout_msec;
+       u32 tmp;
+
+       /* sil24 does the right thing(tm) without any protection */
+       ata_set_sata_spd(ap);
+
+       tout_msec = 100;
+       if (sata_dev_present(ap))
+               tout_msec = 5000;
+
+       writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
+       tmp = ata_wait_register(port + PORT_CTRL_STAT,
+                               PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
+
+       /* SStatus oscillates between zero and valid status for short
+        * duration after DEV_RST, give it time to settle.
+        */
+       msleep(100);
+
+       if (tmp & PORT_CS_DEV_RST) {
+               if (!sata_dev_present(ap))
+                       return 0;
+               reason = "link not ready";
+               goto err;
+       }
+
+       if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+               reason = "device not ready";
+               goto err;
+       }
 
-       /* sil24 doesn't report device signature after hard reset */
-       return sata_std_hardreset(ap, &dummy_class);
+       /* sil24 doesn't report device class code after hardreset,
+        * leave *class alone.
+        */
+       return 0;
+
+ err:
+       printk(KERN_ERR "ata%u: hardreset failed (%s)\n", ap->id, reason);
+       return -EIO;
 }
 
 static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes)