[PATCH] sata_sil24: reimplement hardreset
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>
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index be4817e..4180c81 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -521,10 +521,47 @@
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 doesn't report device signature after hard reset */
- return sata_std_hardreset(ap, &dummy_class);
+ /* 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 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)