aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-05-01 05:50:15 -0400
committerJeff Garzik <jeff@garzik.org>2007-05-11 18:09:18 -0400
commitf4d6d00466ef4879e4289f18c2f59210a06a7ada (patch)
tree60a0ec3c2872f1f21c2b546af3e04990b3bfa60b
parent1626aeb881236c8cb022b5e4ca594146a951d669 (diff)
libata: ignore EH scheduling during initialization
libata enables SCSI host during ATA host activation which happens after IRQ handler is registered and IRQ is enabled. All ATA ports are in frozen state when IRQ is enabled but frozen ports may raise limited number of IRQs after being frozen - IOW, ->freeze() is not responsible for clearing pending IRQs. During normal operation, the IRQ handler is responsible for clearing spurious IRQs on frozen ports and it usually doesn't require any extra code. Unfortunately, during host initialization, the IRQ handler can end up scheduling EH for a port whose SCSI host isn't initialized yet. This results in OOPS in the SCSI midlayer. This is relatively short window and scheduling EH for probing is the first thing libata does after initialization, so ignoring EH scheduling until initialization is complete solves the problem nicely. This problem was spotted by Berck E. Nash in the following thread. http://thread.gmane.org/gmane.linux.kernel/519412 Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Berck E. Nash <flyboy@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/libata-core.c2
-rw-r--r--drivers/ata/libata-eh.c3
-rw-r--r--include/linux/libata.h1
3 files changed, 6 insertions, 0 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 9cff5c506573..6ac4f32ddcc2 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5964,6 +5964,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
5964 if (!ap) 5964 if (!ap)
5965 return NULL; 5965 return NULL;
5966 5966
5967 ap->pflags |= ATA_PFLAG_INITIALIZING;
5967 ap->lock = &host->lock; 5968 ap->lock = &host->lock;
5968 ap->flags = ATA_FLAG_DISABLED; 5969 ap->flags = ATA_FLAG_DISABLED;
5969 ap->print_id = -1; 5970 ap->print_id = -1;
@@ -6332,6 +6333,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
6332 ehi->action |= ATA_EH_SOFTRESET; 6333 ehi->action |= ATA_EH_SOFTRESET;
6333 ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; 6334 ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
6334 6335
6336 ap->pflags &= ~ATA_PFLAG_INITIALIZING;
6335 ap->pflags |= ATA_PFLAG_LOADING; 6337 ap->pflags |= ATA_PFLAG_LOADING;
6336 ata_port_schedule_eh(ap); 6338 ata_port_schedule_eh(ap);
6337 6339
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 412d6049afa3..ee9bb534153a 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -551,6 +551,9 @@ void ata_port_schedule_eh(struct ata_port *ap)
551{ 551{
552 WARN_ON(!ap->ops->error_handler); 552 WARN_ON(!ap->ops->error_handler);
553 553
554 if (ap->pflags & ATA_PFLAG_INITIALIZING)
555 return;
556
554 ap->pflags |= ATA_PFLAG_EH_PENDING; 557 ap->pflags |= ATA_PFLAG_EH_PENDING;
555 scsi_schedule_eh(ap->scsi_host); 558 scsi_schedule_eh(ap->scsi_host);
556 559
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 95b74ba7dbf4..90abcdc3d4ef 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -190,6 +190,7 @@ enum {
190 ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */ 190 ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */
191 ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */ 191 ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */
192 ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */ 192 ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
193 ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */
193 194
194 ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */ 195 ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
195 ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ 196 ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */