diff options
author | Tejun Heo <htejun@gmail.com> | 2007-07-16 01:29:39 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-07-20 08:02:10 -0400 |
commit | 91c4a2e09267b0ddc8e59d121e3748cd18675739 (patch) | |
tree | 6f4d6adfddaf88f60fd2c1c29ce1785fda52cc52 /drivers/ata/ahci.c | |
parent | d2e75dfffbe9e86e1d646264792ac9bcd2cc4267 (diff) |
ahci: separate out ahci_exec_polled_cmd()
Separate out ahci_exec_polled_cmd() from ahci_softreset(). This will
be used to implement ahci_pmp_read/write(). ahci_exec_polled_cmd()
performs reset_engine before returning if the command fails (times
out). This is to improve robustness.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 1be238def0ed..db65f4a16021 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -993,17 +993,42 @@ static int ahci_kick_engine(struct ata_port *ap, int force_restart) | |||
993 | return rc; | 993 | return rc; |
994 | } | 994 | } |
995 | 995 | ||
996 | static int ahci_softreset(struct ata_port *ap, unsigned int *class, | 996 | static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, |
997 | unsigned long deadline) | 997 | struct ata_taskfile *tf, int is_cmd, u16 flags, |
998 | unsigned long timeout_msec) | ||
998 | { | 999 | { |
1000 | const u32 cmd_fis_len = 5; /* five dwords */ | ||
999 | struct ahci_port_priv *pp = ap->private_data; | 1001 | struct ahci_port_priv *pp = ap->private_data; |
1000 | void __iomem *port_mmio = ahci_port_base(ap); | 1002 | void __iomem *port_mmio = ahci_port_base(ap); |
1001 | const u32 cmd_fis_len = 5; /* five dwords */ | 1003 | u8 *fis = pp->cmd_tbl; |
1004 | u32 tmp; | ||
1005 | |||
1006 | /* prep the command */ | ||
1007 | ata_tf_to_fis(tf, pmp, is_cmd, fis); | ||
1008 | ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); | ||
1009 | |||
1010 | /* issue & wait */ | ||
1011 | writel(1, port_mmio + PORT_CMD_ISSUE); | ||
1012 | |||
1013 | if (timeout_msec) { | ||
1014 | tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, | ||
1015 | 1, timeout_msec); | ||
1016 | if (tmp & 0x1) { | ||
1017 | ahci_kick_engine(ap, 1); | ||
1018 | return -EBUSY; | ||
1019 | } | ||
1020 | } else | ||
1021 | readl(port_mmio + PORT_CMD_ISSUE); /* flush */ | ||
1022 | |||
1023 | return 0; | ||
1024 | } | ||
1025 | |||
1026 | static int ahci_softreset(struct ata_port *ap, unsigned int *class, | ||
1027 | unsigned long deadline) | ||
1028 | { | ||
1002 | const char *reason = NULL; | 1029 | const char *reason = NULL; |
1003 | unsigned long now, msecs; | 1030 | unsigned long now, msecs; |
1004 | struct ata_taskfile tf; | 1031 | struct ata_taskfile tf; |
1005 | u32 tmp; | ||
1006 | u8 *fis; | ||
1007 | int rc; | 1032 | int rc; |
1008 | 1033 | ||
1009 | DPRINTK("ENTER\n"); | 1034 | DPRINTK("ENTER\n"); |
@@ -1021,7 +1046,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, | |||
1021 | "failed to reset engine (errno=%d)", rc); | 1046 | "failed to reset engine (errno=%d)", rc); |
1022 | 1047 | ||
1023 | ata_tf_init(ap->device, &tf); | 1048 | ata_tf_init(ap->device, &tf); |
1024 | fis = pp->cmd_tbl; | ||
1025 | 1049 | ||
1026 | /* issue the first D2H Register FIS */ | 1050 | /* issue the first D2H Register FIS */ |
1027 | msecs = 0; | 1051 | msecs = 0; |
@@ -1029,16 +1053,9 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, | |||
1029 | if (time_after(now, deadline)) | 1053 | if (time_after(now, deadline)) |
1030 | msecs = jiffies_to_msecs(deadline - now); | 1054 | msecs = jiffies_to_msecs(deadline - now); |
1031 | 1055 | ||
1032 | ahci_fill_cmd_slot(pp, 0, | ||
1033 | cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); | ||
1034 | |||
1035 | tf.ctl |= ATA_SRST; | 1056 | tf.ctl |= ATA_SRST; |
1036 | ata_tf_to_fis(&tf, 0, 0, fis); | 1057 | if (ahci_exec_polled_cmd(ap, 0, &tf, 0, |
1037 | 1058 | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { | |
1038 | writel(1, port_mmio + PORT_CMD_ISSUE); | ||
1039 | |||
1040 | tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, msecs); | ||
1041 | if (tmp & 0x1) { | ||
1042 | rc = -EIO; | 1059 | rc = -EIO; |
1043 | reason = "1st FIS failed"; | 1060 | reason = "1st FIS failed"; |
1044 | goto fail; | 1061 | goto fail; |
@@ -1048,13 +1065,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, | |||
1048 | msleep(1); | 1065 | msleep(1); |
1049 | 1066 | ||
1050 | /* issue the second D2H Register FIS */ | 1067 | /* issue the second D2H Register FIS */ |
1051 | ahci_fill_cmd_slot(pp, 0, cmd_fis_len); | ||
1052 | |||
1053 | tf.ctl &= ~ATA_SRST; | 1068 | tf.ctl &= ~ATA_SRST; |
1054 | ata_tf_to_fis(&tf, 0, 0, fis); | 1069 | ahci_exec_polled_cmd(ap, 0, &tf, 0, 0, 0); |
1055 | |||
1056 | writel(1, port_mmio + PORT_CMD_ISSUE); | ||
1057 | readl(port_mmio + PORT_CMD_ISSUE); /* flush */ | ||
1058 | 1070 | ||
1059 | /* spec mandates ">= 2ms" before checking status. | 1071 | /* spec mandates ">= 2ms" before checking status. |
1060 | * We wait 150ms, because that was the magic delay used for | 1072 | * We wait 150ms, because that was the magic delay used for |