diff options
author | Tejun Heo <htejun@gmail.com> | 2005-08-22 04:12:45 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-23 01:05:55 -0400 |
commit | 40e8c82c74b9be793601e098fd1313bc2632c5dc (patch) | |
tree | b3c89b2aaa5d477e8db5acc9bf4ee6f31acf3db8 /drivers/scsi | |
parent | c1389503710ef4b4e5d21bea284afde19e9619cf (diff) |
[PATCH] libata: implement ata_poll_qc_complete and use it in polling functions
[PATCH libata-dev-2.6:upstream] implement ata_poll_qc_complete and use it in polling functions
Previously, libata polling functions turned irq back on and completed
qc commands without holding host lock. This creates a race condition
between the polling task and interrupts from other ports on the same
host set or spurious interrupt from itself.
This patch implements ata_poll_qc_complete which enables irq and
completes qc atomically and convert all polling functions.
Note: atapi_packet_task() didn't use to turn irq back on or clear
ATA_FLAG_NOINTR on error exits. This patch makes it use
ata_poll_qc_complete which does both.
Note: With this change, ALL invocations of ata_qc_complete() are now
done under host_set lock.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libata-core.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index c92439fe5dae..2f68563ac3a3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -2402,6 +2402,26 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) | |||
2402 | } | 2402 | } |
2403 | 2403 | ||
2404 | /** | 2404 | /** |
2405 | * ata_poll_qc_complete - turn irq back on and finish qc | ||
2406 | * @qc: Command to complete | ||
2407 | * @drv_stat: ATA status register content | ||
2408 | * | ||
2409 | * LOCKING: | ||
2410 | * None. (grabs host lock) | ||
2411 | */ | ||
2412 | |||
2413 | void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) | ||
2414 | { | ||
2415 | struct ata_port *ap = qc->ap; | ||
2416 | |||
2417 | spin_lock_irq(&ap->host_set->lock); | ||
2418 | ap->flags &= ~ATA_FLAG_NOINTR; | ||
2419 | ata_irq_on(ap); | ||
2420 | ata_qc_complete(qc, drv_stat); | ||
2421 | spin_unlock_irq(&ap->host_set->lock); | ||
2422 | } | ||
2423 | |||
2424 | /** | ||
2405 | * ata_pio_poll - | 2425 | * ata_pio_poll - |
2406 | * @ap: | 2426 | * @ap: |
2407 | * | 2427 | * |
@@ -2492,9 +2512,7 @@ static void ata_pio_complete (struct ata_port *ap) | |||
2492 | 2512 | ||
2493 | ap->pio_task_state = PIO_ST_IDLE; | 2513 | ap->pio_task_state = PIO_ST_IDLE; |
2494 | 2514 | ||
2495 | ata_irq_on(ap); | 2515 | ata_poll_qc_complete(qc, drv_stat); |
2496 | |||
2497 | ata_qc_complete(qc, drv_stat); | ||
2498 | } | 2516 | } |
2499 | 2517 | ||
2500 | 2518 | ||
@@ -2844,9 +2862,7 @@ static void ata_pio_block(struct ata_port *ap) | |||
2844 | if ((status & ATA_DRQ) == 0) { | 2862 | if ((status & ATA_DRQ) == 0) { |
2845 | ap->pio_task_state = PIO_ST_IDLE; | 2863 | ap->pio_task_state = PIO_ST_IDLE; |
2846 | 2864 | ||
2847 | ata_irq_on(ap); | 2865 | ata_poll_qc_complete(qc, status); |
2848 | |||
2849 | ata_qc_complete(qc, status); | ||
2850 | return; | 2866 | return; |
2851 | } | 2867 | } |
2852 | 2868 | ||
@@ -2876,9 +2892,7 @@ static void ata_pio_error(struct ata_port *ap) | |||
2876 | 2892 | ||
2877 | ap->pio_task_state = PIO_ST_IDLE; | 2893 | ap->pio_task_state = PIO_ST_IDLE; |
2878 | 2894 | ||
2879 | ata_irq_on(ap); | 2895 | ata_poll_qc_complete(qc, drv_stat | ATA_ERR); |
2880 | |||
2881 | ata_qc_complete(qc, drv_stat | ATA_ERR); | ||
2882 | } | 2896 | } |
2883 | 2897 | ||
2884 | static void ata_pio_task(void *_data) | 2898 | static void ata_pio_task(void *_data) |
@@ -3791,7 +3805,7 @@ static void atapi_packet_task(void *_data) | |||
3791 | return; | 3805 | return; |
3792 | 3806 | ||
3793 | err_out: | 3807 | err_out: |
3794 | ata_qc_complete(qc, ATA_ERR); | 3808 | ata_poll_qc_complete(qc, ATA_ERR); |
3795 | } | 3809 | } |
3796 | 3810 | ||
3797 | 3811 | ||