From 9977126c4b65c1396b665f7a0eeb8c7dede336f9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:38 +0900 Subject: libata: add @is_cmd to ata_tf_to_fis() Add @is_cmd to ata_tf_to_fis(). This controls bit 7 of the second byte which tells the device whether this H2D FIS is for a command or not. This cleans up ahci a bit and will be used by PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index 47cd2a1c5544..5d3df6cde272 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -764,7 +764,8 @@ extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *); */ extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp); +extern void ata_tf_to_fis(const struct ata_taskfile *tf, + u8 pmp, int is_cmd, u8 *fis); extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf); extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device); extern void ata_std_dev_select (struct ata_port *ap, unsigned int device); -- cgit v1.2.3 From b64bbc39f2122a2276578e40144af69ef01decd4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:39 +0900 Subject: libata: improve EH report formatting Requiring LLDs to format multiple error description messages properly doesn't work too well. Help LLDs a bit by making ata_ehi_push_desc() insert ", " on each invocation. __ata_ehi_push_desc() is the raw version without the automatic separator. While at it, make ehi_desc interface proper functions instead of macros. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 6 ++--- drivers/ata/libata-core.c | 3 +++ drivers/ata/libata-eh.c | 69 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/ata/sata_mv.c | 8 +++--- drivers/ata/sata_nv.c | 22 ++++++++------- drivers/ata/sata_sil24.c | 12 ++++----- include/linux/libata.h | 13 +++------ 7 files changed, 98 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c5034d450c62..210292cd8ad1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1289,12 +1289,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) if (irq_stat & PORT_IRQ_IF_ERR) { err_mask |= AC_ERR_ATA_BUS; action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, ", interface fatal error"); + ata_ehi_push_desc(ehi, "interface fatal error"); } if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? + ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ? "connection status changed" : "PHY RDY changed"); } @@ -1303,7 +1303,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) err_mask |= AC_ERR_HSM; action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x", + ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x", unk[0], unk[1], unk[2], unk[3]); } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 39a8e986a4ea..ecbc3278238a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6945,6 +6945,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); +EXPORT_SYMBOL_GPL(ata_ehi_push_desc); +EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_port_abort); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9aa62a0754f6..96b184ebf708 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -85,6 +85,71 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) { } #endif /* CONFIG_PM */ +static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt, + va_list args) +{ + ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len, + ATA_EH_DESC_LEN - ehi->desc_len, + fmt, args); +} + +/** + * __ata_ehi_push_desc - push error description without adding separator + * @ehi: target EHI + * @fmt: printf format string + * + * Format string according to @fmt and append it to @ehi->desc. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + __ata_ehi_pushv_desc(ehi, fmt, args); + va_end(args); +} + +/** + * ata_ehi_push_desc - push error description with separator + * @ehi: target EHI + * @fmt: printf format string + * + * Format string according to @fmt and append it to @ehi->desc. + * If @ehi->desc is not empty, ", " is added in-between. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...) +{ + va_list args; + + if (ehi->desc_len) + __ata_ehi_push_desc(ehi, ", "); + + va_start(args, fmt); + __ata_ehi_pushv_desc(ehi, fmt, args); + va_end(args); +} + +/** + * ata_ehi_clear_desc - clean error description + * @ehi: target EHI + * + * Clear @ehi->desc. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +void ata_ehi_clear_desc(struct ata_eh_info *ehi) +{ + ehi->desc[0] = '\0'; + ehi->desc_len = 0; +} + static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) { @@ -1524,14 +1589,14 @@ static void ata_eh_report(struct ata_port *ap) ehc->i.err_mask, ap->sactive, ehc->i.serror, ehc->i.action, frozen); if (desc) - ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc); + ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", ehc->i.err_mask, ap->sactive, ehc->i.serror, ehc->i.action, frozen); if (desc) - ata_port_printk(ap, KERN_ERR, "(%s)\n", desc); + ata_port_printk(ap, KERN_ERR, "%s\n", desc); } for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 80ade5b93b86..b4b737e081e8 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1411,12 +1411,12 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) EDMA_ERR_INTRL_PAR)) { err_mask |= AC_ERR_ATA_BUS; action |= ATA_EH_HARDRESET; - ata_ehi_push_desc(ehi, ", parity error"); + ata_ehi_push_desc(ehi, "parity error"); } if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) { ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ? - ", dev disconnect" : ", dev connect"); + "dev disconnect" : "dev connect"); } if (IS_GEN_I(hpriv)) { @@ -1425,7 +1425,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) if (edma_err_cause & EDMA_ERR_SELF_DIS_5) { struct mv_port_priv *pp = ap->private_data; pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; - ata_ehi_push_desc(ehi, ", EDMA self-disable"); + ata_ehi_push_desc(ehi, "EDMA self-disable"); } } else { eh_freeze_mask = EDMA_EH_FREEZE; @@ -1433,7 +1433,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) if (edma_err_cause & EDMA_ERR_SELF_DIS) { struct mv_port_priv *pp = ap->private_data; pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; - ata_ehi_push_desc(ehi, ", EDMA self-disable"); + ata_ehi_push_desc(ehi, "EDMA self-disable"); } if (edma_err_cause & EDMA_ERR_SERR) { diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index db81e3efa5ec..5d943da042f7 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -715,19 +715,20 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) int freeze = 0; ata_ehi_clear_desc(ehi); - ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags ); + __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags ); if (flags & NV_CPB_RESP_ATA_ERR) { - ata_ehi_push_desc(ehi, ": ATA error"); + ata_ehi_push_desc(ehi, "ATA error"); ehi->err_mask |= AC_ERR_DEV; } else if (flags & NV_CPB_RESP_CMD_ERR) { - ata_ehi_push_desc(ehi, ": CMD error"); + ata_ehi_push_desc(ehi, "CMD error"); ehi->err_mask |= AC_ERR_DEV; } else if (flags & NV_CPB_RESP_CPB_ERR) { - ata_ehi_push_desc(ehi, ": CPB error"); + ata_ehi_push_desc(ehi, "CPB error"); ehi->err_mask |= AC_ERR_SYSTEM; freeze = 1; } else { /* notifier error, but no error in CPB flags? */ + ata_ehi_push_desc(ehi, "unknown"); ehi->err_mask |= AC_ERR_OTHER; freeze = 1; } @@ -854,20 +855,21 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) struct ata_eh_info *ehi = &ap->eh_info; ata_ehi_clear_desc(ehi); - ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status ); + __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status ); if (status & NV_ADMA_STAT_TIMEOUT) { ehi->err_mask |= AC_ERR_SYSTEM; - ata_ehi_push_desc(ehi, ": timeout"); + ata_ehi_push_desc(ehi, "timeout"); } else if (status & NV_ADMA_STAT_HOTPLUG) { ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, ": hotplug"); + ata_ehi_push_desc(ehi, "hotplug"); } else if (status & NV_ADMA_STAT_HOTUNPLUG) { ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, ": hot unplug"); + ata_ehi_push_desc(ehi, "hot unplug"); } else if (status & NV_ADMA_STAT_SERROR) { /* let libata analyze SError and figure out the cause */ - ata_ehi_push_desc(ehi, ": SError"); - } + ata_ehi_push_desc(ehi, "SError"); + } else + ata_ehi_push_desc(ehi, "unknown"); ata_port_freeze(ap); continue; } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e538edc1b4ea..e201f1cab66d 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -814,16 +814,16 @@ static void sil24_error_intr(struct ata_port *ap) if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, ", %s", - irq_stat & PORT_IRQ_PHYRDY_CHG ? - "PHY RDY changed" : "device exchanged"); + ata_ehi_push_desc(ehi, "%s", + irq_stat & PORT_IRQ_PHYRDY_CHG ? + "PHY RDY changed" : "device exchanged"); freeze = 1; } if (irq_stat & PORT_IRQ_UNK_FIS) { ehi->err_mask |= AC_ERR_HSM; ehi->action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi , ", unknown FIS"); + ata_ehi_push_desc(ehi, "unknown FIS"); freeze = 1; } @@ -842,11 +842,11 @@ static void sil24_error_intr(struct ata_port *ap) if (ci && ci->desc) { err_mask |= ci->err_mask; action |= ci->action; - ata_ehi_push_desc(ehi, ", %s", ci->desc); + ata_ehi_push_desc(ehi, "%s", ci->desc); } else { err_mask |= AC_ERR_OTHER; action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, ", unknown command error %d", + ata_ehi_push_desc(ehi, "unknown command error %d", cerr); } diff --git a/include/linux/libata.h b/include/linux/libata.h index 5d3df6cde272..94b37d180680 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -910,16 +910,9 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, /* * ata_eh_info helpers */ -#define ata_ehi_push_desc(ehi, fmt, args...) do { \ - (ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \ - ATA_EH_DESC_LEN - (ehi)->desc_len, \ - fmt , ##args); \ -} while (0) - -#define ata_ehi_clear_desc(ehi) do { \ - (ehi)->desc[0] = '\0'; \ - (ehi)->desc_len = 0; \ -} while (0) +extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...); +extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...); +extern void ata_ehi_clear_desc(struct ata_eh_info *ehi); static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi) { -- cgit v1.2.3 From 5335b729064e03319cd2d5219770451dbb1d7f67 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:40 +0900 Subject: libata: implement AC_ERR_NCQ When an NCQ command fails, all commands in flight are aborted and the offending one is reported using log page 10h. Depending on controller characteristics and LLD implementation, all commands may appear as having a device error due to shared TF status making it hard to determine what's actually going on. This patch adds AC_ERR_NCQ, marks the command reported by log page 10h with it and print extra "" after the error report for the command to help distinguishing the offending command. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 7 ++++--- include/linux/libata.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 96b184ebf708..19f9947bd96b 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1195,7 +1195,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) /* we've got the perpetrator, condemn it */ qc = __ata_qc_from_tag(ap, tag); memcpy(&qc->result_tf, &tf, sizeof(tf)); - qc->err_mask |= AC_ERR_DEV; + qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; ehc->i.err_mask &= ~AC_ERR_DEV; } @@ -1616,7 +1616,7 @@ static void ata_eh_report(struct ata_port *ap) "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "tag %d cdb 0x%x data %u %s\n " "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " - "Emask 0x%x (%s)\n", + "Emask 0x%x (%s)%s\n", cmd->command, cmd->feature, cmd->nsect, cmd->lbal, cmd->lbam, cmd->lbah, cmd->hob_feature, cmd->hob_nsect, @@ -1627,7 +1627,8 @@ static void ata_eh_report(struct ata_port *ap) res->lbal, res->lbam, res->lbah, res->hob_feature, res->hob_nsect, res->hob_lbal, res->hob_lbam, res->hob_lbah, - res->device, qc->err_mask, ata_err_string(qc->err_mask)); + res->device, qc->err_mask, ata_err_string(qc->err_mask), + qc->err_mask & AC_ERR_NCQ ? " " : ""); } } diff --git a/include/linux/libata.h b/include/linux/libata.h index 94b37d180680..cb181713d9b5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -323,6 +323,7 @@ enum ata_completion_errors { AC_ERR_INVALID = (1 << 7), /* invalid argument */ AC_ERR_OTHER = (1 << 8), /* unknown */ AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */ + AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */ }; /* forward declarations */ -- cgit v1.2.3 From da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:40 +0900 Subject: libata: make ->scr_read/write callbacks return error code Convert ->scr_read/write callbacks to return error code to better indicate failure. This will help handling of SCR_NOTIFICATION. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 23 ++++++++------- drivers/ata/libata-core.c | 21 +++++++------ drivers/ata/sata_inic162x.c | 16 +++++----- drivers/ata/sata_mv.c | 72 ++++++++++++++++++++++++++++++--------------- drivers/ata/sata_nv.c | 16 +++++----- drivers/ata/sata_promise.c | 25 +++++++++------- drivers/ata/sata_qstor.c | 16 +++++----- drivers/ata/sata_sil.c | 25 ++++++++++------ drivers/ata/sata_sil24.c | 17 +++++++---- drivers/ata/sata_sis.c | 22 +++++++------- drivers/ata/sata_svw.c | 13 ++++---- drivers/ata/sata_uli.c | 16 +++++----- drivers/ata/sata_via.c | 27 +++++++++-------- drivers/ata/sata_vsc.c | 13 ++++---- include/linux/libata.h | 5 ++-- 15 files changed, 191 insertions(+), 136 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 210292cd8ad1..e044d6477a0f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -216,8 +216,8 @@ struct ahci_port_priv { unsigned int ncq_saw_sdb:1; }; -static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); static void ahci_irq_clear(struct ata_port *ap); @@ -625,7 +625,7 @@ static void ahci_restore_initial_config(struct ata_host *host) (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ } -static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) +static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) { unsigned int sc_reg; @@ -635,15 +635,15 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) case SCR_ERROR: sc_reg = 2; break; case SCR_ACTIVE: sc_reg = 3; break; default: - return 0xffffffffU; + return -EINVAL; } - return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } -static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, - u32 val) +static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { unsigned int sc_reg; @@ -653,10 +653,11 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, case SCR_ERROR: sc_reg = 2; break; case SCR_ACTIVE: sc_reg = 3; break; default: - return; + return -EINVAL; } writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } static void ahci_start_engine(struct ata_port *ap) @@ -1133,6 +1134,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, unsigned long deadline) { + u32 serror; int rc; DPRINTK("ENTER\n"); @@ -1143,7 +1145,8 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, deadline); /* vt8251 needs SError cleared for the port to operate */ - ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); + ahci_scr_read(ap, SCR_ERROR, &serror); + ahci_scr_write(ap, SCR_ERROR, serror); ahci_start_engine(ap); @@ -1265,7 +1268,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) ata_ehi_clear_desc(ehi); /* AHCI needs SError cleared; otherwise, it might lock up */ - serror = ahci_scr_read(ap, SCR_ERROR); + ahci_scr_read(ap, SCR_ERROR, &serror); ahci_scr_write(ap, SCR_ERROR, serror); /* analyze @irq_stat */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ecbc3278238a..5718c247e23a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5732,10 +5732,8 @@ int sata_scr_valid(struct ata_port *ap) */ int sata_scr_read(struct ata_port *ap, int reg, u32 *val) { - if (sata_scr_valid(ap)) { - *val = ap->ops->scr_read(ap, reg); - return 0; - } + if (sata_scr_valid(ap)) + return ap->ops->scr_read(ap, reg, val); return -EOPNOTSUPP; } @@ -5757,10 +5755,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val) */ int sata_scr_write(struct ata_port *ap, int reg, u32 val) { - if (sata_scr_valid(ap)) { - ap->ops->scr_write(ap, reg, val); - return 0; - } + if (sata_scr_valid(ap)) + return ap->ops->scr_write(ap, reg, val); return -EOPNOTSUPP; } @@ -5781,10 +5777,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val) */ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) { + int rc; + if (sata_scr_valid(ap)) { - ap->ops->scr_write(ap, reg, val); - ap->ops->scr_read(ap, reg); - return 0; + rc = ap->ops->scr_write(ap, reg, val); + if (rc == 0) + rc = ap->ops->scr_read(ap, reg, &val); + return rc; } return -EOPNOTSUPP; } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 3de183461c3c..a9c948d7604a 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base) writew(ctl, idma_ctl); } -static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg) +static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val) { void __iomem *scr_addr = ap->ioaddr.scr_addr; void __iomem *addr; - u32 val; if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) - return 0xffffffffU; + return -EINVAL; addr = scr_addr + scr_map[sc_reg] * 4; - val = readl(scr_addr + scr_map[sc_reg] * 4); + *val = readl(scr_addr + scr_map[sc_reg] * 4); /* this controller has stuck DIAG.N, ignore it */ if (sc_reg == SCR_ERROR) - val &= ~SERR_PHYRDY_CHG; - return val; + *val &= ~SERR_PHYRDY_CHG; + return 0; } -static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) +static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) { void __iomem *scr_addr = ap->ioaddr.scr_addr; void __iomem *addr; if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) - return; + return -EINVAL; addr = scr_addr + scr_map[sc_reg] * 4; writel(val, scr_addr + scr_map[sc_reg] * 4); + return 0; } /* diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index b4b737e081e8..8ec520885b95 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -404,10 +404,10 @@ struct mv_host_priv { }; static void mv_irq_clear(struct ata_port *ap); -static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in); -static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); -static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in); -static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); +static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); +static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static int mv_port_start(struct ata_port *ap); static void mv_port_stop(struct ata_port *ap); static void mv_qc_prep(struct ata_queued_cmd *qc); @@ -974,22 +974,26 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in) return ofs; } -static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in) +static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) { unsigned int ofs = mv_scr_offset(sc_reg_in); - if (ofs != 0xffffffffU) - return readl(mv_ap_base(ap) + ofs); - else - return (u32) ofs; + if (ofs != 0xffffffffU) { + *val = readl(mv_ap_base(ap) + ofs); + return 0; + } else + return -EINVAL; } -static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) +static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { unsigned int ofs = mv_scr_offset(sc_reg_in); - if (ofs != 0xffffffffU) + if (ofs != 0xffffffffU) { writelfl(val, mv_ap_base(ap) + ofs); + return 0; + } else + return -EINVAL; } static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv, @@ -1752,26 +1756,30 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in) return ofs; } -static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in) +static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) { void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); - if (ofs != 0xffffffffU) - return readl(addr + ofs); - else - return (u32) ofs; + if (ofs != 0xffffffffU) { + *val = readl(addr + ofs); + return 0; + } else + return -EINVAL; } -static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) +static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); - if (ofs != 0xffffffffU) + if (ofs != 0xffffffffU) { writelfl(val, addr + ofs); + return 0; + } else + return -EINVAL; } static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) @@ -2149,9 +2157,17 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class, VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio); - DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " - "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), - mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); +#ifdef DEBUG + { + u32 sstatus, serror, scontrol; + + mv_scr_read(ap, SCR_STATUS, &sstatus); + mv_scr_read(ap, SCR_ERROR, &serror); + mv_scr_read(ap, SCR_CONTROL, &scontrol); + DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", status, serror, scontrol); + } +#endif /* Issue COMRESET via SControl */ comreset_retry: @@ -2175,9 +2191,17 @@ comreset_retry: (retry-- > 0)) goto comreset_retry; - DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " - "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS), - mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL)); +#ifdef DEBUG + { + u32 sstatus, serror, scontrol; + + mv_scr_read(ap, SCR_STATUS, &sstatus); + mv_scr_read(ap, SCR_ERROR, &serror); + mv_scr_read(ap, SCR_CONTROL, &scontrol); + DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x " + "SCtrl 0x%08x\n", sstatus, serror, scontrol); + } +#endif if (ata_port_offline(ap)) { *class = ATA_DEV_NONE; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 5d943da042f7..0b58c4df6fd2 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance); static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); -static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap); @@ -1393,20 +1393,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance) return ret; } -static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { if (sc_reg > SCR_CONTROL) - return 0xffffffffU; + return -EINVAL; - return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); + *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } -static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) - return; + return -EINVAL; iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } static void nv_nf2_freeze(struct ata_port *ap) diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index d2fcb9a6bec2..d39ebc23c4a9 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -128,8 +128,8 @@ struct pdc_port_priv { dma_addr_t pkt_dma; }; -static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int pdc_common_port_start(struct ata_port *ap); static int pdc_sata_port_start(struct ata_port *ap); @@ -427,19 +427,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap) return ATA_CBL_SATA; } -static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { if (sc_reg > SCR_CONTROL) - return 0xffffffffU; - return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return -EINVAL; + *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } -static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, - u32 val) +static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) - return; + return -EINVAL; writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } static void pdc_atapi_pkt(struct ata_queued_cmd *qc) @@ -642,8 +643,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR)) ac_err_mask |= AC_ERR_HOST_BUS; - if (sata_scr_valid(ap)) - ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR); + if (sata_scr_valid(ap)) { + u32 serror; + + pdc_sata_scr_read(ap, SCR_ERROR, &serror); + ehi->serror |= serror; + } qc->err_mask |= ac_err_mask; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 5aef4ac37012..c8f9242e7f44 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -111,8 +111,8 @@ struct qs_port_priv { qs_state_t state; }; -static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int qs_port_start(struct ata_port *ap); static void qs_host_stop(struct ata_host *host); @@ -255,18 +255,20 @@ static void qs_eng_timeout(struct ata_port *ap) ata_eng_timeout(ap); } -static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { if (sc_reg > SCR_CONTROL) - return ~0U; - return readl(ap->ioaddr.scr_addr + (sc_reg * 8)); + return -EINVAL; + *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8)); + return 0; } -static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) - return; + return -EINVAL; writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); + return 0; } static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 2a86dc4598d0..db6763758952 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -115,8 +115,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static int sil_pci_device_resume(struct pci_dev *pdev); #endif static void sil_dev_config(struct ata_device *dev); -static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed); static void sil_freeze(struct ata_port *ap); static void sil_thaw(struct ata_port *ap); @@ -350,19 +350,26 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re return NULL; } -static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { void __iomem *mmio = sil_scr_addr(ap, sc_reg); - if (mmio) - return readl(mmio); - return 0xffffffffU; + + if (mmio) { + *val = readl(mmio); + return 0; + } + return -EINVAL; } -static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { void __iomem *mmio = sil_scr_addr(ap, sc_reg); - if (mmio) + + if (mmio) { writel(val, mmio); + return 0; + } + return -EINVAL; } static void sil_host_intr(struct ata_port *ap, u32 bmdma2) @@ -378,7 +385,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) * controllers continue to assert IRQ as long as * SError bits are pending. Clear SError immediately. */ - serror = sil_scr_read(ap, SCR_ERROR); + sil_scr_read(ap, SCR_ERROR, &serror); sil_scr_write(ap, SCR_ERROR, serror); /* Trigger hotplug and accumulate SError only if the diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e201f1cab66d..46fbbe7f121c 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -326,8 +326,8 @@ struct sil24_port_priv { static void sil24_dev_config(struct ata_device *dev); static u8 sil24_check_status(struct ata_port *ap); -static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); -static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); +static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val); +static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); @@ -488,25 +488,30 @@ static int sil24_scr_map[] = { [SCR_ACTIVE] = 3, }; -static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) +static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val) { void __iomem *scr_addr = ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; - return readl(scr_addr + sil24_scr_map[sc_reg] * 4); + *val = readl(scr_addr + sil24_scr_map[sc_reg] * 4); + return 0; } - return 0xffffffffU; + return -EINVAL; } -static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) +static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) { void __iomem *scr_addr = ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; writel(val, scr_addr + sil24_scr_map[sc_reg] * 4); + return 0; } + return -EINVAL; } static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 33716b00c6b7..31a2f55aae66 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -64,8 +64,8 @@ enum { }; static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static const struct pci_device_id sis_pci_tbl[] = { { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */ @@ -207,36 +207,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val pci_write_config_dword(pdev, cfg_addr+0x10, val); } -static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u32 val, val2 = 0; u8 pmr; if (sc_reg > SCR_CONTROL) - return 0xffffffffU; + return -EINVAL; if (ap->flags & SIS_FLAG_CFGSCR) return sis_scr_cfg_read(ap, sc_reg); pci_read_config_byte(pdev, SIS_PMR, &pmr); - val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); + *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) - val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); + *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); + + *val &= 0xfffffffb; - return (val | val2) & 0xfffffffb; + return 0; } -static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 pmr; if (sc_reg > SCR_CONTROL) - return; + return -EINVAL; pci_read_config_byte(pdev, SIS_PMR, &pmr); @@ -248,6 +249,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED)) iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); } + return 0; } static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 63fe99afd59f..92e877075037 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc) return 0; } -static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { if (sc_reg > SCR_CONTROL) - return 0xffffffffU; - return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return -EINVAL; + *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } -static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, - u32 val) +static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) - return; + return -EINVAL; writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index b52f83ab056a..78c28512f01c 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -57,8 +57,8 @@ struct uli_priv { }; static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static const struct pci_device_id uli_pci_tbl[] = { { PCI_VDEVICE(AL, 0x5289), uli_5289 }, @@ -164,20 +164,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) pci_write_config_dword(pdev, cfg_addr, val); } -static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val) { if (sc_reg > SCR_CONTROL) - return 0xffffffffU; + return -EINVAL; - return uli_scr_cfg_read(ap, sc_reg); + *val = uli_scr_cfg_read(ap, sc_reg); + return 0; } -static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0 - return; + return -EINVAL; uli_scr_cfg_write(ap, sc_reg, val); + return 0; } static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index c4124475f754..86b7bfc17324 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -72,8 +72,8 @@ enum { }; static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); -static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static void svia_noop_freeze(struct ata_port *ap); static void vt6420_error_handler(struct ata_port *ap); static int vt6421_pata_cable_detect(struct ata_port *ap); @@ -249,18 +249,20 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, svia_pci_tbl); MODULE_VERSION(DRV_VERSION); -static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { if (sc_reg > SCR_CONTROL) - return 0xffffffffU; - return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); + return -EINVAL; + *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); + return 0; } -static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) - return; + return -EINVAL; iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg)); + return 0; } static void svia_noop_freeze(struct ata_port *ap) @@ -305,18 +307,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) /* Resume phy. This is the old SATA resume sequence */ svia_scr_write(ap, SCR_CONTROL, 0x300); - svia_scr_read(ap, SCR_CONTROL); /* flush */ + svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */ /* wait for phy to become ready, if necessary */ do { msleep(200); - if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1) + svia_scr_read(ap, SCR_STATUS, &sstatus); + if ((sstatus & 0xf) != 1) break; } while (time_before(jiffies, timeout)); /* open code sata_print_link_status() */ - sstatus = svia_scr_read(ap, SCR_STATUS); - scontrol = svia_scr_read(ap, SCR_CONTROL); + svia_scr_read(ap, SCR_STATUS, &sstatus); + svia_scr_read(ap, SCR_CONTROL, &scontrol); online = (sstatus & 0xf) == 0x3; @@ -325,7 +328,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) online ? "up" : "down", sstatus, scontrol); /* SStatus is read one more time */ - svia_scr_read(ap, SCR_STATUS); + svia_scr_read(ap, SCR_STATUS, &sstatus); if (!online) { /* tell EH to bail */ diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 1b5d81faa102..24344d0d0575 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -98,20 +98,21 @@ enum { VSC_SATA_INT_PHY_CHANGE), }; -static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) +static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) { if (sc_reg > SCR_CONTROL) - return 0xffffffffU; - return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return -EINVAL; + *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } -static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, - u32 val) +static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) - return; + return -EINVAL; writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; } diff --git a/include/linux/libata.h b/include/linux/libata.h index cb181713d9b5..c732b3e78e28 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -620,9 +620,8 @@ struct ata_port_operations { u8 (*irq_on) (struct ata_port *); u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq); - u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); - void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, - u32 val); + int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val); + int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val); int (*port_suspend) (struct ata_port *ap, pm_message_t mesg); int (*port_resume) (struct ata_port *ap); -- cgit v1.2.3 From 008a78961ec72990d09d7625ef9499d7317d040d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:40 +0900 Subject: libata: improve SATA PHY speed down logic sata_down_spd_limit() first reads the current SPD from SStatus and limit the speed to the lower one of one below the current limit or one below the current SPD in SStatus. SPD may not be accessible or valid when SPD down is requested making sata_down_spd_limit() fail when it's most needed. This patch makes the current SPD cached after each successful reset and forces GEN I speed (1.5Gbps) if neither of SStatus or the cached value is valid, so sata_down_spd_limit() is now guaranteed to lower the speed limit if lower speed is available. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 29 ++++++++++++++++++++++------- drivers/ata/libata-eh.c | 6 ++++++ include/linux/libata.h | 1 + 3 files changed, 29 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5718c247e23a..c325b7a4246a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2389,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap) u32 sstatus, spd, mask; int rc, highbit; + if (!sata_scr_valid(ap)) + return -EOPNOTSUPP; + + /* If SCR can be read, use it to determine the current SPD. + * If not, use cached value in ap->sata_spd. + */ rc = sata_scr_read(ap, SCR_STATUS, &sstatus); - if (rc) - return rc; + if (rc == 0) + spd = (sstatus >> 4) & 0xf; + else + spd = ap->sata_spd; mask = ap->sata_spd_limit; if (mask <= 1) return -EINVAL; + + /* unconditionally mask off the highest bit */ highbit = fls(mask) - 1; mask &= ~(1 << highbit); - spd = (sstatus >> 4) & 0xf; - if (spd <= 1) - return -EINVAL; - spd--; - mask &= (1 << spd) - 1; + /* Mask off all speeds higher than or equal to the current + * one. Force 1.5Gbps if current SPD is not available. + */ + if (spd > 1) + mask &= (1 << (spd - 1)) - 1; + else + mask &= 1; + + /* were we already at the bottom? */ if (!mask) return -EINVAL; @@ -5995,6 +6009,7 @@ void ata_dev_init(struct ata_device *dev) /* SATA spd limit is bound to the first device */ ap->sata_spd_limit = ap->hw_sata_spd_limit; + ap->sata_spd = 0; /* High bits of dev->flags are used to record warm plug * requests which occur asynchronously. Synchronize using diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 19f9947bd96b..183eaf466d4f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1799,12 +1799,18 @@ static int ata_eh_reset(struct ata_port *ap, int classify, } if (rc == 0) { + u32 sstatus; + /* After the reset, the device state is PIO 0 and the * controller state is undefined. Record the mode. */ for (i = 0; i < ATA_MAX_DEVICES; i++) ap->device[i].pio_mode = XFER_PIO_0; + /* record current link speed */ + if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) + ap->sata_spd = (sstatus >> 4) & 0xf; + if (postreset) postreset(ap, classes); diff --git a/include/linux/libata.h b/include/linux/libata.h index c732b3e78e28..16ebdf152c75 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -531,6 +531,7 @@ struct ata_port { unsigned int cbl; /* cable type; ATA_CBL_xxx */ unsigned int hw_sata_spd_limit; unsigned int sata_spd_limit; /* SATA PHY speed limit */ + unsigned int sata_spd; /* current SATA PHY speed */ /* record runtime error info, protected by host lock */ struct ata_eh_info eh_info; -- cgit v1.2.3 From f8f1e1cc0cd4d75c73e9a55a0ede8958e4fa14f1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:40 +0900 Subject: libata: reorganize ata_ehi_hotplugged() __ata_ehi_hotplugged() now has no users. Regorganize ata_ehi_hotplugged() such that a new function ata_ehi_schedule_probe() deals with scheduling probing. ata_ehi_hotplugged() calls it and additionally marks hotplug specific flags. ata_ehi_schedule_probe() will be used laster. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index 16ebdf152c75..74800ad6d81f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -915,16 +915,17 @@ extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...); extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...); extern void ata_ehi_clear_desc(struct ata_eh_info *ehi); -static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi) +static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi) { - ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK; + ehi->flags |= ATA_EHI_RESUME_LINK; ehi->action |= ATA_EH_SOFTRESET; ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; } static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) { - __ata_ehi_hotplugged(ehi); + ata_ehi_schedule_probe(ehi); + ehi->flags |= ATA_EHI_HOTPLUGGED; ehi->err_mask |= AC_ERR_ATA_BUS; } -- cgit v1.2.3 From 5ddf24c5ea9d715dc4f5d5d5dd1c9337d90466dc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 16 Jul 2007 14:29:41 +0900 Subject: libata: implement EH fast drain In most cases, when EH is scheduled, all in-flight commands are aborted causing EH to kick in immediately. However, in some cases (especially with PMP), it's unclear which commands are affected by the error condition and although aborting all in-flight commands work, it isn't optimal and may cause unnecessary disruption. On the other hand, waiting for in-flight commands to drain themselves can take up to 30seconds. This patch implements EH fast drain to handle such situations. It gives in-flight commands some time to finish up but doesn't wait for too long. After EH is scheduled, fast drain timer is started and if no other completion occurs in ATA_EH_FASTDRAIN_INTERVAL all in-flight commands are aborted. If any completion occurred in the interval, the port is given another interval to finish up itself. Currently ATA_EH_FASTDRAIN_INTERVAL is 3 secs which should be enough for finishing up most commands. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 3 ++ drivers/ata/libata-eh.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/ata/libata.h | 1 + include/linux/libata.h | 3 ++ 4 files changed, 104 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 35b621293831..6001aae0b884 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6077,6 +6077,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host) INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); + init_timer_deferrable(&ap->fastdrain_timer); + ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn; + ap->fastdrain_timer.data = (unsigned long)ap; ap->cbl = ATA_CBL_NONE; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e7e2ba24ce66..ac6ceed4bb60 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -56,6 +56,7 @@ enum { */ enum { ATA_EH_PRERESET_TIMEOUT = 10 * HZ, + ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ, }; /* The following table determines how we sequence resets. Each entry @@ -361,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host) repeat: /* invoke error handler */ if (ap->ops->error_handler) { + /* kill fast drain timer */ + del_timer_sync(&ap->fastdrain_timer); + /* process port resume request */ ata_eh_handle_port_resume(ap); @@ -576,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap) DPRINTK("EXIT\n"); } +static int ata_eh_nr_in_flight(struct ata_port *ap) +{ + unsigned int tag; + int nr = 0; + + /* count only non-internal commands */ + for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) + if (ata_qc_from_tag(ap, tag)) + nr++; + + return nr; +} + +void ata_eh_fastdrain_timerfn(unsigned long arg) +{ + struct ata_port *ap = (void *)arg; + unsigned long flags; + int cnt; + + spin_lock_irqsave(ap->lock, flags); + + cnt = ata_eh_nr_in_flight(ap); + + /* are we done? */ + if (!cnt) + goto out_unlock; + + if (cnt == ap->fastdrain_cnt) { + unsigned int tag; + + /* No progress during the last interval, tag all + * in-flight qcs as timed out and freeze the port. + */ + for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) { + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); + if (qc) + qc->err_mask |= AC_ERR_TIMEOUT; + } + + ata_port_freeze(ap); + } else { + /* some qcs have finished, give it another chance */ + ap->fastdrain_cnt = cnt; + ap->fastdrain_timer.expires = + jiffies + ATA_EH_FASTDRAIN_INTERVAL; + add_timer(&ap->fastdrain_timer); + } + + out_unlock: + spin_unlock_irqrestore(ap->lock, flags); +} + +/** + * ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain + * @ap: target ATA port + * @fastdrain: activate fast drain + * + * Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain + * is non-zero and EH wasn't pending before. Fast drain ensures + * that EH kicks in in timely manner. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static void ata_eh_set_pending(struct ata_port *ap, int fastdrain) +{ + int cnt; + + /* already scheduled? */ + if (ap->pflags & ATA_PFLAG_EH_PENDING) + return; + + ap->pflags |= ATA_PFLAG_EH_PENDING; + + if (!fastdrain) + return; + + /* do we have in-flight qcs? */ + cnt = ata_eh_nr_in_flight(ap); + if (!cnt) + return; + + /* activate fast drain */ + ap->fastdrain_cnt = cnt; + ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL; + add_timer(&ap->fastdrain_timer); +} + /** * ata_qc_schedule_eh - schedule qc for error handling * @qc: command to schedule error handling for @@ -593,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) WARN_ON(!ap->ops->error_handler); qc->flags |= ATA_QCFLAG_FAILED; - qc->ap->pflags |= ATA_PFLAG_EH_PENDING; + ata_eh_set_pending(ap, 1); /* The following will fail if timeout has already expired. * ata_scsi_error() takes care of such scmds on EH entry. @@ -620,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap) if (ap->pflags & ATA_PFLAG_INITIALIZING) return; - ap->pflags |= ATA_PFLAG_EH_PENDING; + ata_eh_set_pending(ap, 1); scsi_schedule_eh(ap->scsi_host); DPRINTK("port EH scheduled\n"); @@ -644,6 +736,9 @@ int ata_port_abort(struct ata_port *ap) WARN_ON(!ap->ops->error_handler); + /* we're gonna abort all commands, no need for fast drain */ + ata_eh_set_pending(ap, 0); + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 48836b22ce2f..564cd234c805 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -151,6 +151,7 @@ extern int ata_bus_probe(struct ata_port *ap); extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); +extern void ata_eh_fastdrain_timerfn(unsigned long arg); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); /* libata-sff.c */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 74800ad6d81f..be5a43928c84 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -565,6 +565,9 @@ struct ata_port { pm_message_t pm_mesg; int *pm_result; + struct timer_list fastdrain_timer; + unsigned long fastdrain_cnt; + void *private_data; #ifdef CONFIG_ATA_ACPI -- cgit v1.2.3