Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev

* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  [libata] sata_promise: comment out duplicate PCI ID
  [PATCH] libata: improve EH action and EHI flag handling
  [PATCH] libata: fix eh_skip_recovery condition
  [PATCH] libata: fix autopsy ehc->i.action and ehc->i.dev handling
This commit is contained in:
Linus Torvalds 2006-07-28 22:47:44 -07:00
commit dc710afe95
3 changed files with 54 additions and 26 deletions

View File

@ -764,12 +764,27 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
unsigned int action) unsigned int action)
{ {
unsigned long flags; unsigned long flags;
struct ata_eh_info *ehi = &ap->eh_info;
struct ata_eh_context *ehc = &ap->eh_context;
spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
ata_eh_clear_action(dev, &ap->eh_info, action); /* Reset is represented by combination of actions and EHI
* flags. Suck in all related bits before clearing eh_info to
* avoid losing requested action.
*/
if (action & ATA_EH_RESET_MASK) {
ehc->i.action |= ehi->action & ATA_EH_RESET_MASK;
ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;
if (!(ap->eh_context.i.flags & ATA_EHI_QUIET)) /* make sure all reset actions are cleared & clear EHI flags */
action |= ATA_EH_RESET_MASK;
ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
ata_eh_clear_action(dev, ehi, action);
if (!(ehc->i.flags & ATA_EHI_QUIET))
ap->pflags |= ATA_PFLAG_RECOVERED; ap->pflags |= ATA_PFLAG_RECOVERED;
spin_unlock_irqrestore(ap->lock, flags); spin_unlock_irqrestore(ap->lock, flags);
@ -790,6 +805,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
unsigned int action) unsigned int action)
{ {
/* if reset is complete, clear all reset actions & reset modifier */
if (action & ATA_EH_RESET_MASK) {
action |= ATA_EH_RESET_MASK;
ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
ata_eh_clear_action(dev, &ap->eh_context.i, action); ata_eh_clear_action(dev, &ap->eh_context.i, action);
} }
@ -1276,8 +1297,6 @@ static int ata_eh_speed_down(struct ata_device *dev, int is_io,
static void ata_eh_autopsy(struct ata_port *ap) static void ata_eh_autopsy(struct ata_port *ap)
{ {
struct ata_eh_context *ehc = &ap->eh_context; struct ata_eh_context *ehc = &ap->eh_context;
unsigned int action = ehc->i.action;
struct ata_device *failed_dev = NULL;
unsigned int all_err_mask = 0; unsigned int all_err_mask = 0;
int tag, is_io = 0; int tag, is_io = 0;
u32 serror; u32 serror;
@ -1294,7 +1313,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
ehc->i.serror |= serror; ehc->i.serror |= serror;
ata_eh_analyze_serror(ap); ata_eh_analyze_serror(ap);
} else if (rc != -EOPNOTSUPP) } else if (rc != -EOPNOTSUPP)
action |= ATA_EH_HARDRESET; ehc->i.action |= ATA_EH_HARDRESET;
/* analyze NCQ failure */ /* analyze NCQ failure */
ata_eh_analyze_ncq_error(ap); ata_eh_analyze_ncq_error(ap);
@ -1315,7 +1334,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
qc->err_mask |= ehc->i.err_mask; qc->err_mask |= ehc->i.err_mask;
/* analyze TF */ /* analyze TF */
action |= ata_eh_analyze_tf(qc, &qc->result_tf); ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
/* DEV errors are probably spurious in case of ATA_BUS error */ /* DEV errors are probably spurious in case of ATA_BUS error */
if (qc->err_mask & AC_ERR_ATA_BUS) if (qc->err_mask & AC_ERR_ATA_BUS)
@ -1329,11 +1348,11 @@ static void ata_eh_autopsy(struct ata_port *ap)
/* SENSE_VALID trumps dev/unknown error and revalidation */ /* SENSE_VALID trumps dev/unknown error and revalidation */
if (qc->flags & ATA_QCFLAG_SENSE_VALID) { if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
action &= ~ATA_EH_REVALIDATE; ehc->i.action &= ~ATA_EH_REVALIDATE;
} }
/* accumulate error info */ /* accumulate error info */
failed_dev = qc->dev; ehc->i.dev = qc->dev;
all_err_mask |= qc->err_mask; all_err_mask |= qc->err_mask;
if (qc->flags & ATA_QCFLAG_IO) if (qc->flags & ATA_QCFLAG_IO)
is_io = 1; is_io = 1;
@ -1342,25 +1361,22 @@ static void ata_eh_autopsy(struct ata_port *ap)
/* enforce default EH actions */ /* enforce default EH actions */
if (ap->pflags & ATA_PFLAG_FROZEN || if (ap->pflags & ATA_PFLAG_FROZEN ||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
action |= ATA_EH_SOFTRESET; ehc->i.action |= ATA_EH_SOFTRESET;
else if (all_err_mask) else if (all_err_mask)
action |= ATA_EH_REVALIDATE; ehc->i.action |= ATA_EH_REVALIDATE;
/* if we have offending qcs and the associated failed device */ /* if we have offending qcs and the associated failed device */
if (failed_dev) { if (ehc->i.dev) {
/* speed down */ /* speed down */
action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io,
all_err_mask);
/* perform per-dev EH action only on the offending device */ /* perform per-dev EH action only on the offending device */
ehc->i.dev_action[failed_dev->devno] |= ehc->i.dev_action[ehc->i.dev->devno] |=
action & ATA_EH_PERDEV_MASK; ehc->i.action & ATA_EH_PERDEV_MASK;
action &= ~ATA_EH_PERDEV_MASK; ehc->i.action &= ~ATA_EH_PERDEV_MASK;
} }
/* record autopsy result */
ehc->i.dev = failed_dev;
ehc->i.action |= action;
DPRINTK("EXIT\n"); DPRINTK("EXIT\n");
} }
@ -1483,6 +1499,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_reset_fn_t reset; ata_reset_fn_t reset;
int i, did_followup_srst, rc; int i, did_followup_srst, rc;
/* about to reset */
ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
/* Determine which reset to use and record in ehc->i.action. /* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it. * prereset() may examine and modify it.
*/ */
@ -1531,8 +1550,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_INFO, "%s resetting port\n", ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
reset == softreset ? "soft" : "hard"); reset == softreset ? "soft" : "hard");
/* reset */ /* mark that this EH session started with reset */
ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
ehc->i.flags |= ATA_EHI_DID_RESET; ehc->i.flags |= ATA_EHI_DID_RESET;
rc = ata_do_reset(ap, reset, classes); rc = ata_do_reset(ap, reset, classes);
@ -1595,7 +1613,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
postreset(ap, classes); postreset(ap, classes);
/* reset successful, schedule revalidation */ /* reset successful, schedule revalidation */
ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE; ehc->i.action |= ATA_EH_REVALIDATE;
} }
@ -1848,15 +1866,16 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
for (i = 0; i < ata_port_max_devices(ap); i++) { for (i = 0; i < ata_port_max_devices(ap); i++) {
struct ata_device *dev = &ap->device[i]; struct ata_device *dev = &ap->device[i];
if (ata_dev_absent(dev) || ata_dev_ready(dev)) if (!(dev->flags & ATA_DFLAG_SUSPENDED))
break; break;
} }
if (i == ata_port_max_devices(ap)) if (i == ata_port_max_devices(ap))
return 1; return 1;
/* always thaw frozen port and recover failed devices */ /* thaw frozen port, resume link and recover failed devices */
if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap)) if ((ap->pflags & ATA_PFLAG_FROZEN) ||
(ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
return 0; return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */ /* skip if class codes for all vacant slots are ATA_DEV_NONE */

View File

@ -269,8 +269,15 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
{ PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20619 }, board_20619 },
/* TODO: remove all associated board_20771 code, as it completely
* duplicates board_2037x code, unless reason for separation can be
* divined.
*/
#if 0
{ PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20771 }, board_20771 },
#endif
{ } /* terminate list */ { } /* terminate list */
}; };

View File

@ -265,12 +265,14 @@ enum {
/* ata_eh_info->flags */ /* ata_eh_info->flags */
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */ ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */
ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
ATA_EHI_QUIET = (1 << 3), /* be quiet */ ATA_EHI_QUIET = (1 << 3), /* be quiet */
ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,
/* max repeat if error condition is still set after ->error_handler */ /* max repeat if error condition is still set after ->error_handler */
ATA_EH_MAX_REPEAT = 5, ATA_EH_MAX_REPEAT = 5,