aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-01-29 06:31:32 -0500
committerJeff Garzik <jgarzik@redhat.com>2009-02-02 23:03:17 -0500
commit99cf610aa4840d822cdc67d194b23b55010ca9bd (patch)
tree68bc3d6c1f13849731bb7b4b11414b4b0e5fbffb
parent9913ff8abf1c70a8d52560dc931e1901d025ad27 (diff)
libata: clear dev->ering in smarter way
dev->ering used to be cleared together with the rest of ata_device in ata_dev_init() which is called whenever a probing event occurs. dev->ering is about to be used to track probing failures so it needs to remain persistent over multiple porbing events. This patch achieves this by doing the following. * Instead of CLEAR_OFFSET, define CLEAR_BEGIN and CLEAR_END and only clear between BEGIN and END. ering is moved after END. The split of persistent area is to allow hotter items remain at the head. * ering is explicitly cleared on ata_dev_disable() and when device attach succeeds. So, ering is persistent throug a device's life time (unless explicitly cleared of course) and also through periods inbetween disablement of an attached device and successful detection of the next one. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/ata/libata-core.c4
-rw-r--r--drivers/ata/libata-eh.c7
-rw-r--r--include/linux/libata.h18
3 files changed, 19 insertions, 10 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index d006e5c4768c..564c03c4ebb3 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5404,8 +5404,8 @@ void ata_dev_init(struct ata_device *dev)
5404 dev->horkage = 0; 5404 dev->horkage = 0;
5405 spin_unlock_irqrestore(ap->lock, flags); 5405 spin_unlock_irqrestore(ap->lock, flags);
5406 5406
5407 memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0, 5407 memset((void *)dev + ATA_DEVICE_CLEAR_BEGIN, 0,
5408 sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET); 5408 ATA_DEVICE_CLEAR_END - ATA_DEVICE_CLEAR_BEGIN);
5409 dev->pio_mask = UINT_MAX; 5409 dev->pio_mask = UINT_MAX;
5410 dev->mwdma_mask = UINT_MAX; 5410 dev->mwdma_mask = UINT_MAX;
5411 dev->udma_mask = UINT_MAX; 5411 dev->udma_mask = UINT_MAX;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index aafe82bf5e2e..90092c1aae53 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1194,6 +1194,11 @@ void ata_dev_disable(struct ata_device *dev)
1194 ata_acpi_on_disable(dev); 1194 ata_acpi_on_disable(dev);
1195 ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); 1195 ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET);
1196 dev->class++; 1196 dev->class++;
1197
1198 /* From now till the next successful probe, ering is used to
1199 * track probe failures. Clear accumulated device error info.
1200 */
1201 ata_ering_clear(&dev->ering);
1197} 1202}
1198 1203
1199/** 1204/**
@@ -2765,6 +2770,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
2765 readid_flags, dev->id); 2770 readid_flags, dev->id);
2766 switch (rc) { 2771 switch (rc) {
2767 case 0: 2772 case 0:
2773 /* clear error info accumulated during probe */
2774 ata_ering_clear(&dev->ering);
2768 new_mask |= 1 << dev->devno; 2775 new_mask |= 1 << dev->devno;
2769 break; 2776 break;
2770 case -ENOENT: 2777 case -ENOENT:
diff --git a/include/linux/libata.h b/include/linux/libata.h
index bca3ba25f52a..9dcefee5843c 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -580,7 +580,7 @@ struct ata_device {
580 acpi_handle acpi_handle; 580 acpi_handle acpi_handle;
581 union acpi_object *gtf_cache; 581 union acpi_object *gtf_cache;
582#endif 582#endif
583 /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ 583 /* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
584 u64 n_sectors; /* size of device, if ATA */ 584 u64 n_sectors; /* size of device, if ATA */
585 unsigned int class; /* ATA_DEV_xxx */ 585 unsigned int class; /* ATA_DEV_xxx */
586 unsigned long unpark_deadline; 586 unsigned long unpark_deadline;
@@ -605,20 +605,22 @@ struct ata_device {
605 u16 heads; /* Number of heads */ 605 u16 heads; /* Number of heads */
606 u16 sectors; /* Number of sectors per track */ 606 u16 sectors; /* Number of sectors per track */
607 607
608 /* error history */
609 int spdn_cnt;
610 struct ata_ering ering;
611
612 union { 608 union {
613 u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ 609 u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
614 u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ 610 u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
615 }; 611 };
612
613 /* error history */
614 int spdn_cnt;
615 /* ering is CLEAR_END, read comment above CLEAR_END */
616 struct ata_ering ering;
616}; 617};
617 618
618/* Offset into struct ata_device. Fields above it are maintained 619/* Fields between ATA_DEVICE_CLEAR_BEGIN and ATA_DEVICE_CLEAR_END are
619 * acress device init. Fields below are zeroed. 620 * cleared to zero on ata_dev_init().
620 */ 621 */
621#define ATA_DEVICE_CLEAR_OFFSET offsetof(struct ata_device, n_sectors) 622#define ATA_DEVICE_CLEAR_BEGIN offsetof(struct ata_device, n_sectors)
623#define ATA_DEVICE_CLEAR_END offsetof(struct ata_device, ering)
622 624
623struct ata_eh_info { 625struct ata_eh_info {
624 struct ata_device *dev; /* offending device */ 626 struct ata_device *dev; /* offending device */