* [PATCH 01/12] libata: misc updates for AN
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-26 2:27 ` Jeff Garzik
2007-09-23 4:14 ` [PATCH 04/12] libata-pmp-prep: make a number of functions global to libata Tejun Heo
` (10 subsequent siblings)
11 siblings, 1 reply; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
Update AN support in preparation of PMP support.
* s/ata_id_has_AN/ata_id_has_atapi_AN/
* add AN enabled reporting during configuration
* add err_mask to AN configuration failure reporting
* update LOCKING comment for ata_scsi_media_change_notify()
* check whether ATA dev is attached to SCSI dev ata_scsi_media_change_notify()
* set ATA_FLAG_AN in ahci and sata_sil24
Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Kriten Carlson Accardi <kristen.c.accardi@intel.com>
---
drivers/ata/ahci.c | 2 +-
drivers/ata/libata-core.c | 24 ++++++++++++++----------
drivers/ata/libata-scsi.c | 7 ++++---
drivers/ata/sata_sil24.c | 13 +++++++++++--
include/linux/ata.h | 2 +-
5 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index b721569..0a6b694 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -177,7 +177,7 @@ enum {
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY,
};
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 2116f27..63274b6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2012,7 +2012,8 @@ int ata_dev_configure(struct ata_device *dev)
/* ATAPI-specific feature tests */
else if (dev->class == ATA_DEV_ATAPI) {
- char *cdb_intr_string = "";
+ const char *cdb_intr_string = "";
+ const char *atapi_an_string = "";
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -2028,16 +2029,19 @@ int ata_dev_configure(struct ata_device *dev)
* check to see if this ATAPI device supports
* Asynchronous Notification
*/
- if ((ap->flags & ATA_FLAG_AN) && ata_id_has_AN(id)) {
- int err;
+ if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id)) {
+ unsigned int err_mask;
+
/* issue SET feature command to turn this on */
- err = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE);
- if (err)
+ err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE);
+ if (err_mask)
ata_dev_printk(dev, KERN_ERR,
- "unable to set AN, err %x\n",
- err);
- else
+ "failed to enable ATAPI AN "
+ "(err_mask=0x%x)\n", err_mask);
+ else {
dev->flags |= ATA_DFLAG_AN;
+ atapi_an_string = ", ATAPI AN";
+ }
}
if (ata_id_cdb_intr(dev->id)) {
@@ -2048,10 +2052,10 @@ int ata_dev_configure(struct ata_device *dev)
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
- "ATAPI: %s, %s, max %s%s\n",
+ "ATAPI: %s, %s, max %s%s%s\n",
modelbuf, fwrevbuf,
ata_mode_string(xfer_mask),
- cdb_intr_string);
+ cdb_intr_string, atapi_an_string);
}
/* determine max_sectors */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 35284b3..518d475 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3161,12 +3161,13 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)
* event.
*
* LOCKING:
- * interrupt context, may not sleep.
+ * spin_lock_irqsave(host lock)
*/
-void ata_scsi_media_change_notify(struct ata_device *atadev)
+void ata_scsi_media_change_notify(struct ata_device *dev)
{
#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED
- scsi_device_event_notify(atadev->sdev, SDEV_MEDIA_CHANGE);
+ if (dev->sdev)
+ scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE);
#endif
}
EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify);
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 3dcb223..d9c010a 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -168,7 +168,7 @@ enum {
DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
- PORT_IRQ_UNK_FIS,
+ PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,
/* bits[27:16] are unmasked (raw) */
PORT_IRQ_RAW_SHIFT = 16,
@@ -237,7 +237,8 @@ enum {
/* host flags */
SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
+ ATA_FLAG_AN,
SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY,
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
@@ -818,6 +819,14 @@ static void sil24_error_intr(struct ata_port *ap)
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
+ struct ata_device *dev = ap->link.device;
+
+ ata_ehi_push_desc(ehi, "SDB notify");
+ if (dev->flags & ATA_DFLAG_AN)
+ ata_scsi_media_change_notify(dev);
+ }
+
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, "%s",
diff --git a/include/linux/ata.h b/include/linux/ata.h
index a749f00..21f00a0 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -353,7 +353,7 @@ struct ata_taskfile {
#define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1)
#define ata_id_removeable(id) ((id)[0] & (1 << 7))
#define ata_id_has_dword_io(id) ((id)[48] & (1 << 0))
-#define ata_id_has_AN(id) \
+#define ata_id_has_atapi_AN(id) \
( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
((id)[78] & (1 << 5)) )
#define ata_id_iordy_disable(id) ((id)[49] & (1 << 10))
--
1.5.0.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH 01/12] libata: misc updates for AN
2007-09-23 4:14 ` [PATCH 01/12] libata: misc updates for AN Tejun Heo
@ 2007-09-26 2:27 ` Jeff Garzik
0 siblings, 0 replies; 14+ messages in thread
From: Jeff Garzik @ 2007-09-26 2:27 UTC (permalink / raw)
To: Tejun Heo; +Cc: alan, linux-ide
Tejun Heo wrote:
> Update AN support in preparation of PMP support.
>
> * s/ata_id_has_AN/ata_id_has_atapi_AN/
> * add AN enabled reporting during configuration
> * add err_mask to AN configuration failure reporting
> * update LOCKING comment for ata_scsi_media_change_notify()
> * check whether ATA dev is attached to SCSI dev ata_scsi_media_change_notify()
> * set ATA_FLAG_AN in ahci and sata_sil24
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> Cc: Kriten Carlson Accardi <kristen.c.accardi@intel.com>
> ---
> drivers/ata/ahci.c | 2 +-
> drivers/ata/libata-core.c | 24 ++++++++++++++----------
> drivers/ata/libata-scsi.c | 7 ++++---
> drivers/ata/sata_sil24.c | 13 +++++++++++--
> include/linux/ata.h | 2 +-
> 5 files changed, 31 insertions(+), 17 deletions(-)
applied 1-12
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 04/12] libata-pmp-prep: make a number of functions global to libata
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
2007-09-23 4:14 ` [PATCH 01/12] libata: misc updates for AN Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 08/12] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY Tejun Heo
` (9 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 bcddc93..c33a1f8 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6220,7 +6220,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;
@@ -6255,7 +6255,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(struct ata_link *link)
+int sata_link_init_spd(struct ata_link *link)
{
u32 scontrol, spd;
int rc;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index eb087bb..1d3b0dc 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);
@@ -1015,7 +1014,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;
@@ -1052,8 +1051,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;
@@ -1095,8 +1094,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;
@@ -1756,7 +1755,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;
@@ -1867,7 +1866,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;
@@ -1918,9 +1917,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;
@@ -2296,10 +2295,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;
@@ -2445,7 +2444,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 3457048..e380423 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -94,6 +94,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(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);
@@ -155,6 +157,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] 14+ messages in thread* [PATCH 08/12] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
2007-09-23 4:14 ` [PATCH 01/12] libata: misc updates for AN Tejun Heo
2007-09-23 4:14 ` [PATCH 04/12] libata-pmp-prep: make a number of functions global to libata Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 02/12] libata-pmp-prep: add PMP related constants, fields, ops and update helpers Tejun Heo
` (8 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 7be04bd..8f8ed4d 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2335,7 +2335,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 6266fff..adeee73 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -169,6 +169,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] 14+ messages in thread* [PATCH 02/12] libata-pmp-prep: add PMP related constants, fields, ops and update helpers
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (2 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 08/12] libata-pmp-prep: implement ATA_LFLAG_NO_RETRY Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 03/12] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
` (7 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 | 30 ++++++++++++++++++++++++++----
1 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 3ab2196..c3820f1 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -155,7 +155,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 */
@@ -181,6 +185,7 @@ enum {
ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */
ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */
ATA_FLAG_AN = (1 << 18), /* controller supports AN */
+ ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */
/* The following flag belongs to ap->pflags but is kept in
* ap->flags because it's referenced in many LLDs and will be
@@ -299,6 +304,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 */
@@ -450,7 +459,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;
@@ -628,6 +642,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.
*/
@@ -1033,12 +1053,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] 14+ messages in thread* [PATCH 03/12] libata-pmp-prep: add @new_class to ata_dev_revalidate()
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (3 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 02/12] libata-pmp-prep: add PMP related constants, fields, ops and update helpers Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers Tejun Heo
` (6 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 63274b6..bcddc93 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2848,7 +2848,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;
@@ -3752,6 +3752,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
@@ -3763,7 +3764,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;
@@ -3771,6 +3773,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 daa2f74..eb087bb 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2104,7 +2104,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 11f64a4..3457048 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -77,7 +77,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] 14+ 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
` (4 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 03/12] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 07/12] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB Tejun Heo
` (5 subsequent siblings)
11 siblings, 0 replies; 14+ 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] 14+ messages in thread* [PATCH 07/12] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (5 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 06/12] libata-pmp-prep: implement qc_defer helpers Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 05/12] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
` (4 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 5244723..7be04bd 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1906,14 +1906,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;
}
@@ -1940,7 +1944,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
@@ -2003,7 +2008,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;
@@ -2018,8 +2023,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;
@@ -2027,6 +2032,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;
@@ -2051,12 +2060,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 f9f81fd..6266fff 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -165,6 +165,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] 14+ messages in thread* [PATCH 05/12] libata-pmp-prep: implement ops->qc_defer()
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (6 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 07/12] libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 10/12] libata-pmp-prep: implement EH fast-fail path Tejun Heo
` (3 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 0a6b694..cf34044 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -268,6 +268,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,
@@ -298,6 +299,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 c33a1f8..7dd666e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4348,6 +4348,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
*
@@ -7113,6 +7143,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_dumb_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 518d475..eb611b4 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -750,6 +750,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,
@@ -1417,37 +1424,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
@@ -1478,14 +1454,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;
@@ -1509,6 +1483,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);
@@ -1530,8 +1509,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;
}
/**
@@ -2957,6 +2940,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 b860f99..40557fe 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -423,6 +423,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 d9c010a..9acfce4 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -393,6 +393,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 c3820f1..b0d4ca0 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -272,6 +272,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,
@@ -639,6 +643,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);
@@ -824,6 +829,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_dumb_qc_prep(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);
--
1.5.0.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 10/12] libata-pmp-prep: implement EH fast-fail path
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (7 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 05/12] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 12/12] libata-pmp-prep: implement sata_async_notification() Tejun Heo
` (2 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 fbbf791..3c31e10 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2050,7 +2050,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] 14+ messages in thread* [PATCH 12/12] libata-pmp-prep: implement sata_async_notification()
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (8 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 10/12] libata-pmp-prep: implement EH fast-fail path Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 09/12] libata-pmp-prep: implement ATA_LFLAG_DISABLED Tejun Heo
2007-09-23 4:14 ` [PATCH 11/12] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM Tejun Heo
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
AN serves multiple purposes. For ATAPI, it's used for media change
notification. For PMP, for downstream PHY status change notification.
Implement sata_async_notification() which demultiplexes AN.
To avoid unnecessary port events, ATAPI AN is not enabled if PMP is
attached but SNTF is not available.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Kriten Carlson Accardi <kristen.c.accardi@intel.com>
---
drivers/ata/ahci.c | 24 ++++----------
drivers/ata/libata-core.c | 13 +++++--
drivers/ata/libata-eh.c | 73 +++++++++++++++++++++++++++++++++++++++++++++
drivers/ata/libata-scsi.c | 1 -
drivers/ata/libata.h | 1 +
drivers/ata/sata_sil24.c | 5 +--
include/linux/libata.h | 4 +-
7 files changed, 93 insertions(+), 28 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index cf34044..9f3c591 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1356,27 +1356,17 @@ static void ahci_port_intr(struct ata_port *ap)
}
if (status & PORT_IRQ_SDB_FIS) {
- /*
- * if this is an ATAPI device with AN turned on,
- * then we should interrogate the device to
- * determine the cause of the interrupt
- *
- * for AN - this we should check the SDB FIS
- * and find the I and N bits set
+ /* If the 'N' bit in word 0 of the FIS is set, we just
+ * received asynchronous notification. Tell libata
+ * about it. Note that as the SDB FIS itself is
+ * accessible, SNotification can be emulated by the
+ * driver but don't bother for the time being.
*/
const __le32 *f = pp->rx_fis + RX_FIS_SDB;
u32 f0 = le32_to_cpu(f[0]);
- /* check the 'N' bit in word 0 of the FIS */
- if (f0 & (1 << 15)) {
- int port_addr = ((f0 & 0x00000f00) >> 8);
- struct ata_device *adev;
- if (port_addr < ATA_MAX_DEVICES) {
- adev = &ap->link.device[port_addr];
- if (adev->flags & ATA_DFLAG_AN)
- ata_scsi_media_change_notify(adev);
- }
- }
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
}
if (ap->link.sactive)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 86ef06e..e650fb9 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2018,6 +2018,7 @@ int ata_dev_configure(struct ata_device *dev)
else if (dev->class == ATA_DEV_ATAPI) {
const char *cdb_intr_string = "";
const char *atapi_an_string = "";
+ u32 sntf;
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -2029,11 +2030,14 @@ int ata_dev_configure(struct ata_device *dev)
}
dev->cdb_len = (unsigned int) rc;
- /*
- * check to see if this ATAPI device supports
- * Asynchronous Notification
+ /* Enable ATAPI AN if both the host and device have
+ * the support. If PMP is attached, SNTF is required
+ * to enable ATAPI AN to discern between PHY status
+ * changed notifications and ATAPI ANs.
*/
- if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id)) {
+ if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+ (!ap->nr_pmp_links ||
+ sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
unsigned int err_mask;
/* issue SET feature command to turn this on */
@@ -7250,6 +7254,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 3c31e10..60186f8 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -905,6 +905,79 @@ 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_AN))
+ return 0;
+
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0)
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ if (!ap->nr_pmp_links || rc) {
+ /* PMP is not attached or SNTF is not available */
+ if (!ap->nr_pmp_links) {
+ /* PMP is not attached. Check whether ATAPI
+ * AN is configured. If so, notify media
+ * change.
+ */
+ struct ata_device *dev = ap->link.device;
+
+ if ((dev->class == ATA_DEV_ATAPI) &&
+ (dev->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(dev);
+ return 0;
+ } else {
+ /* PMP is attached but SNTF is not available.
+ * ATAPI async media change notification is
+ * not used. The PMP must be reporting PHY
+ * status change, schedule EH.
+ */
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+ } else {
+ /* PMP is attached and SNTF is available */
+ struct ata_link *link;
+
+ /* check and notify ATAPI AN */
+ ata_port_for_each_link(link, ap) {
+ if (!(sntf & (1 << link->pmp)))
+ continue;
+
+ if ((link->device->class == ATA_DEV_ATAPI) &&
+ (link->device->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(link->device);
+ }
+
+ /* If PMP is reporting that PHY status of some
+ * downstream ports has changed, schedule EH.
+ */
+ if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+ 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/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a651bdd..116d875 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3167,7 +3167,6 @@ void ata_scsi_media_change_notify(struct ata_device *dev)
scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE);
#endif
}
-EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify);
/**
* ata_scsi_hotplug - SCSI part of hotplug
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index e380423..fc8a786 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -118,6 +118,7 @@ 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, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_media_change_notify(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,
unsigned int buflen);
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 9acfce4..b4f81eb 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -821,11 +821,8 @@ static void sil24_error_intr(struct ata_port *ap)
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
- struct ata_device *dev = ap->link.device;
-
ata_ehi_push_desc(ehi, "SDB notify");
- if (dev->flags & ATA_DFLAG_AN)
- ata_scsi_media_change_notify(dev);
+ sata_async_notification(ap);
}
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 56b2187..cd9c2a2 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -139,7 +139,7 @@ enum {
ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */
ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
- ATA_DFLAG_AN = (1 << 7), /* device supports AN */
+ ATA_DFLAG_AN = (1 << 7), /* AN configured */
ATA_DFLAG_CFG_MASK = (1 << 12) - 1,
ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */
@@ -787,7 +787,6 @@ extern void ata_host_init(struct ata_host *, struct device *,
extern int ata_scsi_detect(struct scsi_host_template *sht);
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
-extern void ata_scsi_media_change_notify(struct ata_device *atadev);
extern void ata_sas_port_destroy(struct ata_port *);
extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
struct ata_port_info *, struct Scsi_Host *);
@@ -953,6 +952,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] 14+ messages in thread* [PATCH 09/12] libata-pmp-prep: implement ATA_LFLAG_DISABLED
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (9 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 12/12] libata-pmp-prep: implement sata_async_notification() Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
2007-09-23 4:14 ` [PATCH 11/12] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM Tejun Heo
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 8f8ed4d..fbbf791 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1308,6 +1308,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;
@@ -1326,7 +1327,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;
@@ -2227,6 +2241,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))
@@ -2327,6 +2345,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");
@@ -2334,6 +2353,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 adeee73..2bd1d26 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -170,6 +170,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 */
@@ -289,6 +290,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,
@@ -999,6 +1001,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] 14+ messages in thread* [PATCH 11/12] libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM
2007-09-23 4:14 [PATCHSET 1/2] libata: prep for PMP support, take 6 Tejun Heo
` (10 preceding siblings ...)
2007-09-23 4:14 ` [PATCH 09/12] libata-pmp-prep: implement ATA_LFLAG_DISABLED Tejun Heo
@ 2007-09-23 4:14 ` Tejun Heo
11 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2007-09-23 4:14 UTC (permalink / raw)
To: jeff, alan, linux-ide; +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 eb611b4..a651bdd 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -945,6 +945,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 (qc->dev->horkage & 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 2bd1d26..56b2187 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -329,6 +329,7 @@ enum {
ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */
ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */
ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */
+ ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */
};
enum hsm_task_states {
--
1.5.0.3
^ permalink raw reply related [flat|nested] 14+ messages in thread