aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/libata-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r--drivers/scsi/libata-core.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 9c97783462d..63857a90ac2 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -987,6 +987,12 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_lock_irqsave(&ap->host_set->lock, flags);
+ /* no internal command while frozen */
+ if (ap->flags & ATA_FLAG_FROZEN) {
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ return AC_ERR_SYSTEM;
+ }
+
/* initialize internal qc */
/* XXX: Tag 0 is used for drivers with legacy EH as some
@@ -2565,8 +2571,11 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
sata_scr_write(ap, SCR_ERROR, serror);
/* re-enable interrupts */
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
+ if (!ap->ops->error_handler) {
+ /* FIXME: hack. create a hook instead */
+ if (ap->ioaddr.ctl_addr)
+ ata_irq_on(ap);
+ }
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -2681,6 +2690,8 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
{
int rc = -EINVAL;
+ ata_eh_freeze_port(ap);
+
if (probeinit)
probeinit(ap);
@@ -2725,6 +2736,9 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
if (rc == 0) {
if (postreset)
postreset(ap, classes);
+
+ ata_eh_thaw_port(ap);
+
if (classes[0] == ATA_DEV_UNKNOWN)
rc = -ENODEV;
}
@@ -4039,6 +4053,10 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
struct ata_queued_cmd *qc = NULL;
unsigned int i;
+ /* no command while frozen */
+ if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+ return NULL;
+
/* the last tag is reserved for internal command. */
for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
if (!test_and_set_bit(i, &ap->qactive)) {
@@ -4953,6 +4971,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
ata_chk_status(ap);
host_set->ops->irq_clear(ap);
+ ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
count++;
}
@@ -5385,5 +5404,8 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
EXPORT_SYMBOL_GPL(ata_port_abort);
+EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
+EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);