aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2005-08-22 01:59:24 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-08-23 01:05:55 -0400
commitc1389503710ef4b4e5d21bea284afde19e9619cf (patch)
tree270bf8ea0c2ac354273766d8a1ddfb12cd58b608 /drivers/scsi/libata-core.c
parentc0b34ad2956036cdba87792d6c46d8f491539df1 (diff)
[PATCH] fix atapi_packet_task vs. intr race (take 2)
Interrupts from devices sharing the same IRQ could cause ata_host_intr to finish commands being processed by atapi_packet_task if the commands are using ATA_PROT_ATAPI_NODATA or ATA_PROT_ATAPI_DMA protocol. This is because libata interrupt handler is unaware that interrupts are not expected during that period. This patch adds ATA_FLAG_NOINTR flag to tell the interrupt handler that we're not expecting interrupts. Note that once proper HSM is implemented for interrupt-driven PIO, this should be merged into it and this flag will be removed. ahci.c is a different kind of beast, so it's left alone. * The following drivers use ata_qc_issue_prot and ata_interrupt, so changes in libata core will do. ata_piix sata_sil sata_svw sata_via sata_sis sata_uli * The following drivers use ata_qc_issue_prot and custom intr handler. They need this change to work correctly. sata_nv sata_vsc * The following drivers use custom issue function and intr handler. Currently all custom issue functions don't support ATAPI, so this change is irrelevant, updated for consistency and to avoid later mistakes. sata_promise sata_qstor sata_sx4 Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r--drivers/scsi/libata-core.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 9a6aacf467b8..c92439fe5dae 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -3350,11 +3350,13 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
3350 break; 3350 break;
3351 3351
3352 case ATA_PROT_ATAPI_NODATA: 3352 case ATA_PROT_ATAPI_NODATA:
3353 ap->flags |= ATA_FLAG_NOINTR;
3353 ata_tf_to_host_nolock(ap, &qc->tf); 3354 ata_tf_to_host_nolock(ap, &qc->tf);
3354 queue_work(ata_wq, &ap->packet_task); 3355 queue_work(ata_wq, &ap->packet_task);
3355 break; 3356 break;
3356 3357
3357 case ATA_PROT_ATAPI_DMA: 3358 case ATA_PROT_ATAPI_DMA:
3359 ap->flags |= ATA_FLAG_NOINTR;
3358 ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ 3360 ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
3359 ap->ops->bmdma_setup(qc); /* set up bmdma */ 3361 ap->ops->bmdma_setup(qc); /* set up bmdma */
3360 queue_work(ata_wq, &ap->packet_task); 3362 queue_work(ata_wq, &ap->packet_task);
@@ -3708,7 +3710,8 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
3708 struct ata_port *ap; 3710 struct ata_port *ap;
3709 3711
3710 ap = host_set->ports[i]; 3712 ap = host_set->ports[i];
3711 if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { 3713 if (ap &&
3714 !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
3712 struct ata_queued_cmd *qc; 3715 struct ata_queued_cmd *qc;
3713 3716
3714 qc = ata_qc_from_tag(ap, ap->active_tag); 3717 qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -3760,19 +3763,27 @@ static void atapi_packet_task(void *_data)
3760 /* send SCSI cdb */ 3763 /* send SCSI cdb */
3761 DPRINTK("send cdb\n"); 3764 DPRINTK("send cdb\n");
3762 assert(ap->cdb_len >= 12); 3765 assert(ap->cdb_len >= 12);
3763 ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
3764 3766
3765 /* if we are DMA'ing, irq handler takes over from here */ 3767 if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
3766 if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) 3768 qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
3767 ap->ops->bmdma_start(qc); /* initiate bmdma */ 3769 unsigned long flags;
3768 3770
3769 /* non-data commands are also handled via irq */ 3771 /* Once we're done issuing command and kicking bmdma,
3770 else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { 3772 * irq handler takes over. To not lose irq, we need
3771 /* do nothing */ 3773 * to clear NOINTR flag before sending cdb, but
3772 } 3774 * interrupt handler shouldn't be invoked before we're
3775 * finished. Hence, the following locking.
3776 */
3777 spin_lock_irqsave(&ap->host_set->lock, flags);
3778 ap->flags &= ~ATA_FLAG_NOINTR;
3779 ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
3780 if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
3781 ap->ops->bmdma_start(qc); /* initiate bmdma */
3782 spin_unlock_irqrestore(&ap->host_set->lock, flags);
3783 } else {
3784 ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
3773 3785
3774 /* PIO commands are handled by polling */ 3786 /* PIO commands are handled by polling */
3775 else {
3776 ap->pio_task_state = PIO_ST; 3787 ap->pio_task_state = PIO_ST;
3777 queue_work(ata_wq, &ap->pio_task); 3788 queue_work(ata_wq, &ap->pio_task);
3778 } 3789 }