|
@@ -491,6 +491,31 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void ata_eh_unload(struct ata_port *ap)
|
|
|
+{
|
|
|
+ struct ata_link *link;
|
|
|
+ struct ata_device *dev;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ /* Restore SControl IPM and SPD for the next driver and
|
|
|
+ * disable attached devices.
|
|
|
+ */
|
|
|
+ ata_for_each_link(link, ap, PMP_FIRST) {
|
|
|
+ sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
|
|
|
+ ata_for_each_dev(dev, link, ALL)
|
|
|
+ ata_dev_disable(dev);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* freeze and set UNLOADED */
|
|
|
+ spin_lock_irqsave(ap->lock, flags);
|
|
|
+
|
|
|
+ ata_port_freeze(ap); /* won't be thawed */
|
|
|
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING; /* clear pending from freeze */
|
|
|
+ ap->pflags |= ATA_PFLAG_UNLOADED;
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(ap->lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ata_scsi_error - SCSI layer error handler callback
|
|
|
* @host: SCSI host on which error occurred
|
|
@@ -618,8 +643,13 @@ void ata_scsi_error(struct Scsi_Host *host)
|
|
|
/* invoke EH, skip if unloading or suspended */
|
|
|
if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
|
|
|
ap->ops->error_handler(ap);
|
|
|
- else
|
|
|
+ else {
|
|
|
+ /* if unloading, commence suicide */
|
|
|
+ if ((ap->pflags & ATA_PFLAG_UNLOADING) &&
|
|
|
+ !(ap->pflags & ATA_PFLAG_UNLOADED))
|
|
|
+ ata_eh_unload(ap);
|
|
|
ata_eh_finish(ap);
|
|
|
+ }
|
|
|
|
|
|
/* process port suspend request */
|
|
|
ata_eh_handle_port_suspend(ap);
|