aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/scsi/libata-core.c33
-rw-r--r--drivers/scsi/sata_nv.c3
-rw-r--r--drivers/scsi/sata_promise.c3
-rw-r--r--drivers/scsi/sata_qstor.c6
-rw-r--r--drivers/scsi/sata_sx4.c3
-rw-r--r--drivers/scsi/sata_vsc.c3
-rw-r--r--include/linux/libata.h2
7 files changed, 36 insertions, 17 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 }
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 9b9142790bd6..41a3421b02b4 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -291,7 +291,8 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
291 struct ata_port *ap; 291 struct ata_port *ap;
292 292
293 ap = host_set->ports[i]; 293 ap = host_set->ports[i];
294 if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { 294 if (ap &&
295 !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
295 struct ata_queued_cmd *qc; 296 struct ata_queued_cmd *qc;
296 297
297 qc = ata_qc_from_tag(ap, ap->active_tag); 298 qc = ata_qc_from_tag(ap, ap->active_tag);
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index cc613b3c6ce6..6defd7962359 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -445,7 +445,8 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
445 VPRINTK("port %u\n", i); 445 VPRINTK("port %u\n", i);
446 ap = host_set->ports[i]; 446 ap = host_set->ports[i];
447 tmp = mask & (1 << (i + 1)); 447 tmp = mask & (1 << (i + 1));
448 if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { 448 if (tmp && ap &&
449 !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
449 struct ata_queued_cmd *qc; 450 struct ata_queued_cmd *qc;
450 451
451 qc = ata_qc_from_tag(ap, ap->active_tag); 452 qc = ata_qc_from_tag(ap, ap->active_tag);
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index dca9ed7ac760..08a84042ce09 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -386,7 +386,8 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
386 DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", 386 DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
387 sff1, sff0, port_no, sHST, sDST); 387 sff1, sff0, port_no, sHST, sDST);
388 handled = 1; 388 handled = 1;
389 if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { 389 if (ap && !(ap->flags &
390 (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
390 struct ata_queued_cmd *qc; 391 struct ata_queued_cmd *qc;
391 struct qs_port_priv *pp = ap->private_data; 392 struct qs_port_priv *pp = ap->private_data;
392 if (!pp || pp->state != qs_state_pkt) 393 if (!pp || pp->state != qs_state_pkt)
@@ -417,7 +418,8 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
417 for (port_no = 0; port_no < host_set->n_ports; ++port_no) { 418 for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
418 struct ata_port *ap; 419 struct ata_port *ap;
419 ap = host_set->ports[port_no]; 420 ap = host_set->ports[port_no];
420 if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { 421 if (ap &&
422 !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
421 struct ata_queued_cmd *qc; 423 struct ata_queued_cmd *qc;
422 struct qs_port_priv *pp = ap->private_data; 424 struct qs_port_priv *pp = ap->private_data;
423 if (!pp || pp->state != qs_state_mmio) 425 if (!pp || pp->state != qs_state_mmio)
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index 76644ea62d67..e2db499f22dd 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -825,7 +825,8 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
825 ap = host_set->ports[port_no]; 825 ap = host_set->ports[port_no];
826 tmp = mask & (1 << i); 826 tmp = mask & (1 << i);
827 VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp); 827 VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
828 if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { 828 if (tmp && ap &&
829 !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) {
829 struct ata_queued_cmd *qc; 830 struct ata_queued_cmd *qc;
830 831
831 qc = ata_qc_from_tag(ap, ap->active_tag); 832 qc = ata_qc_from_tag(ap, ap->active_tag);
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index cb3a6d89cf00..6f2562171be0 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -173,7 +173,8 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
173 struct ata_port *ap; 173 struct ata_port *ap;
174 174
175 ap = host_set->ports[i]; 175 ap = host_set->ports[i];
176 if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { 176 if (ap && !(ap->flags &
177 (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
177 struct ata_queued_cmd *qc; 178 struct ata_queued_cmd *qc;
178 179
179 qc = ata_qc_from_tag(ap, ap->active_tag); 180 qc = ata_qc_from_tag(ap, ap->active_tag);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 85b0aaee0ef8..724b7d1c18ea 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -113,6 +113,8 @@ enum {
113 ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ 113 ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */
114 ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ 114 ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */
115 ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ 115 ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */
116 ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once
117 * proper HSM is in place. */
116 118
117 ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ 119 ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
118 ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ 120 ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */