Commit 99cf610a authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

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: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 9913ff8a
...@@ -5404,8 +5404,8 @@ void ata_dev_init(struct ata_device *dev) ...@@ -5404,8 +5404,8 @@ void ata_dev_init(struct ata_device *dev)
dev->horkage = 0; dev->horkage = 0;
spin_unlock_irqrestore(ap->lock, flags); spin_unlock_irqrestore(ap->lock, flags);
memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0, memset((void *)dev + ATA_DEVICE_CLEAR_BEGIN, 0,
sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET); ATA_DEVICE_CLEAR_END - ATA_DEVICE_CLEAR_BEGIN);
dev->pio_mask = UINT_MAX; dev->pio_mask = UINT_MAX;
dev->mwdma_mask = UINT_MAX; dev->mwdma_mask = UINT_MAX;
dev->udma_mask = UINT_MAX; dev->udma_mask = UINT_MAX;
......
...@@ -1194,6 +1194,11 @@ void ata_dev_disable(struct ata_device *dev) ...@@ -1194,6 +1194,11 @@ void ata_dev_disable(struct ata_device *dev)
ata_acpi_on_disable(dev); ata_acpi_on_disable(dev);
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET);
dev->class++; dev->class++;
/* From now till the next successful probe, ering is used to
* track probe failures. Clear accumulated device error info.
*/
ata_ering_clear(&dev->ering);
} }
/** /**
...@@ -2765,6 +2770,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, ...@@ -2765,6 +2770,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
readid_flags, dev->id); readid_flags, dev->id);
switch (rc) { switch (rc) {
case 0: case 0:
/* clear error info accumulated during probe */
ata_ering_clear(&dev->ering);
new_mask |= 1 << dev->devno; new_mask |= 1 << dev->devno;
break; break;
case -ENOENT: case -ENOENT:
......
...@@ -580,7 +580,7 @@ struct ata_device { ...@@ -580,7 +580,7 @@ struct ata_device {
acpi_handle acpi_handle; acpi_handle acpi_handle;
union acpi_object *gtf_cache; union acpi_object *gtf_cache;
#endif #endif
/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ /* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
u64 n_sectors; /* size of device, if ATA */ u64 n_sectors; /* size of device, if ATA */
unsigned int class; /* ATA_DEV_xxx */ unsigned int class; /* ATA_DEV_xxx */
unsigned long unpark_deadline; unsigned long unpark_deadline;
...@@ -605,20 +605,22 @@ struct ata_device { ...@@ -605,20 +605,22 @@ struct ata_device {
u16 heads; /* Number of heads */ u16 heads; /* Number of heads */
u16 sectors; /* Number of sectors per track */ u16 sectors; /* Number of sectors per track */
/* error history */
int spdn_cnt;
struct ata_ering ering;
union { union {
u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
}; };
/* error history */
int spdn_cnt;
/* ering is CLEAR_END, read comment above CLEAR_END */
struct ata_ering ering;
}; };
/* Offset into struct ata_device. Fields above it are maintained /* Fields between ATA_DEVICE_CLEAR_BEGIN and ATA_DEVICE_CLEAR_END are
* acress device init. Fields below are zeroed. * cleared to zero on ata_dev_init().
*/ */
#define ATA_DEVICE_CLEAR_OFFSET offsetof(struct ata_device, n_sectors) #define ATA_DEVICE_CLEAR_BEGIN offsetof(struct ata_device, n_sectors)
#define ATA_DEVICE_CLEAR_END offsetof(struct ata_device, ering)
struct ata_eh_info { struct ata_eh_info {
struct ata_device *dev; /* offending device */ struct ata_device *dev; /* offending device */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment