Index: linux-2.6.16/drivers/ata/libata-core.c =================================================================== --- linux-2.6.16.orig/drivers/ata/libata-core.c 2006-10-10 19:40:35.000000000 +0200 +++ linux-2.6.16/drivers/ata/libata-core.c 2006-10-10 19:40:48.000000000 +0200 @@ -4122,7 +4122,8 @@ fsm_start: DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", - ap->id, qc->tf.protocol, ap->hsm_task_state, status); + ap->id, qc->tf.protocol, ap->hsm_task_state, status, + qc->tf.flags & ATA_TFLAG_POLLING); switch (ap->hsm_task_state) { case HSM_ST_FIRST: @@ -4712,6 +4713,14 @@ } } + /* Some controllers show flaky interrupt behavior after + * setting xfer mode. Use polling instead. + */ + if (unlikely(qc->tf.command == ATA_CMD_SET_FEATURES && + qc->tf.feature == SETFEATURES_XFER) && + (ap->flags & ATA_FLAG_SETXFER_POLLING)) + qc->tf.flags |= ATA_TFLAG_POLLING; + /* select the device */ ata_dev_select(ap, qc->dev->devno, 1, 0); Index: linux-2.6.16/drivers/ata/pata_via.c =================================================================== --- linux-2.6.16.orig/drivers/ata/pata_via.c 2006-10-10 19:40:35.000000000 +0200 +++ linux-2.6.16/drivers/ata/pata_via.c 2006-10-10 19:42:43.000000000 +0200 @@ -398,7 +398,7 @@ .data_xfer = ata_pio_data_xfer, - .irq_handler = pata_via_interrupt, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .port_start = ata_port_start, @@ -433,7 +433,7 @@ .data_xfer = ata_pio_data_xfer_noirq, - .irq_handler = pata_via_interrupt, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .port_start = ata_port_start, @@ -455,7 +455,8 @@ /* Early VIA without UDMA support */ static struct ata_port_info via_mwdma_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops @@ -463,7 +464,8 @@ /* Ditto with IRQ masking required */ static struct ata_port_info via_mwdma_info_borked = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops_noirq, @@ -471,7 +473,8 @@ /* VIA UDMA 33 devices (and borked 66) */ static struct ata_port_info via_udma33_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7, @@ -480,7 +483,8 @@ /* VIA UDMA 66 devices */ static struct ata_port_info via_udma66_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x1f, @@ -489,7 +493,8 @@ /* VIA UDMA 100 devices */ static struct ata_port_info via_udma100_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x3f, @@ -498,7 +503,8 @@ /* UDMA133 with bad AST (All current 133) */ static struct ata_port_info via_udma133_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_SETXFER_POLLING, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7f, /* FIXME: should check north bridge */ Index: linux-2.6.16/include/linux/libata.h =================================================================== --- linux-2.6.16.orig/include/linux/libata.h 2006-10-10 19:40:54.000000000 +0200 +++ linux-2.6.16/include/linux/libata.h 2006-10-10 19:41:00.000000000 +0200 @@ -178,6 +178,7 @@ ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_DETECT_POLLING = (1 << 14), /* detect device presence by * polling IDENTIFY */ + ATA_FLAG_SETXFER_POLLING= (1 << 14), /* use polling for SETXFER */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be