Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc710afe authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 4da3dcf3 ab3b3fd3
Loading
Loading
Loading
Loading
+44 −25
Original line number Original line Diff line number Diff line
@@ -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;

		/* 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 (!(ap->eh_context.i.flags & ATA_EHI_QUIET))
	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 */
+7 −0
Original line number Original line Diff line number Diff line
@@ -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 */
};
};


+3 −1
Original line number Original line Diff line number Diff line
@@ -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,