diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
| -rw-r--r-- | drivers/ata/libata-eh.c | 64 | 
1 files changed, 49 insertions, 15 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 159ba6ba19eb..5686353e442c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -147,6 +147,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {  	  .timeouts = ata_eh_other_timeouts, },  	{ .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),  	  .timeouts = ata_eh_flush_timeouts }, +	{ .commands = CMDS(ATA_CMD_VERIFY), +	  .timeouts = ata_eh_reset_timeouts },  };  #undef CMDS @@ -498,7 +500,19 @@ static void ata_eh_unload(struct ata_port *ap)  	struct ata_device *dev;  	unsigned long flags; -	/* Restore SControl IPM and SPD for the next driver and +	/* +	 * Unless we are restarting, transition all enabled devices to +	 * standby power mode. +	 */ +	if (system_state != SYSTEM_RESTART) { +		ata_for_each_link(link, ap, PMP_FIRST) { +			ata_for_each_dev(dev, link, ENABLED) +				ata_dev_power_set_standby(dev); +		} +	} + +	/* +	 * Restore SControl IPM and SPD for the next driver and  	 * disable attached devices.  	 */  	ata_for_each_link(link, ap, PMP_FIRST) { @@ -684,6 +698,10 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)  			ehc->saved_xfer_mode[devno] = dev->xfer_mode;  			if (ata_ncq_enabled(dev))  				ehc->saved_ncq_enabled |= 1 << devno; + +			/* If we are resuming, wake up the device */ +			if (ap->pflags & ATA_PFLAG_RESUMING) +				ehc->i.dev_action[devno] |= ATA_EH_SET_ACTIVE;  		}  	} @@ -743,6 +761,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)  	/* clean up */  	spin_lock_irqsave(ap->lock, flags); +	ap->pflags &= ~ATA_PFLAG_RESUMING; +  	if (ap->pflags & ATA_PFLAG_LOADING)  		ap->pflags &= ~ATA_PFLAG_LOADING;  	else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) && @@ -1218,6 +1238,13 @@ void ata_eh_detach_dev(struct ata_device *dev)  	struct ata_eh_context *ehc = &link->eh_context;  	unsigned long flags; +	/* +	 * If the device is still enabled, transition it to standby power mode +	 * (i.e. spin down HDDs). +	 */ +	if (ata_dev_enabled(dev)) +		ata_dev_power_set_standby(dev); +  	ata_dev_disable(dev);  	spin_lock_irqsave(ap->lock, flags); @@ -2305,7 +2332,7 @@ static void ata_eh_link_report(struct ata_link *link)  	struct ata_eh_context *ehc = &link->eh_context;  	struct ata_queued_cmd *qc;  	const char *frozen, *desc; -	char tries_buf[6] = ""; +	char tries_buf[16] = "";  	int tag, nr_failed = 0;  	if (ehc->i.flags & ATA_EHI_QUIET) @@ -2796,23 +2823,13 @@ int ata_eh_reset(struct ata_link *link, int classify,  		}  	} -	/* -	 * Some controllers can't be frozen very well and may set spurious -	 * error conditions during reset.  Clear accumulated error -	 * information and re-thaw the port if frozen.  As reset is the -	 * final recovery action and we cross check link onlineness against -	 * device classification later, no hotplug event is lost by this. -	 */ +	/* clear cached SError */  	spin_lock_irqsave(link->ap->lock, flags); -	memset(&link->eh_info, 0, sizeof(link->eh_info)); +	link->eh_info.serror = 0;  	if (slave) -		memset(&slave->eh_info, 0, sizeof(link->eh_info)); -	ap->pflags &= ~ATA_PFLAG_EH_PENDING; +		slave->eh_info.serror = 0;  	spin_unlock_irqrestore(link->ap->lock, flags); -	if (ata_port_is_frozen(ap)) -		ata_eh_thaw_port(ap); -  	/*  	 * Make sure onlineness and classification result correspond.  	 * Hotplug could have happened during reset and some @@ -3026,6 +3043,15 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,  		if (ehc->i.flags & ATA_EHI_DID_RESET)  			readid_flags |= ATA_READID_POSTRESET; +		/* +		 * When resuming, before executing any command, make sure to +		 * transition the device to the active power mode. +		 */ +		if ((action & ATA_EH_SET_ACTIVE) && ata_dev_enabled(dev)) { +			ata_dev_power_set_active(dev); +			ata_eh_done(link, dev, ATA_EH_SET_ACTIVE); +		} +  		if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {  			WARN_ON(dev->class == ATA_DEV_PMP); @@ -3999,6 +4025,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)  	unsigned long flags;  	int rc = 0;  	struct ata_device *dev; +	struct ata_link *link;  	/* are we suspending? */  	spin_lock_irqsave(ap->lock, flags); @@ -4011,6 +4038,12 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)  	WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); +	/* Set all devices attached to the port in standby mode */ +	ata_for_each_link(link, ap, HOST_FIRST) { +		ata_for_each_dev(dev, link, ENABLED) +			ata_dev_power_set_standby(dev); +	} +  	/*  	 * If we have a ZPODD attached, check its zero  	 * power ready status before the port is frozen. @@ -4093,6 +4126,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)  	/* update the flags */  	spin_lock_irqsave(ap->lock, flags);  	ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); +	ap->pflags |= ATA_PFLAG_RESUMING;  	spin_unlock_irqrestore(ap->lock, flags);  }  #endif /* CONFIG_PM */  | 
