Skip to content

Commit

Permalink
libata: ignore EH scheduling during initialization
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed May 11, 2007
1 parent 1626aeb commit f4d6d00
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 0 deletions.
2 changes: 2 additions & 0 deletions drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5964,6 +5964,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
if (!ap)
return NULL;

ap->pflags |= ATA_PFLAG_INITIALIZING;
ap->lock = &host->lock;
ap->flags = ATA_FLAG_DISABLED;
ap->print_id = -1;
Expand Down Expand Up @@ -6332,6 +6333,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
ehi->action |= ATA_EH_SOFTRESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;

ap->pflags &= ~ATA_PFLAG_INITIALIZING;
ap->pflags |= ATA_PFLAG_LOADING;
ata_port_schedule_eh(ap);

Expand Down
3 changes: 3 additions & 0 deletions drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,9 @@ void ata_port_schedule_eh(struct ata_port *ap)
{
WARN_ON(!ap->ops->error_handler);

if (ap->pflags & ATA_PFLAG_INITIALIZING)
return;

ap->pflags |= ATA_PFLAG_EH_PENDING;
scsi_schedule_eh(ap->scsi_host);

Expand Down
1 change: 1 addition & 0 deletions include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ enum {
ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */
ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */
ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */

ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
Expand Down

0 comments on commit f4d6d00

Please sign in to comment.