aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2008-05-19 13:17:54 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-07-14 15:59:32 -0400
commit87fbc5a060faf2394bee88a93519f9b9d434727c (patch)
tree6f90cacb1471e64051473c4e1e664b2dea8603e0 /drivers/ata/libata-eh.c
parentd8af0eb6046c56e7238171ca420622541db24926 (diff)
libata: improve EH internal command timeout handling
ATA_TMOUT_INTERNAL which was 30secs were used for all internal commands which is way too long when something goes wrong. This patch implements command type based stepped timeouts. Different command types can use different timeouts and each command type can use different timeout values after timeouts. ie. the initial timeout is set to a value which should cover most of the cases but not too long so that run away cases don't delay things too much. After the first try times out, the second try can use longer timeout and if that one times out too, it can go for full 30sec timeout. IDENTIFYs use 5s - 10s - 30s timeout and all other commands use 5s - 10s timeouts. This patch significantly cuts down the needed time to handle failure cases while still allowing libata to work with nut job devices through retries. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c121
1 files changed, 120 insertions, 1 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 83d1451fa714..d5f03a6e3334 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -67,6 +67,8 @@ enum {
67 ATA_ECAT_DUBIOUS_UNK_DEV = 7, 67 ATA_ECAT_DUBIOUS_UNK_DEV = 7,
68 ATA_ECAT_NR = 8, 68 ATA_ECAT_NR = 8,
69 69
70 ATA_EH_CMD_DFL_TIMEOUT = 5000,
71
70 /* always put at least this amount of time between resets */ 72 /* always put at least this amount of time between resets */
71 ATA_EH_RESET_COOL_DOWN = 5000, 73 ATA_EH_RESET_COOL_DOWN = 5000,
72 74
@@ -93,6 +95,53 @@ static const unsigned long ata_eh_reset_timeouts[] = {
93 ULONG_MAX, /* > 1 min has elapsed, give up */ 95 ULONG_MAX, /* > 1 min has elapsed, give up */
94}; 96};
95 97
98static const unsigned long ata_eh_identify_timeouts[] = {
99 5000, /* covers > 99% of successes and not too boring on failures */
100 10000, /* combined time till here is enough even for media access */
101 30000, /* for true idiots */
102 ULONG_MAX,
103};
104
105static const unsigned long ata_eh_other_timeouts[] = {
106 5000, /* same rationale as identify timeout */
107 10000, /* ditto */
108 /* but no merciful 30sec for other commands, it just isn't worth it */
109 ULONG_MAX,
110};
111
112struct ata_eh_cmd_timeout_ent {
113 const u8 *commands;
114 const unsigned long *timeouts;
115};
116
117/* The following table determines timeouts to use for EH internal
118 * commands. Each table entry is a command class and matches the
119 * commands the entry applies to and the timeout table to use.
120 *
121 * On the retry after a command timed out, the next timeout value from
122 * the table is used. If the table doesn't contain further entries,
123 * the last value is used.
124 *
125 * ehc->cmd_timeout_idx keeps track of which timeout to use per
126 * command class, so if SET_FEATURES times out on the first try, the
127 * next try will use the second timeout value only for that class.
128 */
129#define CMDS(cmds...) (const u8 []){ cmds, 0 }
130static const struct ata_eh_cmd_timeout_ent
131ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
132 { .commands = CMDS(ATA_CMD_ID_ATA, ATA_CMD_ID_ATAPI),
133 .timeouts = ata_eh_identify_timeouts, },
134 { .commands = CMDS(ATA_CMD_READ_NATIVE_MAX, ATA_CMD_READ_NATIVE_MAX_EXT),
135 .timeouts = ata_eh_other_timeouts, },
136 { .commands = CMDS(ATA_CMD_SET_MAX, ATA_CMD_SET_MAX_EXT),
137 .timeouts = ata_eh_other_timeouts, },
138 { .commands = CMDS(ATA_CMD_SET_FEATURES),
139 .timeouts = ata_eh_other_timeouts, },
140 { .commands = CMDS(ATA_CMD_INIT_DEV_PARAMS),
141 .timeouts = ata_eh_other_timeouts, },
142};
143#undef CMDS
144
96static void __ata_port_freeze(struct ata_port *ap); 145static void __ata_port_freeze(struct ata_port *ap);
97#ifdef CONFIG_PM 146#ifdef CONFIG_PM
98static void ata_eh_handle_port_suspend(struct ata_port *ap); 147static void ata_eh_handle_port_suspend(struct ata_port *ap);
@@ -238,6 +287,73 @@ void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
238 287
239#endif /* CONFIG_PCI */ 288#endif /* CONFIG_PCI */
240 289
290static int ata_lookup_timeout_table(u8 cmd)
291{
292 int i;
293
294 for (i = 0; i < ATA_EH_CMD_TIMEOUT_TABLE_SIZE; i++) {
295 const u8 *cur;
296
297 for (cur = ata_eh_cmd_timeout_table[i].commands; *cur; cur++)
298 if (*cur == cmd)
299 return i;
300 }
301
302 return -1;
303}
304
305/**
306 * ata_internal_cmd_timeout - determine timeout for an internal command
307 * @dev: target device
308 * @cmd: internal command to be issued
309 *
310 * Determine timeout for internal command @cmd for @dev.
311 *
312 * LOCKING:
313 * EH context.
314 *
315 * RETURNS:
316 * Determined timeout.
317 */
318unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd)
319{
320 struct ata_eh_context *ehc = &dev->link->eh_context;
321 int ent = ata_lookup_timeout_table(cmd);
322 int idx;
323
324 if (ent < 0)
325 return ATA_EH_CMD_DFL_TIMEOUT;
326
327 idx = ehc->cmd_timeout_idx[dev->devno][ent];
328 return ata_eh_cmd_timeout_table[ent].timeouts[idx];
329}
330
331/**
332 * ata_internal_cmd_timed_out - notification for internal command timeout
333 * @dev: target device
334 * @cmd: internal command which timed out
335 *
336 * Notify EH that internal command @cmd for @dev timed out. This
337 * function should be called only for commands whose timeouts are
338 * determined using ata_internal_cmd_timeout().
339 *
340 * LOCKING:
341 * EH context.
342 */
343void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd)
344{
345 struct ata_eh_context *ehc = &dev->link->eh_context;
346 int ent = ata_lookup_timeout_table(cmd);
347 int idx;
348
349 if (ent < 0)
350 return;
351
352 idx = ehc->cmd_timeout_idx[dev->devno][ent];
353 if (ata_eh_cmd_timeout_table[ent].timeouts[idx + 1] != ULONG_MAX)
354 ehc->cmd_timeout_idx[dev->devno][ent]++;
355}
356
241static void ata_ering_record(struct ata_ering *ering, unsigned int eflags, 357static void ata_ering_record(struct ata_ering *ering, unsigned int eflags,
242 unsigned int err_mask) 358 unsigned int err_mask)
243{ 359{
@@ -2600,8 +2716,11 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
2600 ata_eh_detach_dev(dev); 2716 ata_eh_detach_dev(dev);
2601 2717
2602 /* schedule probe if necessary */ 2718 /* schedule probe if necessary */
2603 if (ata_eh_schedule_probe(dev)) 2719 if (ata_eh_schedule_probe(dev)) {
2604 ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; 2720 ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
2721 memset(ehc->cmd_timeout_idx[dev->devno], 0,
2722 sizeof(ehc->cmd_timeout_idx[dev->devno]));
2723 }
2605 2724
2606 return 1; 2725 return 1;
2607 } else { 2726 } else {