aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-15 07:58:19 -0400
committerTejun Heo <htejun@gmail.com>2006-05-15 07:58:19 -0400
commit0c247c559cd70f85ba9f0764ce13ae00e20fcad8 (patch)
tree9b0d00b300ad9178438b9c7feba95ed62f540c1a
parent9be1e979f2e1e57a091a658fa88dac266f9fd6fe (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.c45
-rw-r--r--include/linux/libata.h17
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
47static void __ata_port_freeze(struct ata_port *ap); 47static void __ata_port_freeze(struct ata_port *ap);
48 48
49static 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
65static 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
73static 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
381struct ata_ering_entry {
382 int is_io;
383 unsigned int err_mask;
384 u64 timestamp;
385};
386
387struct ata_ering {
388 int cursor;
389 struct ata_ering_entry ring[ATA_ERING_SIZE];
390};
391
378struct ata_device { 392struct 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
406struct ata_port { 423struct ata_port {