diff options
author | Tejun Heo <htejun@gmail.com> | 2006-04-11 09:32:19 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-04-11 13:31:36 -0400 |
commit | ecc2e2b9c97719592b3078d5a5a8666551c91115 (patch) | |
tree | a941aa2a8f8daacc8d21990a7b1b85a767c5de5c /drivers/scsi/sata_sil24.c | |
parent | 0eaa6058a6a664ce692e3dc38c6891a74ca47f59 (diff) |
[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>
Diffstat (limited to 'drivers/scsi/sata_sil24.c')
-rw-r--r-- | drivers/scsi/sata_sil24.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index be4817e6502b..4180c81f639c 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c | |||
@@ -521,10 +521,47 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) | |||
521 | 521 | ||
522 | static int sil24_hardreset(struct ata_port *ap, unsigned int *class) | 522 | static int sil24_hardreset(struct ata_port *ap, unsigned int *class) |
523 | { | 523 | { |
524 | unsigned int dummy_class; | 524 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
525 | const char *reason; | ||
526 | int tout_msec; | ||
527 | u32 tmp; | ||
528 | |||
529 | /* sil24 does the right thing(tm) without any protection */ | ||
530 | ata_set_sata_spd(ap); | ||
531 | |||
532 | tout_msec = 100; | ||
533 | if (sata_dev_present(ap)) | ||
534 | tout_msec = 5000; | ||
535 | |||
536 | writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); | ||
537 | tmp = ata_wait_register(port + PORT_CTRL_STAT, | ||
538 | PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec); | ||
539 | |||
540 | /* SStatus oscillates between zero and valid status for short | ||
541 | * duration after DEV_RST, give it time to settle. | ||
542 | */ | ||
543 | msleep(100); | ||
544 | |||
545 | if (tmp & PORT_CS_DEV_RST) { | ||
546 | if (!sata_dev_present(ap)) | ||
547 | return 0; | ||
548 | reason = "link not ready"; | ||
549 | goto err; | ||
550 | } | ||
551 | |||
552 | if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { | ||
553 | reason = "device not ready"; | ||
554 | goto err; | ||
555 | } | ||
525 | 556 | ||
526 | /* sil24 doesn't report device signature after hard reset */ | 557 | /* sil24 doesn't report device class code after hardreset, |
527 | return sata_std_hardreset(ap, &dummy_class); | 558 | * leave *class alone. |
559 | */ | ||
560 | return 0; | ||
561 | |||
562 | err: | ||
563 | printk(KERN_ERR "ata%u: hardreset failed (%s)\n", ap->id, reason); | ||
564 | return -EIO; | ||
528 | } | 565 | } |
529 | 566 | ||
530 | static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes) | 567 | static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes) |