aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ahci.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-31 05:28:18 -0400
committerTejun Heo <htejun@gmail.com>2006-05-31 05:28:18 -0400
commit4296971dd36e2c2deae0826305f591480223af88 (patch)
treebd3cce15c252cea18869b39da231d542a6255e59 /drivers/scsi/ahci.c
parente573890b00426189e1e223967a2c46fb758bf06e (diff)
[PATCH] ahci: convert to new probing mechanism and add hotplug support
Convert to new probing mechanism and add hotplug support by enabling PORT_IRQ_PHYRDY, marking ehi for hotplug and scheduling EH on CONNECT/PHYRDY interrupts. Unfortunately, ahci cannot reliably wait for the first D2H FIS after hotplug. It sometimes succeeds but times out more often than not, so ATA_FLAG_SKIP_D2H_BSY is used. This patch also fixes ahci_hardreset() such that D2H Register FIS RX area is cleared before issuing COMRESET. Without this, ata_busy_sleep() after COMRESET might prematually finish if the previous TF contains DRDY && !BSY. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/ahci.c')
-rw-r--r--drivers/scsi/ahci.c47
1 files changed, 27 insertions, 20 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 60f455bf3696..e261b37c2e48 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -136,6 +136,7 @@ enum {
136 PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | 136 PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
137 PORT_IRQ_IF_ERR | 137 PORT_IRQ_IF_ERR |
138 PORT_IRQ_CONNECT | 138 PORT_IRQ_CONNECT |
139 PORT_IRQ_PHYRDY |
139 PORT_IRQ_UNK_FIS, 140 PORT_IRQ_UNK_FIS,
140 PORT_IRQ_ERROR = PORT_IRQ_FREEZE | 141 PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
141 PORT_IRQ_TF_ERR | 142 PORT_IRQ_TF_ERR |
@@ -200,7 +201,6 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
200static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 201static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
201static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); 202static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
202static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); 203static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
203static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
204static void ahci_irq_clear(struct ata_port *ap); 204static void ahci_irq_clear(struct ata_port *ap);
205static int ahci_port_start(struct ata_port *ap); 205static int ahci_port_start(struct ata_port *ap);
206static void ahci_port_stop(struct ata_port *ap); 206static void ahci_port_stop(struct ata_port *ap);
@@ -241,8 +241,6 @@ static const struct ata_port_operations ahci_ops = {
241 241
242 .tf_read = ahci_tf_read, 242 .tf_read = ahci_tf_read,
243 243
244 .probe_reset = ahci_probe_reset,
245
246 .qc_prep = ahci_qc_prep, 244 .qc_prep = ahci_qc_prep,
247 .qc_issue = ahci_qc_issue, 245 .qc_issue = ahci_qc_issue,
248 246
@@ -267,7 +265,8 @@ static const struct ata_port_info ahci_port_info[] = {
267 { 265 {
268 .sht = &ahci_sht, 266 .sht = &ahci_sht,
269 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 267 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
270 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, 268 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
269 ATA_FLAG_SKIP_D2H_BSY,
271 .pio_mask = 0x1f, /* pio0-4 */ 270 .pio_mask = 0x1f, /* pio0-4 */
272 .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 271 .udma_mask = 0x7f, /* udma0-6 ; FIXME */
273 .port_ops = &ahci_ops, 272 .port_ops = &ahci_ops,
@@ -277,6 +276,7 @@ static const struct ata_port_info ahci_port_info[] = {
277 .sht = &ahci_sht, 276 .sht = &ahci_sht,
278 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 277 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
279 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | 278 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
279 ATA_FLAG_SKIP_D2H_BSY |
280 AHCI_FLAG_RESET_NEEDS_CLO, 280 AHCI_FLAG_RESET_NEEDS_CLO,
281 .pio_mask = 0x1f, /* pio0-4 */ 281 .pio_mask = 0x1f, /* pio0-4 */
282 .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 282 .udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -569,6 +569,17 @@ static int ahci_clo(struct ata_port *ap)
569 return 0; 569 return 0;
570} 570}
571 571
572static int ahci_prereset(struct ata_port *ap)
573{
574 if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
575 (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
576 /* ATA_BUSY hasn't cleared, so send a CLO */
577 ahci_clo(ap);
578 }
579
580 return ata_std_prereset(ap);
581}
582
572static int ahci_softreset(struct ata_port *ap, unsigned int *class) 583static int ahci_softreset(struct ata_port *ap, unsigned int *class)
573{ 584{
574 struct ahci_port_priv *pp = ap->private_data; 585 struct ahci_port_priv *pp = ap->private_data;
@@ -678,12 +689,22 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
678 689
679static int ahci_hardreset(struct ata_port *ap, unsigned int *class) 690static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
680{ 691{
692 struct ahci_port_priv *pp = ap->private_data;
693 u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
694 struct ata_taskfile tf;
681 int rc; 695 int rc;
682 696
683 DPRINTK("ENTER\n"); 697 DPRINTK("ENTER\n");
684 698
685 ahci_stop_engine(ap); 699 ahci_stop_engine(ap);
700
701 /* clear D2H reception area to properly wait for D2H FIS */
702 ata_tf_init(ap->device, &tf);
703 tf.command = 0xff;
704 ata_tf_to_fis(&tf, d2h_fis, 0);
705
686 rc = sata_std_hardreset(ap, class); 706 rc = sata_std_hardreset(ap, class);
707
687 ahci_start_engine(ap); 708 ahci_start_engine(ap);
688 709
689 if (rc == 0 && ata_port_online(ap)) 710 if (rc == 0 && ata_port_online(ap))
@@ -714,19 +735,6 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
714 } 735 }
715} 736}
716 737
717static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
718{
719 if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
720 (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
721 /* ATA_BUSY hasn't cleared, so send a CLO */
722 ahci_clo(ap);
723 }
724
725 return ata_drive_probe_reset(ap, ata_std_probeinit,
726 ahci_softreset, ahci_hardreset,
727 ahci_postreset, classes);
728}
729
730static u8 ahci_check_status(struct ata_port *ap) 738static u8 ahci_check_status(struct ata_port *ap)
731{ 739{
732 void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; 740 void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -839,8 +847,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
839 } 847 }
840 848
841 if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { 849 if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
842 err_mask |= AC_ERR_ATA_BUS; 850 ata_ehi_hotplugged(ehi);
843 action |= ATA_EH_SOFTRESET;
844 ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? 851 ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
845 "connection status changed" : "PHY RDY changed"); 852 "connection status changed" : "PHY RDY changed");
846 } 853 }
@@ -1027,7 +1034,7 @@ static void ahci_error_handler(struct ata_port *ap)
1027 } 1034 }
1028 1035
1029 /* perform recovery */ 1036 /* perform recovery */
1030 ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, 1037 ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
1031 ahci_postreset); 1038 ahci_postreset);
1032} 1039}
1033 1040