* [PATCH 03/21] ahci: use deadline instead of fixed timeout for 1st FIS for SRST
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 01/21] ahci: build fix for !CONFIG_PM Tejun Heo
` (19 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Use deadline instead of fixed timeout for 1st FIS for SRST to improve
robustness of SRST.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/ahci.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 61c5b6e..0451600 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -976,6 +976,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
void __iomem *port_mmio = ahci_port_base(ap);
const u32 cmd_fis_len = 5; /* five dwords */
const char *reason = NULL;
+ unsigned long now, msecs;
struct ata_taskfile tf;
u32 tmp;
u8 *fis;
@@ -1016,6 +1017,11 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
fis = pp->cmd_tbl;
/* issue the first D2H Register FIS */
+ msecs = 0;
+ now = jiffies;
+ if (time_after(now, deadline))
+ msecs = jiffies_to_msecs(deadline - now);
+
ahci_fill_cmd_slot(pp, 0,
cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
@@ -1024,7 +1030,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
writel(1, port_mmio + PORT_CMD_ISSUE);
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
+ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, msecs);
if (tmp & 0x1) {
rc = -EIO;
reason = "1st FIS failed";
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 01/21] ahci: build fix for !CONFIG_PM
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
2007-07-16 5:29 ` [PATCH 03/21] ahci: use deadline instead of fixed timeout for 1st FIS for SRST Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis() Tejun Heo
` (18 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
ahci_port_resume() is also used while starting port. Move it out of
CONFIG_PM block.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/ahci.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 11e4eb9..eaec5e5 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1519,6 +1519,14 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
}
}
+static int ahci_port_resume(struct ata_port *ap)
+{
+ ahci_power_up(ap);
+ ahci_start_port(ap);
+
+ return 0;
+}
+
#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
@@ -1536,14 +1544,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
return rc;
}
-static int ahci_port_resume(struct ata_port *ap)
-{
- ahci_power_up(ap);
- ahci_start_port(ap);
-
- return 0;
-}
-
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
2007-07-16 5:29 ` [PATCH 03/21] ahci: use deadline instead of fixed timeout for 1st FIS for SRST Tejun Heo
2007-07-16 5:29 ` [PATCH 01/21] ahci: build fix for !CONFIG_PM Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-20 11:56 ` Jeff Garzik
2007-07-20 12:02 ` Jeff Garzik
2007-07-16 5:29 ` [PATCH 08/21] sata_sil24: separate out sil24_exec_polled_cmd() Tejun Heo
` (17 subsequent siblings)
20 siblings, 2 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
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 <htejun@gmail.com>
---
drivers/ata/ahci.c | 10 ++++------
drivers/ata/libata-core.c | 14 ++++++++------
drivers/ata/sata_qstor.c | 2 +-
drivers/ata/sata_sil24.c | 2 +-
include/linux/libata.h | 3 ++-
5 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index eaec5e5..61c5b6e 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1020,8 +1020,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
tf.ctl |= ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+ ata_tf_to_fis(&tf, 0, 0, fis);
writel(1, port_mmio + PORT_CMD_ISSUE);
@@ -1039,8 +1038,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
tf.ctl &= ~ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+ ata_tf_to_fis(&tf, 0, 0, fis);
writel(1, port_mmio + PORT_CMD_ISSUE);
readl(port_mmio + PORT_CMD_ISSUE); /* flush */
@@ -1088,7 +1086,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(ap->device, &tf);
tf.command = 0x80;
- ata_tf_to_fis(&tf, d2h_fis, 0);
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_std_hardreset(ap, class, deadline);
@@ -1205,7 +1203,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
- ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 88e2dd0..a78af01 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -111,8 +111,9 @@ MODULE_VERSION(DRV_VERSION);
/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert
- * @fis: Buffer into which data will output
* @pmp: Port multiplier port
+ * @is_cmd: This FIS is for command
+ * @fis: Buffer into which data will output
*
* Converts a standard ATA taskfile to a Serial ATA
* FIS structure (Register - Host to Device).
@@ -120,12 +121,13 @@ MODULE_VERSION(DRV_VERSION);
* LOCKING:
* Inherited from caller.
*/
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
{
- fis[0] = 0x27; /* Register - Host to Device FIS */
- fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
- bit 7 indicates Command FIS */
+ fis[0] = 0x27; /* Register - Host to Device FIS */
+ fis[1] = pmp & 0xf; /* Port multiplier number*/
+ if (is_cmd)
+ fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */
+
fis[2] = tf->command;
fis[3] = tf->feature;
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 9ab554d..5aef4ac 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -337,7 +337,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
buf[28] = dflags;
/* frame information structure (FIS) */
- ata_tf_to_fis(&qc->tf, &buf[32], 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
}
static inline void qs_packet_start(struct ata_queued_cmd *qc)
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ac43a30..a11007b 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -699,7 +699,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
}
prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, prb->fis, 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 47cd2a1..5d3df6c 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);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis()
2007-07-16 5:29 ` [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis() Tejun Heo
@ 2007-07-20 11:56 ` Jeff Garzik
2007-07-20 12:02 ` Jeff Garzik
1 sibling, 0 replies; 30+ messages in thread
From: Jeff Garzik @ 2007-07-20 11:56 UTC (permalink / raw)
To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao
Tejun Heo wrote:
> +extern void ata_tf_to_fis(const struct ata_taskfile *tf,
> + u8 pmp, int is_cmd, u8 *fis);
I'm applying these... but I would like to start seeing 'bool' type used
for arguments like "is_cmd", for situations where the only values we
-ever- care about are true or false.
I really feel the "bool" type makes function prototypes more readable,
in particular.
Jeff
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis()
2007-07-16 5:29 ` [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis() Tejun Heo
2007-07-20 11:56 ` Jeff Garzik
@ 2007-07-20 12:02 ` Jeff Garzik
2007-07-20 12:18 ` Tejun Heo
1 sibling, 1 reply; 30+ messages in thread
From: Jeff Garzik @ 2007-07-20 12:02 UTC (permalink / raw)
To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao
Tejun Heo wrote:
> 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 <htejun@gmail.com>
> ---
> drivers/ata/ahci.c | 10 ++++------
> drivers/ata/libata-core.c | 14 ++++++++------
> drivers/ata/sata_qstor.c | 2 +-
> drivers/ata/sata_sil24.c | 2 +-
> include/linux/libata.h | 3 ++-
> 5 files changed, 16 insertions(+), 15 deletions(-)
applied 2-14
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis()
2007-07-20 12:02 ` Jeff Garzik
@ 2007-07-20 12:18 ` Tejun Heo
2007-07-20 12:20 ` Jeff Garzik
0 siblings, 1 reply; 30+ messages in thread
From: Tejun Heo @ 2007-07-20 12:18 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Alan Cox, linux-ide, Forrest Zhao
Jeff Garzik wrote:
> Tejun Heo wrote:
>> 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 <htejun@gmail.com>
>> ---
>> drivers/ata/ahci.c | 10 ++++------
>> drivers/ata/libata-core.c | 14 ++++++++------
>> drivers/ata/sata_qstor.c | 2 +-
>> drivers/ata/sata_sil24.c | 2 +-
>> include/linux/libata.h | 3 ++-
>> 5 files changed, 16 insertions(+), 15 deletions(-)
>
> applied 2-14
Hmmm... Where did patch 1 go? Did you receive it?
--
tejun
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis()
2007-07-20 12:18 ` Tejun Heo
@ 2007-07-20 12:20 ` Jeff Garzik
0 siblings, 0 replies; 30+ messages in thread
From: Jeff Garzik @ 2007-07-20 12:20 UTC (permalink / raw)
To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao
Tejun Heo wrote:
> Jeff Garzik wrote:
>> Tejun Heo wrote:
>>> 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 <htejun@gmail.com>
>>> ---
>>> drivers/ata/ahci.c | 10 ++++------
>>> drivers/ata/libata-core.c | 14 ++++++++------
>>> drivers/ata/sata_qstor.c | 2 +-
>>> drivers/ata/sata_sil24.c | 2 +-
>>> include/linux/libata.h | 3 ++-
>>> 5 files changed, 16 insertions(+), 15 deletions(-)
>> applied 2-14
>
> Hmmm... Where did patch 1 go? Did you receive it?
It was one of several copies I received :)
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 08/21] sata_sil24: separate out sil24_exec_polled_cmd()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (2 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 02/21] libata: add @is_cmd to ata_tf_to_fis() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 10/21] libata: improve EH report formatting Tejun Heo
` (16 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Separate out sil24_exec_polled_cmd() from sil24_softreset(). This
will be used to implement sil24_pmp_read/write().
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_sil24.c | 76 ++++++++++++++++++++++++++++++++++------------
1 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5f8afa9..e6fe4c4 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -531,16 +531,60 @@ static int sil24_init_port(struct ata_port *ap)
return 0;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+ const struct ata_taskfile *tf,
+ int is_cmd, u32 ctrl,
+ unsigned long timeout_msec)
{
void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
+ u32 irq_enabled, irq_mask, irq_stat;
+ int rc;
+
+ prb->ctrl = cpu_to_le16(ctrl);
+ ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+ /* temporarily plug completion and error interrupts */
+ irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+ writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+ writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+ writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+ irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+ irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+ 10, timeout_msec);
+
+ writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+ irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+ if (irq_stat & PORT_IRQ_COMPLETE)
+ rc = 0;
+ else {
+ /* force port into known state */
+ sil24_init_port(ap);
+
+ if (irq_stat & PORT_IRQ_ERROR)
+ rc = -EIO;
+ else
+ rc = -EBUSY;
+ }
+
+ /* restore IRQ enabled */
+ writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+ return rc;
+}
+
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
+ unsigned long timeout_msec = 0;
struct ata_taskfile tf;
- u32 mask, irq_stat;
const char *reason;
+ int rc;
DPRINTK("ENTER\n");
@@ -557,24 +601,16 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
}
/* do SRST */
- prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
- prb->fis[1] = 0; /* no PMP yet */
+ if (time_after(deadline, jiffies))
+ timeout_msec = jiffies_to_msecs(deadline - jiffies);
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
- mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
- irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
- 100, jiffies_to_msecs(deadline - jiffies));
-
- writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
- irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
- if (!(irq_stat & PORT_IRQ_COMPLETE)) {
- if (irq_stat & PORT_IRQ_ERROR)
- reason = "SRST command error";
- else
- reason = "timeout";
+ ata_tf_init(ap->device, &tf); /* doesn't really matter */
+ rc = sil24_exec_polled_cmd(ap, 0, &tf, 0, PRB_CTRL_SRST, timeout_msec);
+ if (rc == -EBUSY) {
+ reason = "timeout";
+ goto err;
+ } else if (rc) {
+ reason = "SRST command error";
goto err;
}
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 10/21] libata: improve EH report formatting
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (3 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 08/21] sata_sil24: separate out sil24_exec_polled_cmd() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 05/21] ahci: separate out ahci_exec_polled_cmd() Tejun Heo
` (15 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
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 <htejun@gmail.com>
---
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(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c5034d4..210292c 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 a78af01..928b69a 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6944,6 +6944,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 9aa62a0..96b184e 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 80ade5b..b4b737e 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 db81e3e..5d943da 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 e538edc..e201f1c 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 5d3df6c..94b37d1 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)
{
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 05/21] ahci: separate out ahci_exec_polled_cmd()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (4 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 10/21] libata: improve EH report formatting Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 04/21] ahci: separate out ahci_kick_engine() Tejun Heo
` (14 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
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>
---
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 1be238d..db65f4a 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)
return rc;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+ struct ata_taskfile *tf, int is_cmd, u16 flags,
+ unsigned long timeout_msec)
{
+ const u32 cmd_fis_len = 5; /* five dwords */
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
- const u32 cmd_fis_len = 5; /* five dwords */
+ u8 *fis = pp->cmd_tbl;
+ u32 tmp;
+
+ /* prep the command */
+ ata_tf_to_fis(tf, pmp, is_cmd, fis);
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+ /* issue & wait */
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+
+ if (timeout_msec) {
+ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+ 1, timeout_msec);
+ if (tmp & 0x1) {
+ ahci_kick_engine(ap, 1);
+ return -EBUSY;
+ }
+ } else
+ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+
+ return 0;
+}
+
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
- u32 tmp;
- u8 *fis;
int rc;
DPRINTK("ENTER\n");
@@ -1021,7 +1046,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
"failed to reset engine (errno=%d)", rc);
ata_tf_init(ap->device, &tf);
- fis = pp->cmd_tbl;
/* issue the first D2H Register FIS */
msecs = 0;
@@ -1029,16 +1053,9 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
if (time_after(now, deadline))
msecs = jiffies_to_msecs(deadline - now);
- ahci_fill_cmd_slot(pp, 0,
- cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
-
tf.ctl |= ATA_SRST;
- ata_tf_to_fis(&tf, 0, 0, fis);
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
-
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, msecs);
- if (tmp & 0x1) {
+ if (ahci_exec_polled_cmd(ap, 0, &tf, 0,
+ AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
rc = -EIO;
reason = "1st FIS failed";
goto fail;
@@ -1048,13 +1065,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
msleep(1);
/* issue the second D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
tf.ctl &= ~ATA_SRST;
- ata_tf_to_fis(&tf, 0, 0, fis);
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+ ahci_exec_polled_cmd(ap, 0, &tf, 0, 0, 0);
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 04/21] ahci: separate out ahci_kick_engine()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (5 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 05/21] ahci: separate out ahci_exec_polled_cmd() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 07/21] sata_sil24: replace sil24_update_tf() with sil24_read_tf() Tejun Heo
` (13 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Separate out stop_engine - CLO - start_engine sequence from
ahci_softreset() and ahci_clo() into ahci_reset_engine() and use it in
ahci_softreset() and ahci_post_internal_cmd(). The function will also
be used to prepare for and clean up after PMP register access
commands.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/ahci.c | 69 +++++++++++++++++++++++++++-------------------------
1 files changed, 36 insertions(+), 33 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 0451600..1be238d 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -948,25 +948,49 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
+ int busy, rc;
- if (!(hpriv->cap & HOST_CAP_CLO))
- return -EOPNOTSUPP;
+ /* do we need to kick the port? */
+ busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+ if (!busy && !force_restart)
+ return 0;
+
+ /* stop engine */
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ goto out_restart;
+
+ /* need to do CLO? */
+ if (!busy) {
+ rc = 0;
+ goto out_restart;
+ }
+
+ if (!(hpriv->cap & HOST_CAP_CLO)) {
+ rc = -EOPNOTSUPP;
+ goto out_restart;
+ }
+ /* perform CLO */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_CLO;
writel(tmp, port_mmio + PORT_CMD);
+ rc = 0;
tmp = ata_wait_register(port_mmio + PORT_CMD,
PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
if (tmp & PORT_CMD_CLO)
- return -EIO;
+ rc = -EIO;
- return 0;
+ /* restart engine */
+ out_restart:
+ ahci_start_engine(ap);
+ return rc;
}
static int ahci_softreset(struct ata_port *ap, unsigned int *class,
@@ -991,27 +1015,10 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
}
/* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_stop_engine(ap);
- if (rc) {
- reason = "failed to stop engine";
- goto fail_restart;
- }
-
- /* check BUSY/DRQ, perform Command List Override if necessary */
- if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
- rc = ahci_clo(ap);
-
- if (rc == -EOPNOTSUPP) {
- reason = "port busy but CLO unavailable";
- goto fail_restart;
- } else if (rc) {
- reason = "port busy but CLO failed";
- goto fail_restart;
- }
- }
-
- /* restart engine */
- ahci_start_engine(ap);
+ rc = ahci_kick_engine(ap, 1);
+ if (rc)
+ ata_port_printk(ap, KERN_WARNING,
+ "failed to reset engine (errno=%d)", rc);
ata_tf_init(ap->device, &tf);
fis = pp->cmd_tbl;
@@ -1070,8 +1077,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("EXIT, class=%u\n", *class);
return 0;
- fail_restart:
- ahci_start_engine(ap);
fail:
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
@@ -1516,11 +1521,9 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (qc->flags & ATA_QCFLAG_FAILED) {
- /* make DMA engine forget about the failed command */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
+ /* make DMA engine forget about the failed command */
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ ahci_kick_engine(ap, 1);
}
static int ahci_port_resume(struct ata_port *ap)
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 07/21] sata_sil24: replace sil24_update_tf() with sil24_read_tf()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (6 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 04/21] ahci: separate out ahci_kick_engine() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 09/21] sata_sil24: separate out sil24_do_softreset() Tejun Heo
` (12 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Replace sil24_update_tf() to sil24_read_tf() which reads TF into
passed int result TF argument and can read TFs of PMP links. This
will be used by PMP support.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_sil24.c | 23 ++++++++++++++---------
1 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index a11007b..5f8afa9 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -464,15 +464,15 @@ static void sil24_dev_config(struct ata_device *dev)
writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
}
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
{
- struct sil24_port_priv *pp = ap->private_data;
void __iomem *port = ap->ioaddr.cmd_addr;
- struct sil24_prb __iomem *prb = port;
+ struct sil24_prb __iomem *prb;
u8 fis[6 * 4];
- memcpy_fromio(fis, prb->fis, 6 * 4);
- ata_tf_from_fis(fis, &pp->tf);
+ prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+ memcpy_fromio(fis, prb->fis, sizeof(fis));
+ ata_tf_from_fis(fis, tf);
}
static u8 sil24_check_status(struct ata_port *ap)
@@ -538,6 +538,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
+ struct ata_taskfile tf;
u32 mask, irq_stat;
const char *reason;
@@ -577,8 +578,8 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
goto err;
}
- sil24_update_tf(ap);
- *class = ata_dev_classify(&pp->tf);
+ sil24_read_tf(ap, 0, &tf);
+ *class = ata_dev_classify(&tf);
if (*class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
@@ -754,6 +755,7 @@ static void sil24_thaw(struct ata_port *ap)
static void sil24_error_intr(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
struct ata_eh_info *ehi = &ap->eh_info;
int freeze = 0;
u32 irq_stat;
@@ -808,7 +810,7 @@ static void sil24_error_intr(struct ata_port *ap)
/* record error info */
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
- sil24_update_tf(ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
qc->err_mask |= err_mask;
} else
ehi->err_mask |= err_mask;
@@ -825,8 +827,11 @@ static void sil24_error_intr(struct ata_port *ap)
static void sil24_finish_qc(struct ata_queued_cmd *qc)
{
+ struct ata_port *ap = qc->ap;
+ struct sil24_port_priv *pp = ap->private_data;
+
if (qc->flags & ATA_QCFLAG_RESULT_TF)
- sil24_update_tf(qc->ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
}
static inline void sil24_host_intr(struct ata_port *ap)
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 09/21] sata_sil24: separate out sil24_do_softreset()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (7 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 07/21] sata_sil24: replace sil24_update_tf() with sil24_read_tf() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 06/21] ahci: separate out ahci_do_softreset() Tejun Heo
` (11 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Separate out sil24_do_softreset() which takes @pmp as its last
argument. This will be used to implement sil24_pmp_softreset().
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_sil24.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index e6fe4c4..e538edc 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -578,8 +578,8 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
return rc;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+ int pmp, unsigned long deadline)
{
unsigned long timeout_msec = 0;
struct ata_taskfile tf;
@@ -605,7 +605,8 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
timeout_msec = jiffies_to_msecs(deadline - jiffies);
ata_tf_init(ap->device, &tf); /* doesn't really matter */
- rc = sil24_exec_polled_cmd(ap, 0, &tf, 0, PRB_CTRL_SRST, timeout_msec);
+ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+ timeout_msec);
if (rc == -EBUSY) {
reason = "timeout";
goto err;
@@ -629,6 +630,12 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
return -EIO;
}
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
+ return sil24_do_softreset(ap, class, 0, deadline);
+}
+
static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 06/21] ahci: separate out ahci_do_softreset()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (8 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 09/21] sata_sil24: separate out sil24_do_softreset() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 13/21] ahci: make NO_NCQ handling more consistent Tejun Heo
` (10 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Separate out ahci_do_softreset() which takes @pmp as its last
argument. This will be used to implement ahci_pmp_softreset().
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/ahci.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index db65f4a..c5034d4 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1023,8 +1023,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
return 0;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+ int pmp, unsigned long deadline)
{
const char *reason = NULL;
unsigned long now, msecs;
@@ -1054,7 +1054,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
msecs = jiffies_to_msecs(deadline - now);
tf.ctl |= ATA_SRST;
- if (ahci_exec_polled_cmd(ap, 0, &tf, 0,
+ if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
rc = -EIO;
reason = "1st FIS failed";
@@ -1066,7 +1066,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
/* issue the second D2H Register FIS */
tf.ctl &= ~ATA_SRST;
- ahci_exec_polled_cmd(ap, 0, &tf, 0, 0, 0);
+ ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
@@ -1094,6 +1094,12 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
return rc;
}
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
+ return ahci_do_softreset(ap, class, 0, deadline);
+}
+
static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 13/21] ahci: make NO_NCQ handling more consistent
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (9 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 06/21] ahci: separate out ahci_do_softreset() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 16/21] libata: quickly trigger SATA SPD down after debouncing failed Tejun Heo
` (9 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
ahci_save_initial_config() is responsible for reading, screening the
host CAP register and storing the modified result into hpriv->cap for
the rest of the driver. Move ATA_FLAG_NO_NCQ handling into
ahci_save_initial_config(). It's more consistent this way and the
rest of the driver can always refer to hpriv->cap to determine
configured capability.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/ahci.c | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index e044d64..9faf008 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -545,13 +545,19 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
- /* some chips lie about 64bit support */
+ /* some chips lie about their capabilities, bust them */
if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do 64bit DMA, forcing 32bit\n");
cap &= ~HOST_CAP_64;
}
+ if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do NCQ, turning off CAP_NCQ\n");
+ cap &= ~HOST_CAP_NCQ;
+ }
+
/* fixup zero port_map */
if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
@@ -1822,7 +1828,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_save_initial_config(pdev, &pi, hpriv);
/* prepare host */
- if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+ if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 16/21] libata: quickly trigger SATA SPD down after debouncing failed
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (10 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 13/21] ahci: make NO_NCQ handling more consistent Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 14/21] ahci: implement SCR_NOTIFICATION r/w Tejun Heo
` (8 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Debouncing failure is a good indicator of basic link problem. Use
-EPIPE to indicate debouncing failure and make ata_eh_reset() invoke
sata_down_spd_limit() if the error occurs during reset.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-core.c | 6 ++++--
drivers/ata/libata-eh.c | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c60155e..58bc40e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3267,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
last = cur;
last_jiffies = jiffies;
- /* check deadline */
+ /* Check deadline. If debouncing failed, return
+ * -EPIPE to tell upper layer to lower link speed.
+ */
if (time_after(jiffies, deadline))
- return -EBUSY;
+ return -EPIPE;
}
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 183eaf4..1a4397a 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1790,7 +1790,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
schedule_timeout_uninterruptible(delta);
}
- if (reset == hardreset &&
+ if (rc == -EPIPE ||
try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
sata_down_spd_limit(ap);
if (hardreset)
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 14/21] ahci: implement SCR_NOTIFICATION r/w
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (11 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 16/21] libata: quickly trigger SATA SPD down after debouncing failed Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 18/21] libata: reorganize ata_ehi_hotplugged() Tejun Heo
` (7 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Make ahci_scr_read/write() handle SCR_NOTIFICATION if the controller
supports it. Also, print "sntf" in the cap line if supported.
While at it, convert eight space into a tab in ahci_print_info().
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/ahci.c | 68 ++++++++++++++++++++++++++++-----------------------
1 files changed, 37 insertions(+), 31 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 9faf008..417343e 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -99,6 +99,7 @@ enum {
HOST_CAP_SSC = (1 << 14), /* Slumber capable */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
@@ -113,11 +114,11 @@ enum {
PORT_TFDATA = 0x20, /* taskfile data */
PORT_SIG = 0x24, /* device TF signature */
PORT_CMD_ISSUE = 0x38, /* command issue */
- PORT_SCR = 0x28, /* SATA phy register block */
PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
+ PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
@@ -631,39 +632,45 @@ static void ahci_restore_initial_config(struct ata_host *host)
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return -EINVAL;
- }
+ static const int offset[] = {
+ [SCR_STATUS] = PORT_SCR_STAT,
+ [SCR_CONTROL] = PORT_SCR_CTL,
+ [SCR_ERROR] = PORT_SCR_ERR,
+ [SCR_ACTIVE] = PORT_SCR_ACT,
+ [SCR_NOTIFICATION] = PORT_SCR_NTF,
+ };
+ struct ahci_host_priv *hpriv = ap->host->private_data;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ if (sc_reg < ARRAY_SIZE(offset) &&
+ (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+ return offset[sc_reg];
return 0;
}
-
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return -EINVAL;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
+
+ if (offset) {
+ *val = readl(port_mmio + offset);
+ return 0;
}
+ return -EINVAL;
+}
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
- return 0;
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
+
+ if (offset) {
+ writel(val, port_mmio + offset);
+ return 0;
+ }
+ return -EINVAL;
}
static void ahci_start_engine(struct ata_port *ap)
@@ -1768,12 +1775,13 @@ static void ahci_print_info(struct ata_host *host)
dev_printk(KERN_INFO, &pdev->dev,
"flags: "
- "%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s\n"
+ "%s%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s\n"
,
cap & (1 << 31) ? "64bit " : "",
cap & (1 << 30) ? "ncq " : "",
+ cap & (1 << 29) ? "sntf " : "",
cap & (1 << 28) ? "ilck " : "",
cap & (1 << 27) ? "stag " : "",
cap & (1 << 26) ? "pm " : "",
@@ -1842,10 +1850,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *port_mmio = ahci_port_base(ap);
/* standard SATA port setup */
- if (hpriv->port_map & (1 << i)) {
+ if (hpriv->port_map & (1 << i))
ap->ioaddr.cmd_addr = port_mmio;
- ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
- }
/* disabled/not-implemented port */
else
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 18/21] libata: reorganize ata_ehi_hotplugged()
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (12 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 14/21] ahci: implement SCR_NOTIFICATION r/w Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 12/21] libata: make ->scr_read/write callbacks return error code Tejun Heo
` (6 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
__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 <htejun@gmail.com>
---
include/linux/libata.h | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 16ebdf1..74800ad 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;
}
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 12/21] libata: make ->scr_read/write callbacks return error code
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (13 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 18/21] libata: reorganize ata_ehi_hotplugged() Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-20 11:58 ` Jeff Garzik
2007-07-16 5:29 ` [PATCH 17/21] libata: improve SCSI scan failure handling Tejun Heo
` (5 subsequent siblings)
20 siblings, 1 reply; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
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 <htejun@gmail.com>
---
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(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 210292c..e044d64 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 928b69a..be1d96a 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5731,10 +5731,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;
}
@@ -5756,10 +5754,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;
}
@@ -5780,10 +5776,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 3de1834..a9c948d 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 b4b737e..8ec5208 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 5d943da..0b58c4d 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 d2fcb9a..d39ebc2 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 5aef4ac..c8f9242 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 2a86dc4..db67637 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 e201f1c..46fbbe7 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 33716b0..31a2f55 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 63fe99a..92e8770 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 b52f83a..78c2851 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 c412447..86b7bfc 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 1b5d81f..24344d0 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 cb18171..c732b3e 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);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 17/21] libata: improve SCSI scan failure handling
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (14 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 12/21] libata: make ->scr_read/write callbacks return error code Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-20 12:26 ` Jeff Garzik
2007-07-16 5:29 ` [PATCH 15/21] libata: improve SATA PHY speed down logic Tejun Heo
` (4 subsequent siblings)
20 siblings, 1 reply; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
SCSI scan may fail due to memory allocation failure even if EH is not
in progress. Due to use of GFP_ATOMIC in SCSI scan path, allocation
failure isn't too rare especially while probing multiple devices at
once which is the case when a bunch of devices are connected to PMP.
This patch moves SCSI scan failure detetion logic from
ata_scsi_hotplug() to ata_scsi_scan_host() and implement synchronous
scan behavior. The synchronous path sleeps briefly and repeats SCSI
scan if some devices aren't attached properly. It contains robust
retry loop to minimize the chance of device misdetection during boot
and falls back to async retry if everything fails.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-core.c | 2 +-
drivers/ata/libata-scsi.c | 63 +++++++++++++++++++++++++++++++++-----------
drivers/ata/libata.h | 2 +-
3 files changed, 49 insertions(+), 18 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 58bc40e..155061e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6452,7 +6452,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- ata_scsi_scan_host(ap);
+ ata_scsi_scan_host(ap, 1);
}
return 0;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfde22d..12ac0b5 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2947,17 +2947,22 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
return rc;
}
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
{
+ int tries = 5;
+ struct ata_device *last_failed_dev = NULL;
+ struct ata_device *dev;
unsigned int i;
if (ap->flags & ATA_FLAG_DISABLED)
return;
+ repeat:
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
struct scsi_device *sdev;
+ dev = &ap->device[i];
+
if (!ata_dev_enabled(dev) || dev->sdev)
continue;
@@ -2967,6 +2972,45 @@ void ata_scsi_scan_host(struct ata_port *ap)
scsi_device_put(sdev);
}
}
+
+ /* If we scanned while EH was in progress or allocation
+ * failure occurred, scan would have failed silently. Check
+ * whether all devices are attached.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+ if (ata_dev_enabled(dev) && !dev->sdev)
+ break;
+ }
+ if (i == ATA_MAX_DEVICES)
+ return;
+
+ /* we're missing some SCSI devices */
+ if (sync) {
+ /* If caller requested synchrnous scan && we've made
+ * any progress, sleep briefly and repeat.
+ */
+ if (dev != last_failed_dev) {
+ msleep(100);
+ last_failed_dev = dev;
+ goto repeat;
+ }
+
+ /* We might be failing to detect boot device, give it
+ * a few more chances.
+ */
+ if (--tries) {
+ msleep(100);
+ goto repeat;
+ }
+
+ ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+ "failed without making any progress,\n"
+ " switching to async\n");
+ }
+
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ round_jiffies_relative(HZ));
}
/**
@@ -3093,20 +3137,7 @@ void ata_scsi_hotplug(struct work_struct *work)
}
/* scan for new ones */
- ata_scsi_scan_host(ap);
-
- /* If we scanned while EH was in progress, scan would have
- * failed silently. Requeue if there are enabled but
- * unattached devices.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev) && !dev->sdev) {
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
- round_jiffies_relative(HZ));
- break;
- }
- }
+ ata_scsi_scan_host(ap, 0);
DPRINTK("EXIT\n");
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ba17fc5..48836b2 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -112,7 +112,7 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
/* libata-scsi.c */
extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH 17/21] libata: improve SCSI scan failure handling
2007-07-16 5:29 ` [PATCH 17/21] libata: improve SCSI scan failure handling Tejun Heo
@ 2007-07-20 12:26 ` Jeff Garzik
2007-07-20 12:28 ` Tejun Heo
0 siblings, 1 reply; 30+ messages in thread
From: Jeff Garzik @ 2007-07-20 12:26 UTC (permalink / raw)
To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao
Tejun Heo wrote:
> SCSI scan may fail due to memory allocation failure even if EH is not
> in progress. Due to use of GFP_ATOMIC in SCSI scan path, allocation
> failure isn't too rare especially while probing multiple devices at
> once which is the case when a bunch of devices are connected to PMP.
>
> This patch moves SCSI scan failure detetion logic from
> ata_scsi_hotplug() to ata_scsi_scan_host() and implement synchronous
> scan behavior. The synchronous path sleeps briefly and repeats SCSI
> scan if some devices aren't attached properly. It contains robust
> retry loop to minimize the chance of device misdetection during boot
> and falls back to async retry if everything fails.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> ---
> drivers/ata/libata-core.c | 2 +-
> drivers/ata/libata-scsi.c | 63 +++++++++++++++++++++++++++++++++-----------
> drivers/ata/libata.h | 2 +-
> 3 files changed, 49 insertions(+), 18 deletions(-)
applied 17-21, though this one makes me nervous. off to test upstream +
patchset #1... :)
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 17/21] libata: improve SCSI scan failure handling
2007-07-20 12:26 ` Jeff Garzik
@ 2007-07-20 12:28 ` Tejun Heo
0 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-20 12:28 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Alan Cox, linux-ide, Forrest Zhao
Jeff Garzik wrote:
> Tejun Heo wrote:
>> SCSI scan may fail due to memory allocation failure even if EH is not
>> in progress. Due to use of GFP_ATOMIC in SCSI scan path, allocation
>> failure isn't too rare especially while probing multiple devices at
>> once which is the case when a bunch of devices are connected to PMP.
>>
>> This patch moves SCSI scan failure detetion logic from
>> ata_scsi_hotplug() to ata_scsi_scan_host() and implement synchronous
>> scan behavior. The synchronous path sleeps briefly and repeats SCSI
>> scan if some devices aren't attached properly. It contains robust
>> retry loop to minimize the chance of device misdetection during boot
>> and falls back to async retry if everything fails.
>>
>> Signed-off-by: Tejun Heo <htejun@gmail.com>
>> ---
>> drivers/ata/libata-core.c | 2 +-
>> drivers/ata/libata-scsi.c | 63
>> +++++++++++++++++++++++++++++++++-----------
>> drivers/ata/libata.h | 2 +-
>> 3 files changed, 49 insertions(+), 18 deletions(-)
>
> applied 17-21, though this one makes me nervous. off to test upstream +
> patchset #1... :)
The proper thing to do is updating SCSI scan code such that it doesn't
fail at nothing (SCSI likes GFP_ATOMIC too much it seems). Anyways,
we're much safer with this patch but it's ugly as hell. :-(
--
tejun
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 15/21] libata: improve SATA PHY speed down logic
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (15 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 17/21] libata: improve SCSI scan failure handling Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-20 12:20 ` Jeff Garzik
2007-07-16 5:29 ` [PATCH 11/21] libata: implement AC_ERR_NCQ Tejun Heo
` (3 subsequent siblings)
20 siblings, 1 reply; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
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 <htejun@gmail.com>
---
drivers/ata/libata-core.c | 29 ++++++++++++++++++++++-------
drivers/ata/libata-eh.c | 6 ++++++
include/linux/libata.h | 1 +
3 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index be1d96a..c60155e 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;
@@ -5994,6 +6008,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 19f9947..183eaf4 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 c732b3e..16ebdf1 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;
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH 15/21] libata: improve SATA PHY speed down logic
2007-07-16 5:29 ` [PATCH 15/21] libata: improve SATA PHY speed down logic Tejun Heo
@ 2007-07-20 12:20 ` Jeff Garzik
0 siblings, 0 replies; 30+ messages in thread
From: Jeff Garzik @ 2007-07-20 12:20 UTC (permalink / raw)
To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao
Tejun Heo wrote:
> 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 <htejun@gmail.com>
> ---
> drivers/ata/libata-core.c | 29 ++++++++++++++++++++++-------
> drivers/ata/libata-eh.c | 6 ++++++
> include/linux/libata.h | 1 +
> 3 files changed, 29 insertions(+), 7 deletions(-)
applied 15-16
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 11/21] libata: implement AC_ERR_NCQ
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (16 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 15/21] libata: improve SATA PHY speed down logic Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 20/21] libata: schedule probing after SError access failure during autopsy Tejun Heo
` (2 subsequent siblings)
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
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 "<F>" after the error report for the command
to help distinguishing the offending command.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-eh.c | 7 ++++---
include/linux/libata.h | 1 +
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 96b184e..19f9947 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 ? " <F>" : "");
}
}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 94b37d1..cb18171 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 */
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 20/21] libata: schedule probing after SError access failure during autopsy
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (17 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 11/21] libata: implement AC_ERR_NCQ Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 19/21] libata: clear HOTPLUG flag after a reset Tejun Heo
2007-07-16 5:29 ` [PATCH 21/21] libata: implement EH fast drain Tejun Heo
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
If SError isn't accessible, EH can't tell whether hotplug has happened
or not. Report SError read failure with AC_ERR_OTHER and schedule
probing with hardreset. This will be mainly useful for PMPs.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-eh.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a5a8f84..e7e2ba2 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1478,8 +1478,12 @@ static void ata_eh_autopsy(struct ata_port *ap)
if (rc == 0) {
ehc->i.serror |= serror;
ata_eh_analyze_serror(ap);
- } else if (rc != -EOPNOTSUPP)
+ } else if (rc != -EOPNOTSUPP) {
+ /* SError read failed, force hardreset and probing */
+ ata_ehi_schedule_probe(&ehc->i);
ehc->i.action |= ATA_EH_HARDRESET;
+ ehc->i.err_mask |= AC_ERR_OTHER;
+ }
/* analyze NCQ failure */
ata_eh_analyze_ncq_error(ap);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 19/21] libata: clear HOTPLUG flag after a reset
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (18 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 20/21] libata: schedule probing after SError access failure during autopsy Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
2007-07-16 5:29 ` [PATCH 21/21] libata: implement EH fast drain Tejun Heo
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
ATA_EHI_HOTPLUGGED is a hint for reset functions indicating the the
port might have gone through hotplug/unplug just before entering EH.
Reset functions modify their behaviors a bit to handle the situation
better - e.g. using longer debouncing delay.
Currently, once HOTPLUG is set, it isn't cleared till the end of EH.
This is unnecessary and makes EH take longer. Clear the HOTPLUGGED
flag after a reset try (successful or not).
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-eh.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 1a4397a..a5a8f84 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1714,7 +1714,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
} else
ata_port_printk(ap, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
- return rc;
+ goto out;
}
}
@@ -1727,7 +1727,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
/* prereset told us not to reset, bang classes and return */
for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_NONE;
- return 0;
+ rc = 0;
+ goto out;
}
/* did prereset() screw up? if so, fix up to avoid oopsing */
@@ -1763,7 +1764,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_ERR,
"follow-up softreset required "
"but no softreset avaliable\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
@@ -1773,7 +1775,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
classes[0] == ATA_DEV_UNKNOWN) {
ata_port_printk(ap, KERN_ERR,
"classification failed\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
}
@@ -1818,7 +1821,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}
-
+ out:
+ /* clear hotplug flag */
+ ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
return rc;
}
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 21/21] libata: implement EH fast drain
2007-07-16 5:29 [PATCHSET 1/4] libata: misc updates in preparation of PMP support, take #2 Tejun Heo
` (19 preceding siblings ...)
2007-07-16 5:29 ` [PATCH 19/21] libata: clear HOTPLUG flag after a reset Tejun Heo
@ 2007-07-16 5:29 ` Tejun Heo
20 siblings, 0 replies; 30+ messages in thread
From: Tejun Heo @ 2007-07-16 5:29 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
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 <htejun@gmail.com>
---
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(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 155061e..9b1d179 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6076,6 +6076,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 e7e2ba2..ac6ceed 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 48836b2..564cd23 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 74800ad..be5a439 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
--
1.5.0.3
^ permalink raw reply related [flat|nested] 30+ messages in thread