aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorAndrew Chew <achew@nvidia.com>2006-01-04 22:13:04 -0500
committerJeff Garzik <jgarzik@pobox.com>2006-01-09 10:42:06 -0500
commitb887030aec0971a47ca97a18e93ff446bc7d049e (patch)
tree77ecea6cce7d8047ad39feea2d0b0cbff1bdbad2 /drivers/scsi
parent5367f2d67c7d0bf1faae90e6e7b4e2ac3c9b5e0f (diff)
[PATCH] sata_nv, spurious interrupts at system startup with MAXTOR 6H500F0 drive
This patch works around a problem with spurious interrupts seen at boot time when a MAXTOR 6H500F0 drive is present. An ATA interrupt condition is mysteriously present at start of day. If we took too long in issuing the first command, the kernel would basically get tired of the spurious interrupts and turn the interrupt off. Issuing the first command essentially causes the interrupt condition to get acknowledged. I haven't seen this happen with any other drives. What I basically do is ack ATA status by reading it regardless of whether we're expecting to have to handle an interrupt. This clears the start-of-day anomalous interrupt condition, and keeps the kernel from disabling that interrupt due to too many spurious interrupts. Also, I fixed a bug where hotplug interrupts weren't getting acknowledged as handled in the ISR. This was not the cause of the spurious interrupts, but it's the right thing to do anyway. Signed-Off-By: Andrew Chew Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sata_nv.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index c0cf52cb975a..bbbb55eeb73a 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -29,6 +29,12 @@
29 * NV-specific details such as register offsets, SATA phy location, 29 * NV-specific details such as register offsets, SATA phy location,
30 * hotplug info, etc. 30 * hotplug info, etc.
31 * 31 *
32 * 0.10
33 * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB
34 * drive. Also made the check_hotplug() callbacks return whether there
35 * was a hotplug interrupt or not. This was not the source of the
36 * spurious interrupts, but is the right thing to do anyway.
37 *
32 * 0.09 38 * 0.09
33 * - Fixed bug introduced by 0.08's MCP51 and MCP55 support. 39 * - Fixed bug introduced by 0.08's MCP51 and MCP55 support.
34 * 40 *
@@ -124,10 +130,10 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
124static void nv_host_stop (struct ata_host_set *host_set); 130static void nv_host_stop (struct ata_host_set *host_set);
125static void nv_enable_hotplug(struct ata_probe_ent *probe_ent); 131static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
126static void nv_disable_hotplug(struct ata_host_set *host_set); 132static void nv_disable_hotplug(struct ata_host_set *host_set);
127static void nv_check_hotplug(struct ata_host_set *host_set); 133static int nv_check_hotplug(struct ata_host_set *host_set);
128static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent); 134static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
129static void nv_disable_hotplug_ck804(struct ata_host_set *host_set); 135static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
130static void nv_check_hotplug_ck804(struct ata_host_set *host_set); 136static int nv_check_hotplug_ck804(struct ata_host_set *host_set);
131 137
132enum nv_host_type 138enum nv_host_type
133{ 139{
@@ -176,7 +182,7 @@ struct nv_host_desc
176 enum nv_host_type host_type; 182 enum nv_host_type host_type;
177 void (*enable_hotplug)(struct ata_probe_ent *probe_ent); 183 void (*enable_hotplug)(struct ata_probe_ent *probe_ent);
178 void (*disable_hotplug)(struct ata_host_set *host_set); 184 void (*disable_hotplug)(struct ata_host_set *host_set);
179 void (*check_hotplug)(struct ata_host_set *host_set); 185 int (*check_hotplug)(struct ata_host_set *host_set);
180 186
181}; 187};
182static struct nv_host_desc nv_device_tbl[] = { 188static struct nv_host_desc nv_device_tbl[] = {
@@ -309,12 +315,16 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
309 qc = ata_qc_from_tag(ap, ap->active_tag); 315 qc = ata_qc_from_tag(ap, ap->active_tag);
310 if (qc && (!(qc->tf.ctl & ATA_NIEN))) 316 if (qc && (!(qc->tf.ctl & ATA_NIEN)))
311 handled += ata_host_intr(ap, qc); 317 handled += ata_host_intr(ap, qc);
318 else
319 // No request pending? Clear interrupt status
320 // anyway, in case there's one pending.
321 ap->ops->check_status(ap);
312 } 322 }
313 323
314 } 324 }
315 325
316 if (host->host_desc->check_hotplug) 326 if (host->host_desc->check_hotplug)
317 host->host_desc->check_hotplug(host_set); 327 handled += host->host_desc->check_hotplug(host_set);
318 328
319 spin_unlock_irqrestore(&host_set->lock, flags); 329 spin_unlock_irqrestore(&host_set->lock, flags);
320 330
@@ -497,7 +507,7 @@ static void nv_disable_hotplug(struct ata_host_set *host_set)
497 outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); 507 outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
498} 508}
499 509
500static void nv_check_hotplug(struct ata_host_set *host_set) 510static int nv_check_hotplug(struct ata_host_set *host_set)
501{ 511{
502 u8 intr_status; 512 u8 intr_status;
503 513
@@ -522,7 +532,11 @@ static void nv_check_hotplug(struct ata_host_set *host_set)
522 if (intr_status & NV_INT_STATUS_SDEV_REMOVED) 532 if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
523 printk(KERN_WARNING "nv_sata: " 533 printk(KERN_WARNING "nv_sata: "
524 "Secondary device removed\n"); 534 "Secondary device removed\n");
535
536 return 1;
525 } 537 }
538
539 return 0;
526} 540}
527 541
528static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent) 542static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
@@ -560,7 +574,7 @@ static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
560 pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); 574 pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
561} 575}
562 576
563static void nv_check_hotplug_ck804(struct ata_host_set *host_set) 577static int nv_check_hotplug_ck804(struct ata_host_set *host_set)
564{ 578{
565 u8 intr_status; 579 u8 intr_status;
566 580
@@ -585,7 +599,11 @@ static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
585 if (intr_status & NV_INT_STATUS_SDEV_REMOVED) 599 if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
586 printk(KERN_WARNING "nv_sata: " 600 printk(KERN_WARNING "nv_sata: "
587 "Secondary device removed\n"); 601 "Secondary device removed\n");
602
603 return 1;
588 } 604 }
605
606 return 0;
589} 607}
590 608
591static int __init nv_init(void) 609static int __init nv_init(void)