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>
This commit is contained in:
parent
9913ff8abf
commit
99cf610aa4
|
@ -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)
|
||||||
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,
|
||||||
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 {
|
||||||
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 {
|
||||||
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 */
|
||||||
|
|
Loading…
Reference in New Issue