diff options
| author | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:19 -0400 |
|---|---|---|
| committer | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:19 -0400 |
| commit | 0c247c559cd70f85ba9f0764ce13ae00e20fcad8 (patch) | |
| tree | 9b0d00b300ad9178438b9c7feba95ed62f540c1a | |
| parent | 9be1e979f2e1e57a091a658fa88dac266f9fd6fe (diff) | |
[PATCH] libata-eh: implement dev->ering
This patch implements ata_ering and uses it to define dev->ering.
ata_ering is a ring buffer which records libata errors - whether a
command was for normar IO request, err_mask and timestamp. Errors are
recorded per-device in dev->ering. This will be used by EH to
determine recovery actions.
Signed-off-by: Tejun Heo <htejun@gmail.com>
| -rw-r--r-- | drivers/scsi/libata-eh.c | 45 | ||||
| -rw-r--r-- | include/linux/libata.h | 17 |
2 files changed, 62 insertions, 0 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 0803231f6577..71ad18b7cff6 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
| @@ -46,6 +46,51 @@ | |||
| 46 | 46 | ||
| 47 | static void __ata_port_freeze(struct ata_port *ap); | 47 | static void __ata_port_freeze(struct ata_port *ap); |
| 48 | 48 | ||
| 49 | static void ata_ering_record(struct ata_ering *ering, int is_io, | ||
| 50 | unsigned int err_mask) | ||
| 51 | { | ||
| 52 | struct ata_ering_entry *ent; | ||
| 53 | |||
| 54 | WARN_ON(!err_mask); | ||
| 55 | |||
| 56 | ering->cursor++; | ||
| 57 | ering->cursor %= ATA_ERING_SIZE; | ||
| 58 | |||
| 59 | ent = &ering->ring[ering->cursor]; | ||
| 60 | ent->is_io = is_io; | ||
| 61 | ent->err_mask = err_mask; | ||
| 62 | ent->timestamp = get_jiffies_64(); | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering) | ||
| 66 | { | ||
| 67 | struct ata_ering_entry *ent = &ering->ring[ering->cursor]; | ||
| 68 | if (!ent->err_mask) | ||
| 69 | return NULL; | ||
| 70 | return ent; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int ata_ering_map(struct ata_ering *ering, | ||
| 74 | int (*map_fn)(struct ata_ering_entry *, void *), | ||
| 75 | void *arg) | ||
| 76 | { | ||
| 77 | int idx, rc = 0; | ||
| 78 | struct ata_ering_entry *ent; | ||
| 79 | |||
| 80 | idx = ering->cursor; | ||
| 81 | do { | ||
| 82 | ent = &ering->ring[idx]; | ||
| 83 | if (!ent->err_mask) | ||
| 84 | break; | ||
| 85 | rc = map_fn(ent, arg); | ||
| 86 | if (rc) | ||
| 87 | break; | ||
| 88 | idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE; | ||
| 89 | } while (idx != ering->cursor); | ||
| 90 | |||
| 91 | return rc; | ||
| 92 | } | ||
| 93 | |||
| 49 | /** | 94 | /** |
| 50 | * ata_scsi_timed_out - SCSI layer time out callback | 95 | * ata_scsi_timed_out - SCSI layer time out callback |
| 51 | * @cmd: timed out SCSI command | 96 | * @cmd: timed out SCSI command |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 6fe5ed8eabf5..f5cea13599c3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -226,6 +226,9 @@ enum { | |||
| 226 | ATA_PORT_PRIMARY = (1 << 0), | 226 | ATA_PORT_PRIMARY = (1 << 0), |
| 227 | ATA_PORT_SECONDARY = (1 << 1), | 227 | ATA_PORT_SECONDARY = (1 << 1), |
| 228 | 228 | ||
| 229 | /* ering size */ | ||
| 230 | ATA_ERING_SIZE = 32, | ||
| 231 | |||
| 229 | /* reset / recovery action types */ | 232 | /* reset / recovery action types */ |
| 230 | ATA_EH_REVALIDATE = (1 << 0), | 233 | ATA_EH_REVALIDATE = (1 << 0), |
| 231 | ATA_EH_SOFTRESET = (1 << 1), | 234 | ATA_EH_SOFTRESET = (1 << 1), |
| @@ -375,6 +378,17 @@ struct ata_host_stats { | |||
| 375 | unsigned long rw_reqbuf; | 378 | unsigned long rw_reqbuf; |
| 376 | }; | 379 | }; |
| 377 | 380 | ||
| 381 | struct ata_ering_entry { | ||
| 382 | int is_io; | ||
| 383 | unsigned int err_mask; | ||
| 384 | u64 timestamp; | ||
| 385 | }; | ||
| 386 | |||
| 387 | struct ata_ering { | ||
| 388 | int cursor; | ||
| 389 | struct ata_ering_entry ring[ATA_ERING_SIZE]; | ||
| 390 | }; | ||
| 391 | |||
| 378 | struct ata_device { | 392 | struct ata_device { |
| 379 | struct ata_port *ap; | 393 | struct ata_port *ap; |
| 380 | u64 n_sectors; /* size of device, if ATA */ | 394 | u64 n_sectors; /* size of device, if ATA */ |
| @@ -401,6 +415,9 @@ struct ata_device { | |||
| 401 | u16 cylinders; /* Number of cylinders */ | 415 | u16 cylinders; /* Number of cylinders */ |
| 402 | u16 heads; /* Number of heads */ | 416 | u16 heads; /* Number of heads */ |
| 403 | u16 sectors; /* Number of sectors per track */ | 417 | u16 sectors; /* Number of sectors per track */ |
| 418 | |||
| 419 | /* error history */ | ||
| 420 | struct ata_ering ering; | ||
| 404 | }; | 421 | }; |
| 405 | 422 | ||
| 406 | struct ata_port { | 423 | struct ata_port { |
