diff options
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r-- | drivers/scsi/libata-core.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9a6aacf467b..c92439fe5da 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 | } |