diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-08-25 22:01:20 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-25 22:01:20 -0400 |
commit | b8f6153ee421014f42b620238f4203a4106db309 (patch) | |
tree | ebc9eac4517325be0a91a4e2b2cb38f08d36812e /drivers | |
parent | 617e44fdfd7ee3d53388ab295d9411b826437ce9 (diff) |
libata: fix EH locking
Wrap ata_qc_complete() calls in EH context in spinlocks, to prevent
races (mainly in ATAPI code paths).
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/ahci.c | 7 | ||||
-rw-r--r-- | drivers/scsi/libata-core.c | 14 | ||||
-rw-r--r-- | drivers/scsi/sata_promise.c | 5 | ||||
-rw-r--r-- | drivers/scsi/sata_sx4.c | 5 |
4 files changed, 28 insertions, 3 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 348493982b56..841f4e2cfe08 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -586,12 +586,16 @@ static void ahci_intr_error(struct ata_port *ap, u32 irq_stat) | |||
586 | 586 | ||
587 | static void ahci_eng_timeout(struct ata_port *ap) | 587 | static void ahci_eng_timeout(struct ata_port *ap) |
588 | { | 588 | { |
589 | void *mmio = ap->host_set->mmio_base; | 589 | struct ata_host_set *host_set = ap->host_set; |
590 | void *mmio = host_set->mmio_base; | ||
590 | void *port_mmio = ahci_port_base(mmio, ap->port_no); | 591 | void *port_mmio = ahci_port_base(mmio, ap->port_no); |
591 | struct ata_queued_cmd *qc; | 592 | struct ata_queued_cmd *qc; |
593 | unsigned long flags; | ||
592 | 594 | ||
593 | DPRINTK("ENTER\n"); | 595 | DPRINTK("ENTER\n"); |
594 | 596 | ||
597 | spin_lock_irqsave(&host_set->lock, flags); | ||
598 | |||
595 | ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT)); | 599 | ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT)); |
596 | 600 | ||
597 | qc = ata_qc_from_tag(ap, ap->active_tag); | 601 | qc = ata_qc_from_tag(ap, ap->active_tag); |
@@ -609,6 +613,7 @@ static void ahci_eng_timeout(struct ata_port *ap) | |||
609 | ata_qc_complete(qc, ATA_ERR); | 613 | ata_qc_complete(qc, ATA_ERR); |
610 | } | 614 | } |
611 | 615 | ||
616 | spin_unlock_irqrestore(&host_set->lock, flags); | ||
612 | } | 617 | } |
613 | 618 | ||
614 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) | 619 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) |
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 157a3e914cb7..ec7bff73ae18 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -2388,12 +2388,13 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) | |||
2388 | void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) | 2388 | void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) |
2389 | { | 2389 | { |
2390 | struct ata_port *ap = qc->ap; | 2390 | struct ata_port *ap = qc->ap; |
2391 | unsigned long flags; | ||
2391 | 2392 | ||
2392 | spin_lock_irq(&ap->host_set->lock); | 2393 | spin_lock_irqsave(&ap->host_set->lock, flags); |
2393 | ap->flags &= ~ATA_FLAG_NOINTR; | 2394 | ap->flags &= ~ATA_FLAG_NOINTR; |
2394 | ata_irq_on(ap); | 2395 | ata_irq_on(ap); |
2395 | ata_qc_complete(qc, drv_stat); | 2396 | ata_qc_complete(qc, drv_stat); |
2396 | spin_unlock_irq(&ap->host_set->lock); | 2397 | spin_unlock_irqrestore(&ap->host_set->lock, flags); |
2397 | } | 2398 | } |
2398 | 2399 | ||
2399 | /** | 2400 | /** |
@@ -2973,8 +2974,10 @@ static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, | |||
2973 | static void ata_qc_timeout(struct ata_queued_cmd *qc) | 2974 | static void ata_qc_timeout(struct ata_queued_cmd *qc) |
2974 | { | 2975 | { |
2975 | struct ata_port *ap = qc->ap; | 2976 | struct ata_port *ap = qc->ap; |
2977 | struct ata_host_set *host_set = ap->host_set; | ||
2976 | struct ata_device *dev = qc->dev; | 2978 | struct ata_device *dev = qc->dev; |
2977 | u8 host_stat = 0, drv_stat; | 2979 | u8 host_stat = 0, drv_stat; |
2980 | unsigned long flags; | ||
2978 | 2981 | ||
2979 | DPRINTK("ENTER\n"); | 2982 | DPRINTK("ENTER\n"); |
2980 | 2983 | ||
@@ -2985,7 +2988,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) | |||
2985 | if (!(cmd->eh_eflags & SCSI_EH_CANCEL_CMD)) { | 2988 | if (!(cmd->eh_eflags & SCSI_EH_CANCEL_CMD)) { |
2986 | 2989 | ||
2987 | /* finish completing original command */ | 2990 | /* finish completing original command */ |
2991 | spin_lock_irqsave(&host_set->lock, flags); | ||
2988 | __ata_qc_complete(qc); | 2992 | __ata_qc_complete(qc); |
2993 | spin_unlock_irqrestore(&host_set->lock, flags); | ||
2989 | 2994 | ||
2990 | atapi_request_sense(ap, dev, cmd); | 2995 | atapi_request_sense(ap, dev, cmd); |
2991 | 2996 | ||
@@ -2996,6 +3001,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) | |||
2996 | } | 3001 | } |
2997 | } | 3002 | } |
2998 | 3003 | ||
3004 | spin_lock_irqsave(&host_set->lock, flags); | ||
3005 | |||
2999 | /* hack alert! We cannot use the supplied completion | 3006 | /* hack alert! We cannot use the supplied completion |
3000 | * function from inside the ->eh_strategy_handler() thread. | 3007 | * function from inside the ->eh_strategy_handler() thread. |
3001 | * libata is the only user of ->eh_strategy_handler() in | 3008 | * libata is the only user of ->eh_strategy_handler() in |
@@ -3029,6 +3036,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) | |||
3029 | ata_qc_complete(qc, drv_stat); | 3036 | ata_qc_complete(qc, drv_stat); |
3030 | break; | 3037 | break; |
3031 | } | 3038 | } |
3039 | |||
3040 | spin_unlock_irqrestore(&host_set->lock, flags); | ||
3041 | |||
3032 | out: | 3042 | out: |
3033 | DPRINTK("EXIT\n"); | 3043 | DPRINTK("EXIT\n"); |
3034 | } | 3044 | } |
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index defcc1fb3f16..b8dc49fed769 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c | |||
@@ -325,11 +325,15 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) | |||
325 | 325 | ||
326 | static void pdc_eng_timeout(struct ata_port *ap) | 326 | static void pdc_eng_timeout(struct ata_port *ap) |
327 | { | 327 | { |
328 | struct ata_host_set *host_set = ap->host_set; | ||
328 | u8 drv_stat; | 329 | u8 drv_stat; |
329 | struct ata_queued_cmd *qc; | 330 | struct ata_queued_cmd *qc; |
331 | unsigned long flags; | ||
330 | 332 | ||
331 | DPRINTK("ENTER\n"); | 333 | DPRINTK("ENTER\n"); |
332 | 334 | ||
335 | spin_lock_irqsave(&host_set->lock, flags); | ||
336 | |||
333 | qc = ata_qc_from_tag(ap, ap->active_tag); | 337 | qc = ata_qc_from_tag(ap, ap->active_tag); |
334 | if (!qc) { | 338 | if (!qc) { |
335 | printk(KERN_ERR "ata%u: BUG: timeout without command\n", | 339 | printk(KERN_ERR "ata%u: BUG: timeout without command\n", |
@@ -363,6 +367,7 @@ static void pdc_eng_timeout(struct ata_port *ap) | |||
363 | } | 367 | } |
364 | 368 | ||
365 | out: | 369 | out: |
370 | spin_unlock_irqrestore(&host_set->lock, flags); | ||
366 | DPRINTK("EXIT\n"); | 371 | DPRINTK("EXIT\n"); |
367 | } | 372 | } |
368 | 373 | ||
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index e2db499f22dd..a20d4285090a 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c | |||
@@ -848,10 +848,14 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re | |||
848 | static void pdc_eng_timeout(struct ata_port *ap) | 848 | static void pdc_eng_timeout(struct ata_port *ap) |
849 | { | 849 | { |
850 | u8 drv_stat; | 850 | u8 drv_stat; |
851 | struct ata_host_set *host_set = ap->host_set; | ||
851 | struct ata_queued_cmd *qc; | 852 | struct ata_queued_cmd *qc; |
853 | unsigned long flags; | ||
852 | 854 | ||
853 | DPRINTK("ENTER\n"); | 855 | DPRINTK("ENTER\n"); |
854 | 856 | ||
857 | spin_lock_irqsave(&host_set->lock, flags); | ||
858 | |||
855 | qc = ata_qc_from_tag(ap, ap->active_tag); | 859 | qc = ata_qc_from_tag(ap, ap->active_tag); |
856 | if (!qc) { | 860 | if (!qc) { |
857 | printk(KERN_ERR "ata%u: BUG: timeout without command\n", | 861 | printk(KERN_ERR "ata%u: BUG: timeout without command\n", |
@@ -885,6 +889,7 @@ static void pdc_eng_timeout(struct ata_port *ap) | |||
885 | } | 889 | } |
886 | 890 | ||
887 | out: | 891 | out: |
892 | spin_unlock_irqrestore(&host_set->lock, flags); | ||
888 | DPRINTK("EXIT\n"); | 893 | DPRINTK("EXIT\n"); |
889 | } | 894 | } |
890 | 895 | ||