diff options
author | Mark Lord <mlord@pobox.com> | 2009-02-25 15:19:20 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2009-03-24 22:02:41 -0400 |
commit | 70f8b79cf3a2eb892a01271fdfbb1903c0c982a8 (patch) | |
tree | ca959654f45cf57760470a17742a530a0a1e21b6 | |
parent | 1a660164c291f41b2aa853a7269b310933574ef9 (diff) |
[libata] sata_mv: Implement direct FIS transmission via mv_qc_issue_fis().
This is initially needed to work around NCQ errata,
whereby the READ_LOG_EXT command sometimes fails
when issued in the traditional (sff) fashion.
Portions of this code will likely be reused for
implementation of the target mode feature later on.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r-- | drivers/ata/sata_mv.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 542e244f37ab..8cad3b2fe554 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -1822,6 +1822,105 @@ static u8 mv_sff_check_status(struct ata_port *ap) | |||
1822 | } | 1822 | } |
1823 | 1823 | ||
1824 | /** | 1824 | /** |
1825 | * mv_send_fis - Send a FIS, using the "Vendor-Unique FIS" register | ||
1826 | * @fis: fis to be sent | ||
1827 | * @nwords: number of 32-bit words in the fis | ||
1828 | */ | ||
1829 | static unsigned int mv_send_fis(struct ata_port *ap, u32 *fis, int nwords) | ||
1830 | { | ||
1831 | void __iomem *port_mmio = mv_ap_base(ap); | ||
1832 | u32 ifctl, old_ifctl, ifstat; | ||
1833 | int i, timeout = 200, final_word = nwords - 1; | ||
1834 | |||
1835 | /* Initiate FIS transmission mode */ | ||
1836 | old_ifctl = readl(port_mmio + SATA_IFCTL_OFS); | ||
1837 | ifctl = 0x100 | (old_ifctl & 0xf); | ||
1838 | writelfl(ifctl, port_mmio + SATA_IFCTL_OFS); | ||
1839 | |||
1840 | /* Send all words of the FIS except for the final word */ | ||
1841 | for (i = 0; i < final_word; ++i) | ||
1842 | writel(fis[i], port_mmio + VENDOR_UNIQUE_FIS_OFS); | ||
1843 | |||
1844 | /* Flag end-of-transmission, and then send the final word */ | ||
1845 | writelfl(ifctl | 0x200, port_mmio + SATA_IFCTL_OFS); | ||
1846 | writelfl(fis[final_word], port_mmio + VENDOR_UNIQUE_FIS_OFS); | ||
1847 | |||
1848 | /* | ||
1849 | * Wait for FIS transmission to complete. | ||
1850 | * This typically takes just a single iteration. | ||
1851 | */ | ||
1852 | do { | ||
1853 | ifstat = readl(port_mmio + SATA_IFSTAT_OFS); | ||
1854 | } while (!(ifstat & 0x1000) && --timeout); | ||
1855 | |||
1856 | /* Restore original port configuration */ | ||
1857 | writelfl(old_ifctl, port_mmio + SATA_IFCTL_OFS); | ||
1858 | |||
1859 | /* See if it worked */ | ||
1860 | if ((ifstat & 0x3000) != 0x1000) { | ||
1861 | ata_port_printk(ap, KERN_WARNING, | ||
1862 | "%s transmission error, ifstat=%08x\n", | ||
1863 | __func__, ifstat); | ||
1864 | return AC_ERR_OTHER; | ||
1865 | } | ||
1866 | return 0; | ||
1867 | } | ||
1868 | |||
1869 | /** | ||
1870 | * mv_qc_issue_fis - Issue a command directly as a FIS | ||
1871 | * @qc: queued command to start | ||
1872 | * | ||
1873 | * Note that the ATA shadow registers are not updated | ||
1874 | * after command issue, so the device will appear "READY" | ||
1875 | * if polled, even while it is BUSY processing the command. | ||
1876 | * | ||
1877 | * So we use a status hook to fake ATA_BUSY until the drive changes state. | ||
1878 | * | ||
1879 | * Note: we don't get updated shadow regs on *completion* | ||
1880 | * of non-data commands. So avoid sending them via this function, | ||
1881 | * as they will appear to have completed immediately. | ||
1882 | * | ||
1883 | * GEN_IIE has special registers that we could get the result tf from, | ||
1884 | * but earlier chipsets do not. For now, we ignore those registers. | ||
1885 | */ | ||
1886 | static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc) | ||
1887 | { | ||
1888 | struct ata_port *ap = qc->ap; | ||
1889 | struct mv_port_priv *pp = ap->private_data; | ||
1890 | struct ata_link *link = qc->dev->link; | ||
1891 | u32 fis[5]; | ||
1892 | int err = 0; | ||
1893 | |||
1894 | ata_tf_to_fis(&qc->tf, link->pmp, 1, (void *)fis); | ||
1895 | err = mv_send_fis(ap, fis, sizeof(fis) / sizeof(fis[0])); | ||
1896 | if (err) | ||
1897 | return err; | ||
1898 | |||
1899 | switch (qc->tf.protocol) { | ||
1900 | case ATAPI_PROT_PIO: | ||
1901 | pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY; | ||
1902 | /* fall through */ | ||
1903 | case ATAPI_PROT_NODATA: | ||
1904 | ap->hsm_task_state = HSM_ST_FIRST; | ||
1905 | break; | ||
1906 | case ATA_PROT_PIO: | ||
1907 | pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY; | ||
1908 | if (qc->tf.flags & ATA_TFLAG_WRITE) | ||
1909 | ap->hsm_task_state = HSM_ST_FIRST; | ||
1910 | else | ||
1911 | ap->hsm_task_state = HSM_ST; | ||
1912 | break; | ||
1913 | default: | ||
1914 | ap->hsm_task_state = HSM_ST_LAST; | ||
1915 | break; | ||
1916 | } | ||
1917 | |||
1918 | if (qc->tf.flags & ATA_TFLAG_POLLING) | ||
1919 | ata_pio_queue_task(ap, qc, 0); | ||
1920 | return 0; | ||
1921 | } | ||
1922 | |||
1923 | /** | ||
1825 | * mv_qc_issue - Initiate a command to the host | 1924 | * mv_qc_issue - Initiate a command to the host |
1826 | * @qc: queued command to start | 1925 | * @qc: queued command to start |
1827 | * | 1926 | * |
@@ -1896,6 +1995,23 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) | |||
1896 | mv_stop_edma(ap); | 1995 | mv_stop_edma(ap); |
1897 | mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs); | 1996 | mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs); |
1898 | mv_pmp_select(ap, qc->dev->link->pmp); | 1997 | mv_pmp_select(ap, qc->dev->link->pmp); |
1998 | |||
1999 | if (qc->tf.command == ATA_CMD_READ_LOG_EXT) { | ||
2000 | struct mv_host_priv *hpriv = ap->host->private_data; | ||
2001 | /* | ||
2002 | * Workaround for 88SX60x1 FEr SATA#25 (part 2). | ||
2003 | * | ||
2004 | * After any NCQ error, the READ_LOG_EXT command | ||
2005 | * from libata-eh *must* use mv_qc_issue_fis(). | ||
2006 | * Otherwise it might fail, due to chip errata. | ||
2007 | * | ||
2008 | * Rather than special-case it, we'll just *always* | ||
2009 | * use this method here for READ_LOG_EXT, making for | ||
2010 | * easier testing. | ||
2011 | */ | ||
2012 | if (IS_GEN_II(hpriv)) | ||
2013 | return mv_qc_issue_fis(qc); | ||
2014 | } | ||
1899 | return ata_sff_qc_issue(qc); | 2015 | return ata_sff_qc_issue(qc); |
1900 | } | 2016 | } |
1901 | 2017 | ||