* [PATCHSET 3/4] libata: prep for PMP support, take 4
@ 2007-07-01 10:26 Tejun Heo
2007-07-01 10:26 ` [PATCH 01/12] libata-pmp: add PMP related constants, fields, ops and update helpers Tejun Heo
` (12 more replies)
0 siblings, 13 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao, htejun
Hello, all.
This is the fourth take of libata-pmp-prep patchset. This patchset
contains 12 patches implementing various stuff needed for PMP.
#01 : add PMP related constants
#02-04 : various small stuff
#05-06 : qc_defer mechanism implementation
#07-11 : link/device quirks and EH fast-fail path - things needed to
handle quirky PMP fan-out links / pseudo devices.
#12 : SATA SDB notify handler
Changes from the last take[L] are.
* PMP related constants patch moved here from pmp patchset
* qc_defer CLEAR_EXCL fixed to clear excl_link iff it points to self
* addition of various quirks/special case handling vital for
supporting first-gen PMP chips
* generalized SDB notify handling
This patchset is against
libata-dev#upstream (4e1ae96828f6cee7b89ab8ca474c150fe211afd8)
+ [1] misc-updates patchset
+ [2] libata-link patchset, take 4
Thanks.
--
tejun
[L] http://thread.gmane.org/gmane.linux.ide/13500
[1] http://thread.gmane.org/gmane.linux.ide/20081
[2] http://thread.gmane.org/gmane.linux.ide/20099
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/12] libata-pmp: add PMP related constants, fields, ops and update helpers
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 02/12] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
` (11 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Add PMP related constants, fields and ops. Also, update
ata_class_enabled/disabled() such that PMP classes are considered.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
include/linux/libata.h | 31 +++++++++++++++++++++++++++----
1 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index a353305..3db3aa5 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -153,7 +153,11 @@ enum {
ATA_DEV_ATA_UNSUP = 2, /* ATA device (unsupported) */
ATA_DEV_ATAPI = 3, /* ATAPI device */
ATA_DEV_ATAPI_UNSUP = 4, /* ATAPI device (unsupported) */
- ATA_DEV_NONE = 5, /* no device */
+ ATA_DEV_PMP = 5, /* SATA port multiplier */
+ ATA_DEV_PMP_UNSUP = 6, /* SATA port multiplier (unsupported) */
+ ATA_DEV_SEMB = 7, /* SEMB */
+ ATA_DEV_SEMB_UNSUP = 8, /* SEMB (unsupported) */
+ ATA_DEV_NONE = 9, /* no device */
/* struct ata_link flags */
ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */
@@ -178,6 +182,8 @@ enum {
ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */
ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */
ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */
+ ATA_FLAG_PMP = (1 << 18),
+ ATA_FLAG_SDB_NOTIFY = (1 << 19),
/* The following flag belongs to ap->pflags but is kept in
* ap->flags because it's referenced in many LLDs and will be
@@ -295,6 +301,10 @@ enum {
/* how hard are we gonna try to probe/recover devices */
ATA_PROBE_MAX_TRIES = 3,
ATA_EH_DEV_TRIES = 3,
+ ATA_EH_PMP_TRIES = 5,
+ ATA_EH_PMP_LINK_TRIES = 3,
+
+ SATA_PMP_SCR_TIMEOUT = 250,
/* Horkage types. May be set by libata or controller on drives
(some horkage may be drive/controller pair dependant */
@@ -445,7 +455,12 @@ struct ata_device {
/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
u64 n_sectors; /* size of device, if ATA */
unsigned int class; /* ATA_DEV_xxx */
- u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+
+ union {
+ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
+ };
+
u8 pio_mode;
u8 dma_mode;
u8 xfer_mode;
@@ -625,6 +640,12 @@ struct ata_port_operations {
void (*qc_prep) (struct ata_queued_cmd *qc);
unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
+ /* port multiplier */
+ void (*pmp_attach) (struct ata_port *ap);
+ void (*pmp_detach) (struct ata_port *ap);
+ int (*pmp_read) (struct ata_device *dev, int pmp, int reg, u32 *r_val);
+ int (*pmp_write) (struct ata_device *dev, int pmp, int reg, u32 val);
+
/* Error handlers. ->error_handler overrides ->eng_timeout and
* indicates that new-style EH is in place.
*/
@@ -1020,12 +1041,14 @@ static inline unsigned int ata_tag_internal(unsigned int tag)
*/
static inline unsigned int ata_class_enabled(unsigned int class)
{
- return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
+ return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI ||
+ class == ATA_DEV_PMP || class == ATA_DEV_SEMB;
}
static inline unsigned int ata_class_disabled(unsigned int class)
{
- return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP;
+ return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP ||
+ class == ATA_DEV_PMP_UNSUP || class == ATA_DEV_SEMB_UNSUP;
}
static inline unsigned int ata_class_absent(unsigned int class)
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/12] libata-pmp-prep: add @new_class to ata_dev_revalidate()
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
2007-07-01 10:26 ` [PATCH 01/12] libata-pmp: add PMP related constants, fields, ops and update helpers Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 07/12] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB Tejun Heo
` (10 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Consider newly found class code while revalidating. PMP resetting
always results in valid class code and issuing PMP commands to
ATA/ATAPI device isn't very attractive. Add @new_class to
ata_dev_revalidate() and check class code for revalidation.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-core.c | 15 +++++++++++++--
drivers/ata/libata-eh.c | 3 ++-
drivers/ata/libata.h | 3 ++-
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index f4863b6..d366ac2 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2790,7 +2790,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
}
ehc->i.flags |= ATA_EHI_POST_SETMODE;
- rc = ata_dev_revalidate(dev, 0);
+ rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
ehc->i.flags &= ~ATA_EHI_POST_SETMODE;
if (rc)
return rc;
@@ -3699,6 +3699,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
/**
* ata_dev_revalidate - Revalidate ATA device
* @dev: device to revalidate
+ * @new_class: new class code
* @readid_flags: read ID flags
*
* Re-read IDENTIFY page, make sure @dev is still attached to the
@@ -3710,7 +3711,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags)
{
u64 n_sectors = dev->n_sectors;
int rc;
@@ -3718,6 +3720,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
if (!ata_dev_enabled(dev))
return -ENODEV;
+ /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */
+ if (ata_class_enabled(new_class) &&
+ new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+ ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n",
+ dev->class, new_class);
+ rc = -ENODEV;
+ goto fail;
+ }
+
/* re-read ID */
rc = ata_dev_reread_id(dev, readid_flags);
if (rc)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index eb51b76..7e8ec17 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1966,7 +1966,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
}
ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
- rc = ata_dev_revalidate(dev, readid_flags);
+ rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
+ readid_flags);
if (rc)
goto err;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 6d85ede..4153817 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -76,7 +76,8 @@ extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id);
extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
-extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags);
extern int ata_dev_configure(struct ata_device *dev);
extern int sata_down_spd_limit(struct ata_link *link);
extern int sata_set_spd_needed(struct ata_link *link);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/12] libata-pmp-prep: add @is_cmd to ata_tf_to_fis()
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (5 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 08/12] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 03/12] libata-pmp-prep: make a number of functions global to libata Tejun Heo
` (5 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 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 7d315de..d3af721 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -994,8 +994,7 @@ static int ahci_softreset(struct ata_link *link, 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);
@@ -1013,8 +1012,7 @@ static int ahci_softreset(struct ata_link *link, 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 */
@@ -1063,7 +1061,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->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(link, class, deadline);
@@ -1184,7 +1182,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 1e1855e..e66f7c0 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -110,8 +110,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).
@@ -119,12 +120,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 dbef6f3..11353b4 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -339,7 +339,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 1eb3c47..85fd370 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -709,7 +709,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, qc->dev->link->pmp, 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 3db3aa5..b310af4 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -806,7 +806,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] 15+ messages in thread
* [PATCH 03/12] libata-pmp-prep: make a number of functions global to libata
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (6 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 04/12] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 11/12] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM Tejun Heo
` (4 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Make a number of functions from libata-core.c and libata-eh.c global
to libata (drivers/ata/libata.h). These will be used by PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-core.c | 4 ++--
drivers/ata/libata-eh.c | 31 +++++++++++++++----------------
drivers/ata/libata.h | 17 +++++++++++++++++
3 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index d366ac2..1e1855e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6010,7 +6010,7 @@ void ata_dev_init(struct ata_device *dev)
* LOCKING:
* Kernel thread context (may sleep)
*/
-static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
{
int i;
@@ -6045,7 +6045,7 @@ static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
* RETURNS:
* 0 on success, -errno on failure.
*/
-static int sata_link_init_spd_limit(struct ata_link *link)
+int sata_link_init_spd_limit(struct ata_link *link)
{
u32 scontrol, spd;
int rc;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 7e8ec17..ec0b90b 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -74,7 +74,6 @@ static const unsigned long ata_eh_reset_timeouts[] = {
};
static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -883,7 +882,7 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc)
* LOCKING:
* None.
*/
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
{
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
@@ -920,8 +919,8 @@ static void ata_eh_detach_dev(struct ata_device *dev)
* LOCKING:
* None.
*/
-static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
- unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
struct ata_port *ap = link->ap;
struct ata_eh_info *ehi = &link->eh_info;
@@ -963,8 +962,8 @@ static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
* LOCKING:
* None.
*/
-static void ata_eh_done(struct ata_link *link, struct ata_device *dev,
- unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
struct ata_eh_context *ehc = &link->eh_context;
@@ -1624,7 +1623,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_autopsy(struct ata_port *ap)
+void ata_eh_autopsy(struct ata_port *ap)
{
struct ata_link *link;
@@ -1729,7 +1728,7 @@ static void ata_eh_link_report(struct ata_link *link)
* LOCKING:
* None.
*/
-static void ata_eh_report(struct ata_port *ap)
+void ata_eh_report(struct ata_port *ap)
{
struct ata_link *link;
@@ -1780,9 +1779,9 @@ static int ata_eh_followup_srst_needed(int rc, int classify,
return 0;
}
-static int ata_eh_reset(struct ata_link *link, int classify,
- ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
- ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
struct ata_eh_context *ehc = &link->eh_context;
unsigned int *classes = ehc->classes;
@@ -2158,10 +2157,10 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
* RETURNS:
* 0 on success, -errno on failure.
*/
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset,
- struct ata_link **r_failed_link)
+int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_link)
{
struct ata_link *link;
struct ata_device *dev;
@@ -2307,7 +2306,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
* LOCKING:
* None.
*/
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
{
int tag;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 4153817..114b988 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -93,6 +93,8 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device,
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int sata_link_init_spd_limit(struct ata_link *link);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct ata_port *ata_port_alloc(struct ata_host *host);
@@ -154,6 +156,21 @@ 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);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
/* libata-sff.c */
extern u8 ata_irq_on(struct ata_port *ap);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/12] libata-pmp-prep: implement ops->qc_defer()
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (2 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 07/12] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers Tejun Heo
` (8 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Controllers which support PMP have various restrictions on which
combinations of commands are allowed to what number of devices
concurrently. This patch implements ops->qc_defer() which determines
whether a qc can be issued at the moment or should be deferred.
If the function returns ATA_DEFER_LINK, the qc will be deferred until
a qc completes on the link. If ATA_DEFER_PORT, until a qc completes
on any link. The defer conditions are advisory and in general
ATA_DEFER_LINK can be considered as lower priority deferring than
ATA_DEFER_PORT.
ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard
NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and
sata_sil24 are converted to use ata_std_qc_defer().
ops->qc_defer() is heavier than the original mechanism because full qc
is prepped before determining to defer it, but various information is
needed to determine defer conditinos and fully translating a qc is the
only way to supply such information in generic manner.
IMHO, this shouldn't cause any noticeable performance issues as
* for most cases deferring occurs rarely (except for NCQ-aware
cmd-switching PMP)
* translation itself isn't that expensive
* once deferred the command won't be repeated until another command
completes which usually is a very long time cpu-wise.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/ahci.c | 2 +
drivers/ata/libata-core.c | 31 ++++++++++++++++++++++
drivers/ata/libata-scsi.c | 62 +++++++++++++++++++--------------------------
drivers/ata/sata_nv.c | 1 +
drivers/ata/sata_sil24.c | 1 +
include/linux/libata.h | 6 ++++
6 files changed, 67 insertions(+), 36 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index d3af721..88cfac0 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -267,6 +267,7 @@ static const struct ata_port_operations ahci_ops = {
.tf_read = ahci_tf_read,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
@@ -301,6 +302,7 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.tf_read = ahci_tf_read,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index e66f7c0..fb5d7e7 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4160,6 +4160,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
}
/**
+ * ata_std_qc_defer - Check whether a qc needs to be deferred
+ * @qc: ATA command in question
+ *
+ * Non-NCQ commands cannot run with any other command, NCQ or
+ * not. As upper layer only knows the queue depth, we are
+ * responsible for maintaining exclusion. This function checks
+ * whether a new command @qc can be issued.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ if (!ata_tag_valid(link->active_tag))
+ return 0;
+ } else {
+ if (!ata_tag_valid(link->active_tag) && !link->sactive)
+ return 0;
+ }
+
+ return ATA_DEFER_LINK;
+}
+
+/**
* ata_qc_prep - Prepare taskfile for submission
* @qc: Metadata associated with taskfile to be prepared
*
@@ -6921,6 +6951,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);
EXPORT_SYMBOL_GPL(ata_do_set_mode);
EXPORT_SYMBOL_GPL(ata_data_xfer);
EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index f7a9dc8..680850f 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -755,6 +755,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+
+ /* Schedule policy is determined by ->qc_defer() callback and
+ * it needs to see every deferred qc. Set dev_blocked to 1 to
+ * prevent SCSI midlayer from automatically deferring
+ * requests.
+ */
+ sdev->max_device_blocked = 1;
}
static void ata_scsi_dev_config(struct scsi_device *sdev,
@@ -1422,37 +1429,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
/**
- * ata_scmd_need_defer - Check whether we need to defer scmd
- * @dev: ATA device to which the command is addressed
- * @is_io: Is the command IO (and thus possibly NCQ)?
- *
- * NCQ and non-NCQ commands cannot run together. As upper layer
- * only knows the queue depth, we are responsible for maintaining
- * exclusion. This function checks whether a new command can be
- * issued to @dev.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * 1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
- struct ata_link *link = dev->link;
- int is_ncq = is_io && ata_ncq_enabled(dev);
-
- if (is_ncq) {
- if (!ata_tag_valid(link->active_tag))
- return 0;
- } else {
- if (!ata_tag_valid(link->active_tag) && !link->sactive)
- return 0;
- }
- return 1;
-}
-
-/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
@@ -1483,14 +1459,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
- int is_io = xlat_func == ata_scsi_rw_xlat;
+ int rc;
VPRINTK("ENTER\n");
- if (unlikely(ata_scmd_need_defer(dev, is_io)))
- goto defer;
-
qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
@@ -1518,6 +1492,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
if (xlat_func(qc))
goto early_finish;
+ if (ap->ops->qc_defer) {
+ if ((rc = ap->ops->qc_defer(qc)))
+ goto defer;
+ }
+
/* select device, send command to hardware */
ata_qc_issue(qc);
@@ -1539,8 +1518,12 @@ err_mem:
return 0;
defer:
+ ata_qc_free(qc);
DPRINTK("EXIT - defer\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ if (rc == ATA_DEFER_LINK)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ else
+ return SCSI_MLQUEUE_HOST_BUSY;
}
/**
@@ -2934,6 +2917,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
shost->max_channel = 1;
shost->max_cmd_len = 16;
+ /* Schedule policy is determined by ->qc_defer()
+ * callback and it needs to see every deferred qc.
+ * Set host_blocked to 1 to prevent SCSI midlayer from
+ * automatically deferring requests.
+ */
+ shost->max_host_blocked = 1;
+
rc = scsi_add_host(ap->scsi_host, ap->host->dev);
if (rc)
goto err_add;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 3a349e0..e9847fe 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -429,6 +429,7 @@ static const struct ata_port_operations nv_adma_ops = {
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = nv_adma_qc_prep,
.qc_issue = nv_adma_qc_issue,
.freeze = nv_adma_freeze,
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 85fd370..e2a41ff 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -394,6 +394,7 @@ static const struct ata_port_operations sil24_ops = {
.tf_read = sil24_tf_read,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b310af4..fa332e0 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -269,6 +269,10 @@ enum {
/* ering size */
ATA_ERING_SIZE = 32,
+ /* return values for ->qc_defer */
+ ATA_DEFER_LINK = 1,
+ ATA_DEFER_PORT = 2,
+
/* desc_len for ata_eh_info and context */
ATA_EH_DESC_LEN = 80,
@@ -637,6 +641,7 @@ struct ata_port_operations {
void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
+ int (*qc_defer) (struct ata_queued_cmd *qc);
void (*qc_prep) (struct ata_queued_cmd *qc);
unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
@@ -821,6 +826,7 @@ extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data);
extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data);
+extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
extern void ata_qc_prep(struct ata_queued_cmd *qc);
extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/12] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
2007-07-01 10:26 ` [PATCH 01/12] libata-pmp: add PMP related constants, fields, ops and update helpers Tejun Heo
2007-07-01 10:26 ` [PATCH 02/12] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 05/12] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
` (9 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Some links on some PMPs locks up on SRST and/or report incorrect
device signature. Implement ATA_LFLAG_NO_SRST, ASSUME_ATA and
ASSUME_SEMB to handle these quirky links. NO_SRST makes EH avoid
SRST. ASSUME_ATA and SEMB forces class code to ATA and SEMB_UNSUP
respectively. Note that SEMB isn't currently supported yet so the
_UNSUP variant is used.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-eh.c | 42 ++++++++++++++++++++++++++++++++----------
include/linux/libata.h | 4 ++++
2 files changed, 36 insertions(+), 10 deletions(-)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 3779067..5d06509 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1768,14 +1768,18 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
return 0;
}
-static int ata_eh_followup_srst_needed(int rc, int classify,
+static int ata_eh_followup_srst_needed(struct ata_link *link,
+ int rc, int classify,
const unsigned int *classes)
{
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ return 0;
if (rc == -EAGAIN)
return 1;
if (rc != 0)
return 0;
- if (classify && classes[0] == ATA_DEV_UNKNOWN)
+ if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
+ classes[0] == ATA_DEV_UNKNOWN)
return 1;
return 0;
}
@@ -1802,7 +1806,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
*/
action = ehc->i.action;
ehc->i.action &= ~ATA_EH_RESET_MASK;
- if (softreset && (!hardreset || (!sata_set_spd_needed(link) &&
+ if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) &&
+ !sata_set_spd_needed(link) &&
!(action & ATA_EH_HARDRESET))))
ehc->i.action |= ATA_EH_SOFTRESET;
else
@@ -1865,7 +1870,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
rc = ata_do_reset(link, reset, classes, deadline);
if (reset == hardreset &&
- ata_eh_followup_srst_needed(rc, classify, classes)) {
+ ata_eh_followup_srst_needed(link, rc, classify, classes)) {
/* okay, let's do follow-up softreset */
reset = softreset;
@@ -1880,8 +1885,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
rc = ata_do_reset(link, reset, classes, deadline);
- if (rc == 0 && classify &&
- classes[0] == ATA_DEV_UNKNOWN) {
+ if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN &&
+ !(link->flags & ATA_LFLAG_ASSUME_CLASS)) {
ata_link_printk(link, KERN_ERR,
"classification failed\n");
rc = -EINVAL;
@@ -1889,6 +1894,10 @@ int ata_eh_reset(struct ata_link *link, int classify,
}
}
+ /* if we skipped follow-up srst, clear rc */
+ if (rc == -EAGAIN)
+ rc = 0;
+
if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
unsigned long now = jiffies;
@@ -1913,12 +1922,25 @@ int ata_eh_reset(struct ata_link *link, 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.
- */
- ata_link_for_each_dev(dev, link)
+ ata_link_for_each_dev(dev, link) {
+ /* After the reset, the device state is PIO 0
+ * and the controller state is undefined.
+ * Record the mode.
+ */
dev->pio_mode = XFER_PIO_0;
+ if (ata_link_offline(link))
+ continue;
+
+ /* apply class override and convert UNKNOWN to NONE */
+ if (link->flags & ATA_LFLAG_ASSUME_ATA)
+ classes[dev->devno] = ATA_DEV_ATA;
+ else if (link->flags & ATA_LFLAG_ASSUME_SEMB)
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+ else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ }
+
/* record current link speed */
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
link->sata_spd = (sstatus >> 4) & 0xf;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 349180a..57da3ba 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -163,6 +163,10 @@ enum {
ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */
ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H
* Register FIS clearing BSY */
+ ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */
+ ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */
+ ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */
+ ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB,
/* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/12] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (4 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 04/12] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
` (6 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Some PMP links are connected to internal pseudo devices which may come
and go depending on situation. There's no reason to try hard to
recover them. ATA_LFLAG_NO_RETRY tells EH to not retry if the device
attached to the link fails.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-eh.c | 5 ++++-
include/linux/libata.h | 1 +
2 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 5d06509..e4363af 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2197,7 +2197,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
struct ata_eh_context *ehc = &link->eh_context;
ata_link_for_each_dev(dev, link) {
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+ if (link->flags & ATA_LFLAG_NO_RETRY)
+ ehc->tries[dev->devno] = 1;
+ else
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
/* collect port action mask recorded in dev actions */
ehc->i.action |= ehc->i.dev_action[dev->devno] &
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 57da3ba..3ac3763 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -167,6 +167,7 @@ enum {
ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */
ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */
ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB,
+ ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */
/* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (3 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 05/12] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 08/12] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY Tejun Heo
` (7 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Implement ap->nr_active_links (the number of links with active qcs),
ap->excl_link (pointer to link which can be used by ->qc_defer and is
cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and
ata_link_active().
These can be used by ->qc_defer() to implement proper command
exclusion. This set of helpers seem enough for both sil24 (ATAPI
exclusion needed) and cmd-switching PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-core.c | 22 ++++++++++++++++++++--
drivers/ata/libata-eh.c | 5 +++++
include/linux/libata.h | 8 ++++++++
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index fb5d7e7..17b1734 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1381,6 +1381,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
+ int preempted_nr_active_links;
DECLARE_COMPLETION_ONSTACK(wait);
unsigned long flags;
unsigned int err_mask;
@@ -1419,9 +1420,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
preempted_tag = link->active_tag;
preempted_sactive = link->sactive;
preempted_qc_active = ap->qc_active;
+ preempted_nr_active_links = ap->nr_active_links;
link->active_tag = ATA_TAG_POISON;
link->sactive = 0;
ap->qc_active = 0;
+ ap->nr_active_links = 0;
/* prepare & issue qc */
qc->tf = *tf;
@@ -1500,6 +1503,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
link->active_tag = preempted_tag;
link->sactive = preempted_sactive;
ap->qc_active = preempted_qc_active;
+ ap->nr_active_links = preempted_nr_active_links;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -5208,10 +5212,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ)
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
link->sactive &= ~(1 << qc->tag);
- else
+ if (!link->sactive)
+ ap->nr_active_links--;
+ } else {
link->active_tag = ATA_TAG_POISON;
+ ap->nr_active_links--;
+ }
+
+ /* clear exclusive status */
+ if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
+ ap->excl_link == link))
+ ap->excl_link = NULL;
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
@@ -5390,9 +5403,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
if (qc->tf.protocol == ATA_PROT_NCQ) {
WARN_ON(link->sactive & (1 << qc->tag));
+
+ if (!link->sactive)
+ ap->nr_active_links++;
link->sactive |= 1 << qc->tag;
} else {
WARN_ON(link->sactive);
+
+ ap->nr_active_links++;
link->active_tag = qc->tag;
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ec0b90b..3779067 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -316,6 +316,7 @@ void ata_scsi_error(struct Scsi_Host *host)
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+ ap->excl_link = NULL; /* don't maintain exclusion over EH */
spin_unlock_irqrestore(ap->lock, flags);
@@ -2336,6 +2337,10 @@ void ata_eh_finish(struct ata_port *ap)
}
}
}
+
+ /* make sure nr_active_links is zero after EH */
+ WARN_ON(ap->nr_active_links);
+ ap->nr_active_links = 0;
}
/**
diff --git a/include/linux/libata.h b/include/linux/libata.h
index fa332e0..349180a 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -215,6 +215,7 @@ enum {
ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
+ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */
ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
@@ -576,11 +577,13 @@ struct ata_port {
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
unsigned long qc_allocated;
unsigned int qc_active;
+ int nr_active_links; /* #links with active qcs */
struct ata_link link; /* host default link */
int nr_pmp_links; /* nr of available PMP links */
struct ata_link *pmp_link; /* array of PMP links */
+ struct ata_link *excl_link; /* for PMP qc exclusion */
struct ata_port_stats stats;
struct ata_host *host;
@@ -1093,6 +1096,11 @@ static inline int ata_link_max_devices(const struct ata_link *link)
return 1;
}
+static inline int ata_link_active(struct ata_link *link)
+{
+ return ata_tag_valid(link->active_tag) || link->sactive;
+}
+
static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
{
if (ap->nr_pmp_links)
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/12] libata-pmp-prep: implement EH fast-fail path
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (8 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 11/12] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 09/12] libata-pmp-prep: implement ATA_LFLAG_DISABLED Tejun Heo
` (2 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
If PMP itself becomes inaccessible while trying to link a downstream
link, spending time to recover the downstream link doesn't make any
sense. Make EH skip retry and fail fast if -ERESTART is received.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-eh.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 0a60105..f4dae06 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1912,7 +1912,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
if (rc == -EAGAIN)
rc = 0;
- if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
+ if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
unsigned long now = jiffies;
if (time_before(now, deadline)) {
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 11/12] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (7 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 03/12] libata-pmp-prep: make a number of functions global to libata Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 10/12] libata-pmp-prep: implement EH fast-fail path Tejun Heo
` (3 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Some pseudo devices fail PM commands unnecessarily aborting system
suspend. Implement ATA_HORKAGE_SKIP_PM which makes libata skip PM
commands for these devices.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-scsi.c | 7 +++++++
include/linux/libata.h | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 680850f..6317533 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -950,6 +950,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
goto invalid_fld; /* LOEJ bit set not supported */
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
+
+ if (ata_device_blacklisted(qc->dev) & ATA_HORKAGE_SKIP_PM) {
+ /* the device lacks PM support, finish without doing anything */
+ scmd->result = SAM_STAT_GOOD;
+ return 1;
+ }
+
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 6b7b346..d41da74 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -325,6 +325,7 @@ enum {
ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */
ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */
ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */
+ ATA_HORKAGE_SKIP_PM = (1 << 4), /* Skip PM operations */
};
enum hsm_task_states {
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/12] libata-pmp-prep: implement ATA_LFLAG_DISABLED
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (9 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 10/12] libata-pmp-prep: implement EH fast-fail path Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-01 10:26 ` [PATCH 12/12] libata-pmp-prep: implement sata_async_notification() Tejun Heo
2007-07-11 2:04 ` [PATCHSET 3/4] libata: prep for PMP support, take 4 Jeff Garzik
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Implement ATA_LFLAG_DISABLED. The flag indicates the link is disabled
due to EH recovery failure. While a link is disabled, no EH action is
taken on the link and suspend/resume become noop too.
This will be used by PMP links to manage failed links.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-eh.c | 30 +++++++++++++++++++++++++++++-
include/linux/libata.h | 3 +++
2 files changed, 32 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index e4363af..0a60105 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1176,6 +1176,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
struct ata_eh_context *ehc = &link->eh_context;
u32 serror = ehc->i.serror;
unsigned int err_mask = 0, action = 0;
+ u32 hotplug_mask;
if (serror & SERR_PERSISTENT) {
err_mask |= AC_ERR_ATA_BUS;
@@ -1194,7 +1195,20 @@ static void ata_eh_analyze_serror(struct ata_link *link)
err_mask |= AC_ERR_SYSTEM;
action |= ATA_EH_HARDRESET;
}
- if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+ /* Determine whether a hotplug event has occurred. Both
+ * SError.N/X are considered hotplug events for enabled or
+ * host links. For disabled PMP links, only N bit is
+ * considered as X bit is left at 1 for link plugging.
+ */
+ hotplug_mask = 0;
+
+ if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+ hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+ else
+ hotplug_mask = SERR_PHYRDY_CHG;
+
+ if (serror & hotplug_mask)
ata_ehi_hotplugged(&ehc->i);
ehc->i.err_mask |= err_mask;
@@ -2089,6 +2103,10 @@ static int ata_eh_skip_recovery(struct ata_link *link)
struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev;
+ /* skip disabled links */
+ if (link->flags & ATA_LFLAG_DISABLED)
+ return 1;
+
/* thaw frozen port, resume link and recover failed devices */
if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
(ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
@@ -2189,6 +2207,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
struct ata_device *dev;
int nr_failed_devs, nr_disabled_devs;
int reset, rc;
+ unsigned long flags;
DPRINTK("ENTER\n");
@@ -2196,6 +2215,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_port_for_each_link(link, ap) {
struct ata_eh_context *ehc = &link->eh_context;
+ /* re-enable link? */
+ if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+ ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags &= ~ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+ }
+
ata_link_for_each_dev(dev, link) {
if (link->flags & ATA_LFLAG_NO_RETRY)
ehc->tries[dev->devno] = 1;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 3ac3763..6b7b346 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -168,6 +168,7 @@ enum {
ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */
ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB,
ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */
+ ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */
/* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
@@ -286,6 +287,7 @@ enum {
ATA_EH_REVALIDATE = (1 << 0),
ATA_EH_SOFTRESET = (1 << 1),
ATA_EH_HARDRESET = (1 << 2),
+ ATA_EH_ENABLE_LINK = (1 << 3),
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
@@ -998,6 +1000,7 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
ata_ehi_schedule_probe(ehi);
ehi->flags |= ATA_EHI_HOTPLUGGED;
+ ehi->action |= ATA_EH_ENABLE_LINK;
ehi->err_mask |= AC_ERR_ATA_BUS;
}
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 12/12] libata-pmp-prep: implement sata_async_notification()
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (10 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 09/12] libata-pmp-prep: implement ATA_LFLAG_DISABLED Tejun Heo
@ 2007-07-01 10:26 ` Tejun Heo
2007-07-11 2:04 ` [PATCHSET 3/4] libata: prep for PMP support, take 4 Jeff Garzik
12 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-07-01 10:26 UTC (permalink / raw)
To: Jeff Garzik, Alan Cox, linux-ide, Forrest Zhao; +Cc: Tejun Heo
Implement SATA async notification handler sata_async_notification().
LLDs can call this function when it suspects SDB_NOTIFY has occurred.
This function will check SCR_NOTIFICATION if available and schedule
proper EH action.
Currently, only PMP notification is handled. The function can be
easily extended to cover ATAPI notification later.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-core.c | 1 +
drivers/ata/libata-eh.c | 49 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/libata.h | 1 +
3 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 17b1734..2d960da 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -7051,6 +7051,7 @@ EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
EXPORT_SYMBOL_GPL(ata_link_abort);
EXPORT_SYMBOL_GPL(ata_port_abort);
EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(sata_async_notification);
EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index f4dae06..03b1665 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -773,6 +773,55 @@ int ata_port_freeze(struct ata_port *ap)
}
/**
+ * sata_async_notification - SATA async notification handler
+ * @ap: ATA port where async notification is received
+ *
+ * Handler to be called when async notification via SDB FIS is
+ * received. This function schedules EH if necessary.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+ u32 sntf;
+ int rc;
+
+ if (!(ap->flags & ATA_FLAG_SDB_NOTIFY))
+ return 0;
+
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0) {
+ if (!sntf)
+ return 0;
+
+ /* clear it */
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ /* PMP is reporting that PHY status of some downstream
+ * ports have changed. Schedule EH.
+ */
+ if (ap->nr_pmp_links && (sntf & (1 << SATA_PMP_CTRL_PORT))) {
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+ } else {
+ /* Dunno what's going on. Schedule EH if PMP is
+ * attached. It might be reporting PHY status change.
+ */
+ if (ap->nr_pmp_links) {
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
* ata_eh_freeze_port - EH helper to freeze port
* @ap: ATA port to freeze
*
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d41da74..09959a7 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -947,6 +947,7 @@ extern void ata_port_schedule_eh(struct ata_port *ap);
extern int ata_link_abort(struct ata_link *link);
extern int ata_port_abort(struct ata_port *ap);
extern int ata_port_freeze(struct ata_port *ap);
+extern int sata_async_notification(struct ata_port *ap);
extern void ata_eh_freeze_port(struct ata_port *ap);
extern void ata_eh_thaw_port(struct ata_port *ap);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCHSET 3/4] libata: prep for PMP support, take 4
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
` (11 preceding siblings ...)
2007-07-01 10:26 ` [PATCH 12/12] libata-pmp-prep: implement sata_async_notification() Tejun Heo
@ 2007-07-11 2:04 ` Jeff Garzik
12 siblings, 0 replies; 15+ messages in thread
From: Jeff Garzik @ 2007-07-11 2:04 UTC (permalink / raw)
To: Tejun Heo; +Cc: Alan Cox, linux-ide, Forrest Zhao
Tejun Heo wrote:
> Hello, all.
>
> This is the fourth take of libata-pmp-prep patchset. This patchset
> contains 12 patches implementing various stuff needed for PMP.
>
> #01 : add PMP related constants
> #02-04 : various small stuff
> #05-06 : qc_defer mechanism implementation
> #07-11 : link/device quirks and EH fast-fail path - things needed to
> handle quirky PMP fan-out links / pseudo devices.
> #12 : SATA SDB notify handler
>
> Changes from the last take[L] are.
>
> * PMP related constants patch moved here from pmp patchset
> * qc_defer CLEAR_EXCL fixed to clear excl_link iff it points to self
> * addition of various quirks/special case handling vital for
> supporting first-gen PMP chips
> * generalized SDB notify handling
>
> This patchset is against
>
> libata-dev#upstream (4e1ae96828f6cee7b89ab8ca474c150fe211afd8)
> + [1] misc-updates patchset
> + [2] libata-link patchset, take 4
seems generally OK to me
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
0 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
Implement ap->nr_active_links (the number of links with active qcs),
ap->excl_link (pointer to link which can be used by ->qc_defer and is
cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and
ata_link_active().
These can be used by ->qc_defer() to implement proper command
exclusion. This set of helpers seem enough for both sil24 (ATAPI
exclusion needed) and cmd-switching PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/libata-core.c | 22 ++++++++++++++++++++--
drivers/ata/libata-eh.c | 5 +++++
include/linux/libata.h | 8 ++++++++
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 7dd666e..86ef06e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1392,6 +1392,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
+ int preempted_nr_active_links;
DECLARE_COMPLETION_ONSTACK(wait);
unsigned long flags;
unsigned int err_mask;
@@ -1430,9 +1431,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
preempted_tag = link->active_tag;
preempted_sactive = link->sactive;
preempted_qc_active = ap->qc_active;
+ preempted_nr_active_links = ap->nr_active_links;
link->active_tag = ATA_TAG_POISON;
link->sactive = 0;
ap->qc_active = 0;
+ ap->nr_active_links = 0;
/* prepare & issue qc */
qc->tf = *tf;
@@ -1511,6 +1514,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
link->active_tag = preempted_tag;
link->sactive = preempted_sactive;
ap->qc_active = preempted_qc_active;
+ ap->nr_active_links = preempted_nr_active_links;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -5410,10 +5414,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ)
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
link->sactive &= ~(1 << qc->tag);
- else
+ if (!link->sactive)
+ ap->nr_active_links--;
+ } else {
link->active_tag = ATA_TAG_POISON;
+ ap->nr_active_links--;
+ }
+
+ /* clear exclusive status */
+ if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
+ ap->excl_link == link))
+ ap->excl_link = NULL;
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
@@ -5592,9 +5605,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
if (qc->tf.protocol == ATA_PROT_NCQ) {
WARN_ON(link->sactive & (1 << qc->tag));
+
+ if (!link->sactive)
+ ap->nr_active_links++;
link->sactive |= 1 << qc->tag;
} else {
WARN_ON(link->sactive);
+
+ ap->nr_active_links++;
link->active_tag = qc->tag;
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 1d3b0dc..5244723 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -451,6 +451,7 @@ void ata_scsi_error(struct Scsi_Host *host)
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+ ap->excl_link = NULL; /* don't maintain exclusion over EH */
spin_unlock_irqrestore(ap->lock, flags);
@@ -2474,6 +2475,10 @@ void ata_eh_finish(struct ata_port *ap)
}
}
}
+
+ /* make sure nr_active_links is zero after EH */
+ WARN_ON(ap->nr_active_links);
+ ap->nr_active_links = 0;
}
/**
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b0d4ca0..f9f81fd 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -216,6 +216,7 @@ enum {
ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
+ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */
ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
@@ -579,11 +580,13 @@ struct ata_port {
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
unsigned long qc_allocated;
unsigned int qc_active;
+ int nr_active_links; /* #links with active qcs */
struct ata_link link; /* host default link */
int nr_pmp_links; /* nr of available PMP links */
struct ata_link *pmp_link; /* array of PMP links */
+ struct ata_link *excl_link; /* for PMP qc exclusion */
struct ata_port_stats stats;
struct ata_host *host;
@@ -1104,6 +1107,11 @@ static inline int ata_link_max_devices(const struct ata_link *link)
return 1;
}
+static inline int ata_link_active(struct ata_link *link)
+{
+ return ata_tag_valid(link->active_tag) || link->sactive;
+}
+
static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
{
if (ap->nr_pmp_links)
--
1.5.0.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
end of thread, other threads:[~2007-09-23 4:19 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-01 10:26 [PATCHSET 3/4] libata: prep for PMP support, take 4 Tejun Heo
2007-07-01 10:26 ` [PATCH 01/12] libata-pmp: add PMP related constants, fields, ops and update helpers Tejun Heo
2007-07-01 10:26 ` [PATCH 02/12] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
2007-07-01 10:26 ` [PATCH 07/12] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB Tejun Heo
2007-07-01 10:26 ` [PATCH 05/12] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
2007-07-01 10:26 ` [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers Tejun Heo
2007-07-01 10:26 ` [PATCH 08/12] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY Tejun Heo
2007-07-01 10:26 ` [PATCH 04/12] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
2007-07-01 10:26 ` [PATCH 03/12] libata-pmp-prep: make a number of functions global to libata Tejun Heo
2007-07-01 10:26 ` [PATCH 11/12] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM Tejun Heo
2007-07-01 10:26 ` [PATCH 10/12] libata-pmp-prep: implement EH fast-fail path Tejun Heo
2007-07-01 10:26 ` [PATCH 09/12] libata-pmp-prep: implement ATA_LFLAG_DISABLED Tejun Heo
2007-07-01 10:26 ` [PATCH 12/12] libata-pmp-prep: implement sata_async_notification() Tejun Heo
2007-07-11 2:04 ` [PATCHSET 3/4] libata: prep for PMP support, take 4 Jeff Garzik
-- strict thread matches above, loose matches on Subject: below --
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
2007-09-23 4:14 ` [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers Tejun Heo
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.